前言
再接上回,我们对索引再进一步学习
1.5 布尔索引
我们可以先通过下列例子来学习。假设我们的数据都在数组中,并且数组中的数据是一些存在重复的人名。再使用numpy.random中的randn函数来生成一些随机正态分布的数据:
names = np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
data = np.random.randn(7,4)
print(names)
print(data)
-----------------------------------------------------------------
['Bob' 'Joe' 'Will' 'Bob' 'Will' 'Joe' 'Joe']
[[ 0.4992984 -0.07234365 0.14451715 -0.41352239]
[-0.39308394 1.4680289 -0.95722327 1.87224511]
[-0.26925324 -0.17984855 -1.64057174 -2.69845021]
[-0.12484777 1.40737756 -0.25473659 0.56018487]
[-0.06335307 -0.78682012 1.86302967 0.59474813]
[-0.93085943 3.07061212 -0.93294211 -1.89029313]
[ 1.14198847 2.72435097 3.32645484 1.55818926]]
假设每个人名都和data数组中的一行相对应,并且我们想要选中所有’Bob’对应的行就可以使用布尔索引。由于数组的比较操作也是可以向量化。比较names数组和字符串’Bob’会产生一个布尔值数组:
print(names == 'Bob')
-----------------------------------------------------------------
[ True False False True False False False]
我们把布尔值数组当作索引值:
print(data[names == 'Bob'])
-----------------------------------------------------------------
[[ 0.4992984 -0.07234365 0.14451715 -0.41352239]
[-0.12484777 1.40737756 -0.25473659 0.56018487]]
这个时候我们就可以选出所有’Bob’对应的行的数据,分别是第一行和第三行。由此可见当我们想要对一个数组的特定标签来从数据中筛选特点标签所指定的数据时可以用到布尔索引。
但我们需注意的一点就是:布尔值数组的长度必须和数组竖轴的索引长度一致。当布尔值数组的长度不正确时,布尔值选择数据的方法并不会报错。
我们甚至还可以用切片或者整数值对布尔值数组进行混合和匹配。
print(data[names == 'Bob',2:])
print(data[names == 'Bob',3])
-----------------------------------------------------------------
[[ 0.14451715 -0.41352239]
[-0.25473659 0.56018487]]
[-0.41352239 0.56018487]
如果你想要选择的是除了’Bob’以外的其他书籍,可以使用!=或在条件表达式前使用~对条件取反:
print(data[~(names == 'Bob')])
-----------------------------------------------------------------
[[-0.39308394 1.4680289 -0.95722327 1.87224511]
[-0.26925324 -0.17984855 -1.64057174 -2.69845021]
[-0.06335307 -0.78682012 1.86302967 0.59474813]
[-0.93085943 3.07061212 -0.93294211 -1.89029313]
[ 1.14198847 2.72435097 3.32645484 1.55818926]]
当你想选择多个名字时,可以组合多个布尔值条件,需要使用布尔算术运算符,如&(and)和|(or):
print(data[(names == 'Bob') | (names == 'Will')])
-----------------------------------------------------------------
[[ 0.4992984 -0.07234365 0.14451715 -0.41352239]
[-0.26925324 -0.17984855 -1.64057174 -2.69845021]
[-0.12484777 1.40737756 -0.25473659 0.56018487]
[-0.06335307 -0.78682012 1.86302967 0.59474813]]
使用布尔值索引选择数据时,总是生成数据的拷贝,即使返回的数组并没有任何变化。需注意Python的关键字and 和 or对布尔数组并没有用,请使用&和|。
再我们学习到布尔索引时,利用布尔索引对每一行或每一列设置数值也是很简单的。
data[names != 'Joe']=7
print(data)
-----------------------------------------------------------------
[[ 7. 7. 7. 7. ]
[-0.39308394 1.4680289 -0.95722327 1.87224511]
[ 7. 7. 7. 7. ]
[ 7. 7. 7. 7. ]
[ 7. 7. 7. 7. ]
[-0.93085943 3.07061212 -0.93294211 -1.89029313]
[ 1.14198847 2.72435097 3.32645484 1.55818926]]
1.6 神奇索引
神奇索引是NumPy中的术语,用于描述使用整数数组进行数据索引。
假设我们有一个8x4 数组:
arr = np.empty((8,4))
for i in range(8):
arr[i]=i
print(arr)
-----------------------------------------------------------------
[[0. 0. 0. 0.]
[1. 1. 1. 1.]
[2. 2. 2. 2.]
[3. 3. 3. 3.]
[4. 4. 4. 4.]
[5. 5. 5. 5.]
[6. 6. 6. 6.]
[7. 7. 7. 7.]]
为了选出一个符合特定顺序的子集,你可以简单地通过传递一个包含指明所需顺序的列表或者数组来完成:
print(arr[[4, 3, 0, 6]])
-----------------------------------------------------------------
[[4. 4. 4. 4.]
[3. 3. 3. 3.]
[0. 0. 0. 0.]
[6. 6. 6. 6.]]
如果使用负的索引,将从尾部进行选择:
print(arr[[-3, -5, -7]])
-----------------------------------------------------------------
[[5. 5. 5. 5.]
[3. 3. 3. 3.]
[1. 1. 1. 1.]]
如果传递多个索引数组时,这样会根据每个索引元组对应的元素选出一个一维数组:
arr = np.arange(32).reshape((8, 4))
print(arr)
arr1 = arr[[1, 5, 7, 2], [0, 3, 1, 2]]
print(arr1)
-----------------------------------------------------------------
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
[16 17 18 19]
[20 21 22 23]
[24 25 26 27]
[28 29 30 31]]
[ 4 23 29 10]
在arr这个二维数组中,元素(1,0)、(5,3)、(7,1)和(2,2)被选中。
通常情况下,我们所设想的结果是通过选择矩阵中行列的子集所形成的矩形区域。
arr1 = arr[[1, 5, 7, 2]][:,[0, 3, 1, 2]]
print(arr1)
-----------------------------------------------------------------
[[ 4 7 5 6]
[20 23 21 22]
[28 31 29 30]
[ 8 11 9 10]]
第一个[]里是表示行,先从第一行取值,第二个[]则是对应的列值,切片表示长度为4,接着按照[0,3,1,2]顺序取值,分别为[4 7 5 6],以此类推
1.7 数组转置和换轴
1.7.1 转置
转置是一种特殊的数据重组形式,可以返回底层数据的视图而不需要复制任何内容。可以使用.T属性进行转置:
arr = np.arange(15).reshape((3, 5))
print(arr)
arr1 = arr.T
print(arr1)
-----------------------------------------------------------------
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
[[ 0 5 10]
[ 1 6 11]
[ 2 7 12]
[ 3 8 13]
[ 4 9 14]]
知道转置之后,有利于我们计算矩阵内积,矩阵内积会使用np.dot:
arr2 = np.dot(arr,arr1)
print(arr2)
-----------------------------------------------------------------
[[ 30 80 130]
[ 80 255 430]
[130 430 730]]
对于更高维度的数组,transpose方法可以接收包含轴编号的元组,用于置换轴,这里只作为演示,要是想知道原理可以私信或者自寻。
arr = np.arange(16).reshape((2,2,4))
print(arr)
arr1 = arr.transpose(1,0,2)
print(arr1)
-----------------------------------------------------------------
[[[ 0 1 2 3]
[ 4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]]
[[[ 0 1 2 3]
[ 8 9 10 11]]
[[ 4 5 6 7]
[12 13 14 15]]]
ndarray有一个swapaxes方法,该方法接收一对轴编号作为参数,并对轴进行调整用于重组数据:
arr1 = arr.swapaxes(1,2)
print(arr1)
-----------------------------------------------------------------
[[[ 0 4]
[ 1 5]
[ 2 6]
[ 3 7]]
[[ 8 12]
[ 9 13]
[10 14]
[11 15]]]
swapaxes返回的是数据的视图,而没有对数据进行复制。
第三天结束下班!!!!!