假设我们的数据都在数组中,并且数组中的数据是一些存在重复的人名。我们先使用numpy.random中的randn函数来生成一些随机正态分布的数据:
import numpy as np
names = np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
data = np.random.randn(7,4)
names
array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='<U4')
data
array([[-0.24427644, -1.46367872, -0.49068242, 1.78822424],
[-0.86311703, 0.51422326, 0.56743326, 0.8871636 ],
[-0.5866742 , 0.73856216, 0.38637554, 0.30568998],
[ 0.57535788, 1.30374594, -2.05887936, -0.22818597],
[ 2.35235075, 0.68025456, 1.00348864, 0.32746915],
[ 0.42857695, -0.16228046, 1.27368772, -0.648772 ],
[ 0.00398702, 0.72742387, -0.79640429, -0.93247884]])
假设每个人名都和data数组中的一行相对应,并且我们想要选中所有的 ‘Bob’ 对应的行。与数学操作类似,数组的比较操作(比如==)也是可以向量化的。因此,比较names数组和字符串 ‘Bob’ 会产生一个布尔值数组:
names == 'Bob'
array([ True, False, False, True, False, False, False])
在索引数组时可以传入布尔值数组:
data[names == 'Bob']
array([[-0.24427644, -1.46367872, -0.49068242, 1.78822424],
[ 0.57535788, 1.30374594, -2.05887936, -0.22818597]])
布尔值数组的长度必须和数组轴索引长度一致。你甚至还可以用切片或整数值对布尔值数组进行混合和匹配。
(当布尔值数组的长度不正确时,布尔值选择数据的方法并不会报错,因此我建议在使用该特性的时候要小心。)
在这些例子中,我选择 names == ‘Bob’ 的行,并进行索引:
data[names == 'Bob',2:]
array([[-0.49068242, 1.78822424],
[-2.05887936, -0.22818597]])
data[names == 'Bob',3]
array([ 1.78822424, -0.22818597])
为了选择除了 ‘Bob’ 以外的其他数据,你可以使用 != 或在条件表达式前使用 ~ 对条件取反:
names != 'Bob'
array([False, True, True, False, True, True, True])
data[~(names == 'Bob')]
array([[-0.86311703, 0.51422326, 0.56743326, 0.8871636 ],
[-0.5866742 , 0.73856216, 0.38637554, 0.30568998],
[ 2.35235075, 0.68025456, 1.00348864, 0.32746915],
[ 0.42857695, -0.16228046, 1.27368772, -0.648772 ],
[ 0.00398702, 0.72742387, -0.79640429, -0.93247884]])
~ 符号可以在你想要对一个通用条件进行取反时使用:
cond = names == 'Bob'
data[~cond]
array([[-0.86311703, 0.51422326, 0.56743326, 0.8871636 ],
[-0.5866742 , 0.73856216, 0.38637554, 0.30568998],
[ 2.35235075, 0.68025456, 1.00348864, 0.32746915],
[ 0.42857695, -0.16228046, 1.27368772, -0.648772 ],
[ 0.00398702, 0.72742387, -0.79640429, -0.93247884]])
当要选择三个名字中的两个时,可以对多个布尔值条件进行联合,需要使用数学操作符&(and)和|(or):
mask = (names == 'Bob')|(names == 'Will')
mask
array([ True, False, True, True, True, False, False])
data[mask]
array([[-0.24427644, -1.46367872, -0.49068242, 1.78822424],
[-0.5866742 , 0.73856216, 0.38637554, 0.30568998],
[ 0.57535788, 1.30374594, -2.05887936, -0.22818597],
[ 2.35235075, 0.68025456, 1.00348864, 0.32746915]])
使用布尔值索引选择数据时,总是生成数据的拷贝,即使返回的数组并没有任何变化。
(Python的关键字and和or对布尔值数组并没有用,请使用&和|来代替。)
基于常识来设置布尔值数组的值也是可行的。将data中所有的负值设置为0,我们需要做:
data[data < 0] = 0
data
data
data
array([[0. , 0. , 0. , 1.78822424],
[0. , 0.51422326, 0.56743326, 0.8871636 ],
[0. , 0.73856216, 0.38637554, 0.30568998],
[0.57535788, 1.30374594, 0. , 0. ],
[2.35235075, 0.68025456, 1.00348864, 0.32746915],
[0.42857695, 0. , 1.27368772, 0. ],
[0.00398702, 0.72742387, 0. , 0. ]])
利用一维布尔值数组对每一行设置数值也是非常简单的:
data[names != 'Joe'] = 7
data
data
data
array([[7.00000000e+00, 7.00000000e+00, 7.00000000e+00, 7.00000000e+00],
[0.00000000e+00, 5.14223265e-01, 5.67433258e-01, 8.87163599e-01],
[7.00000000e+00, 7.00000000e+00, 7.00000000e+00, 7.00000000e+00],
[7.00000000e+00, 7.00000000e+00, 7.00000000e+00, 7.00000000e+00],
[7.00000000e+00, 7.00000000e+00, 7.00000000e+00, 7.00000000e+00],
[4.28576952e-01, 0.00000000e+00, 1.27368772e+00, 0.00000000e+00],
[3.98701940e-03, 7.27423872e-01, 0.00000000e+00, 0.00000000e+00]])