本节我们讲解 Numpy 数组的布尔索引操作,大家对于这一概念很可能会无感,通过本节知识的介绍,你会认识到 Numpy 数组的与众不同的。Numpy 数组布尔索引也可以叫做掩码操作,即通过一组布尔值序列,对 Numpy 数组进行取值操作,下面就正式进入本节的主要内容。
布尔值即 True 或 False 使用它们两者进行索引可以使 Numpy 数组呈现出我们想要的数据,我们先看一个简单的示例:
- In [1]: import numpy as np
- In [2]: data=np.arange(1,11)
- #创建mask掩码布尔值列表
- In [3]: mask=[True,False,True,False,True,False,True,False,True,False]
- #使用布尔值对数组data进行索引
- In [4]: data[mask]
- #输出只有奇数的数组
- Out[4]: array([1, 3, 5, 7, 9])
通过上面的代码,你应该对布尔值索引有了一个基本的认识。这种使用 mask 布尔值序列对数组进行取值的操作,称之为掩码,即掩盖掉不想显示的数据。下面我们讲一些实际的应用场景。
假设现在有一组班级姓名的数组,并且还有一组成绩表,成绩表我们可以随机生成一组数据,如下所示:
- In [1]: import numpy as np
-
- In [2]: data=np.arange(1,11)
-
- In [3]: mask=[True,False,True,False,True,False,True,False,True,False]
-
- In [4]: data[mask]
- Out[4]: array([1, 3, 5, 7, 9])
-
- In [5]: import numpy as np
- #名字数组
- In [6]: names=np.array(['xm','ls','cd','ra','xm','lz'])
- #随机生成6行4列的成绩数组并和姓名一一对应
- In [7]: data=np.random.randn(6,4)
- In [8]: data
- Out[8]:
- array([[ 0.11862692, 0.43370356, 0.24572782, 0.12563666],
- [-0.66938338, -0.27592135, 0.27299139, -0.62841077],
- [-0.49116108, -1.34173789, 1.71092549, 0.97037571],
- [ 0.79156476, -0.33761401, 0.15094182, 0.59195507],
- [-0.10606347, 0.00604084, -0.3119981 , -0.82903705],
- [ 1.2775524 , -0.76599632, -1.41684961, 0.27957322]])
-
- In [9]: names
- Out[9]: array(['xm', 'ls', 'cd', 'ra', 'xm', 'lz'], dtype='<U2')
我们假设每个人名都和 data 数组的一行数据相对应,如果此时我们想要根据名字筛选出我们想要的成绩应该怎么做呢?我们知道 True 和 False 可以用来判断一个 if 表达式的条件是否成立,若成立则返回 True,否则就返回 False,所以在此处依然使用这种思想来考虑。
我们使用数学上的比较运算符就可以得到想要的结果,如下所示:
- In [1]: import numpy as np
-
- In [2]: names=np.array(['xm','ls','cd','ra','xm','lz'])
-
- In [3]: data=np.random.randn(6,4)
-
- In [4]: names
- Out[4]: array(['xm', 'ls', 'cd', 'ra', 'xm', 'lz'], dtype='<U2')
-
- In [5]: data
- Out[5]:
- array([[ 1.27893324, -0.2869719 , 1.53727143, 0.92759443],
- [-1.34825698, 0.61118769, 0.09381353, -0.25670181],
- [ 1.23828121, -0.60258588, -1.29633343, -0.79827614],
- [-0.69281436, 0.35496869, -1.18819669, -1.06783884],
- [-0.63522862, -0.46742291, 1.29312452, -1.83039843],
- [ 1.0572994 , 1.55526538, 0.46449384, -0.2587228 ]])
- #使names数组等于xm会生成布尔序列数组
- In [6]: names=="xm"
- #为xm的位置显示为True
- Out[6]: array([ True, False, False, False, True, False])
- #对data数组进行掩码操作
- In [7]: data[names=="xm"]
- #输入结果为xm对应的行数
- Out[7]:
- array([[ 1.27893324, -0.2869719 , 1.53727143, 0.92759443],
- [-0.63522862, -0.46742291, 1.29312452, -1.83039843]])
这里有一点需要大家注意,布尔值数组长度必须和数组索引长度一致。继续上面示例,我们还可以使用如下的方式,父获取的数组结果进一步操作:
- In [8]: data[names=="xm"]
- Out[8]:
- array([[ 1.27893324, -0.2869719 , 1.53727143, 0.92759443],
- [-0.63522862, -0.46742291, 1.29312452, -1.83039843]])
- #前面的位置代表选择行,后面表示选择列
- In [9]: data[names=="xm",3]
- Out[9]: array([ 0.92759443, -1.83039843])
-
- In [10]: data[names=="xm",-2]
- Out[10]: array([1.53727143, 1.29312452])
-
- In [11]: data[names=="xm",1:]
- Out[11]:
- array([[-0.2869719 , 1.53727143, 0.92759443],
- [-0.46742291, 1.29312452, -1.83039843]])
data[names=="xm",1:] 表示 data 对应names=='xm' 的行,列取值不包含第一列以外的所有列。
理解了上面的使用方法后,我们再来看看其他使用方法,我们也可以使用逻辑运算符号 | 和 & 来进行布尔值索引,它们分别代表着 or 和 and,在布尔值中需要使用符号来代替关键字,如下所示:
- In [19]: mask=(names=="xm")|(names=="ls")
- In [20]: mask
- Out[20]: array([ True, True, False, False, True, False])
- In [21]: mask=(names=="xm")&(names=="ls")
- In [22]: mask
- Out[22]: array([False, False, False, False, False, False])
使用不相等和取反也可以进行掩码操作,如下所示,它们最终的结果是一样的:
- In [12]: names!="xm"
- Out[12]: array([False, True, True, True, False, True])
-
- In [13]: data[names!="xm"]
- Out[13]:
- array([[-1.34825698, 0.61118769, 0.09381353, -0.25670181],
- [ 1.23828121, -0.60258588, -1.29633343, -0.79827614],
- [-0.69281436, 0.35496869, -1.18819669, -1.06783884],
- [ 1.0572994 , 1.55526538, 0.46449384, -0.2587228 ]])
-
- In [14]: data[~(names=="xm")]
- Out[14]:
- array([[-1.34825698, 0.61118769, 0.09381353, -0.25670181],
- [ 1.23828121, -0.60258588, -1.29633343, -0.79827614],
- [-0.69281436, 0.35496869, -1.18819669, -1.06783884],
- [ 1.0572994 , 1.55526538, 0.46449384, -0.2587228 ]])
-
我们可以使用数学上的比较符号对数组值进行判断,进而操作数组中数值,比如重新赋值等:
- In [23]: data<0
- #data<0生成布尔值数组
- Out[23]:
- array([[False, True, False, False],
- [ True, False, False, True],
- [False, True, True, True],
- [ True, False, True, True],
- [ True, True, False, True],
- [False, False, False, True]])
- In [24]: data[data<0]=0
- #对于满足条件的数值进行修改去掉负值
- In [25]: data
- Out[25]:
- array([[1.27893324, 0. , 1.53727143, 0.92759443],
- [0. , 0.61118769, 0.09381353, 0. ],
- [1.23828121, 0. , 0. , 0. ],
- [0. , 0.35496869, 0. , 0. ],
- [0. , 0. , 1.29312452, 0. ],
- [1.0572994 , 1.55526538, 0.46449384, 0. ]])
- In [26]: data[names!='lz']=7
- #对于满足条件的数据进行修改
- In [27]: data
- Out[27]:
- array([[7. , 7. , 7. , 7. ],
- [7. , 7. , 7. , 7. ],
- [7. , 7. , 7. , 7. ],
- [7. , 7. , 7. , 7. ],
- [7. , 7. , 7. , 7. ],
- [1.0572994 , 1.55526538, 0.46449384, 0. ]])
通过上面的示例,我们可以看出 Numpy 数组强大功能以及它的灵活性,对于上述操作方法需要大家实际去练习然后再掌握它们。注意当我们再使用布尔值索引选择数据时,生成的是数据的拷贝,即不会影响到原数组数据。