布尔索引
加入我们的数据都在数组里,并且数组中的数据时有重复的的人名。我们会使用 numpy.random.randn 函数来生成一些随机正态分布的数据:
names=np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
data = np.random.randn(7,4)
names = 'Bob' # 数组的比较操作也是可以向量化的。
array([ True, False, False, True, False, False, False])
data[names=='Bob'] # 索引数组传入布尔值数组
array([[-0.29428946, -0.38702775, 0.03886024, 0.35322932], # 提出了第一行第四行的数据
[-0.92449432, 0.39243842, -0.2197732 , -0.64333182]])
布尔值数组的长度必须和数组轴索引长度一致。你甚至可以用切片或整数值对布尔值数组进行混合和匹配。
当布尔值数组的长度不正确时,布尔值选择数据的方法并不会报错,因此使用这个特性的时候要小心。
data[names=='Bob',2:] # 选择 names==Bob 的行,并索引各个列。
names != 'Bob'
data[(~(names=='Bob')] # 选择处理 Bob 以外的数据,~ 取反
#当要选择多个名字时,可以使用 &(and) 和 |(or)
mask =(names=='Bob') | (names=='Will')
使用布尔值索引选择数据时,总是生成数据的视图。
python的关键字 and or 对布尔值数组没有用的,使用 & | 。我们也可以基于常识来设置布尔数组的值。
data[data < 0] =0
data[names != 'Joe'] = 7
神奇索引。。
神奇索引时numpy 中的术语,用于描述 使用整数数组 进行数据索引。
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.]]
arr[[-3,-5,-7]] # 我们可以传递一个包含指明所需顺序的列表或数组来选出一个符合特定顺序的子集
array([[5., 5., 5., 5.], # 负的索引从尾部开始
[3., 3., 3., 3.],
[1., 1., 1., 1.]])
传递多个索引数组的情况有所不同,这样会根据每个索引元组对应的元素选出一个一维数组。
- 重塑数组:将数组从一个形状转换成另一个形状,使用 reshape 方法。
arr = np.arrage(32).reshape((8,4))
array([[ 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]])
arr[[1,5,7,2],[0,3,1,2]]
array([ 4, 23, 29, 10])
这个例子中,(1,0),(5,3),(7,1),(2,2) 被选中。如果不考虑数组的维数,神奇索引的结果总是一维的。
神奇索引的行为跟我们想的并不相同,通常情况下,我们设想的结果时通过选中矩阵中行列的子集所形成的矩阵区域。
arr[[1,5,7,2]][:,[0,3,1,2]] # 通过这种方式实现我们的想法
array([[ 4, 7, 5, 6],
[20, 23, 21, 22],
[28, 31, 29, 30],
[ 8, 11, 9, 10]])
神奇索引与切片不同,他是将数据复制到一个新的数组中,也就说,改变它不会改变原数组。
数组转置和换轴
转置是一种特殊的数据重组方式,可以返回底层数据的视图而不需要复制任何内容。数组拥有 transpose 方法和特殊的 T 属性:(适用于一维,二维数组)
arr = np.arange(15).reshape((3,5))
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
arr.T
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
np.dot(arr.T,arr) # 计算矩阵的内积
对于更高维度的数组, transpose 方法可以接受包含编号的元组,用于置换轴。
arr = np.arange(16).reshape((2,2,4))
arr.transpose((1,0,2))
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
这里的轴已经被重新排序,原来的第二个轴转变成了第一个。。都表上坐标(0,1,0)-> (1,0,0) 这样的可能比较好理解。。。可以去看看这篇文章理解一下啊
使用 .T 进行转置时换轴的一个特殊案例,ndarray 有一个 swapaxes 方法,该方法接受一对轴编号,并对轴进行调整用于重组数据,
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
arr.swapaxes(1,2) # 跟 transpse(0,2,1) 一样
array([[[ 0, 4],
[ 1, 5],
[ 2, 6],
[ 3, 7]],
[[ 8, 12],
[ 9, 13],
[10, 14],
[11, 15]]]) # 返回的是视图
通用函数:快速的逐元素数组元素
通用函数也可以称为 ufunc ,是一种再 ndarray 数据中进行逐元素操作的函数,某些简单函数接受一个或多个标量数值,并产生一个标量结果,通用函数就是对这些简单函数的向量化封装。
arr = np.arange(10)
print(np.exp(arr)) # e 的多少次方
print(np.sqrt(arr)) # 平方根 这些就是一元通用函数
[1.00000000e+00 2.71828183e+00 7.38905610e+00 2.00855369e+01
5.45981500e+01 1.48413159e+02 4.03428793e+02 1.09663316e+03
2.98095799e+03 8.10308393e+03]
[0. 1. 1.41421356 1.73205081 2. 2.23606798
2.44948974 2.64575131 2.82842712 3. ]
x = np.random.randn(8)
y = np.random.randn(8)
np.maximum(x,y) # 逐个将 x,y 中较大值提出来,并返回一个数组作为结果,,还有 add 这些是二元通用函数
# 还有些通用函数返回多个数组,比如 modf 是python内置函数 divmod 的向量化版本。返回一个浮点值数组的小数部分和整数部分
arr = np.random.randn(7) *5
print(arr)
remainder,whole_port = np.modf(arr)
print(remainder)
print(whole_port)
[12.02538948 8.01871831 1.84609585 8.0471689 0.25140654 4.12570102
-7.03642332]
[ 0.02538948 0.01871831 0.84609585 0.0471689 0.25140654 0.12570102
-0.03642332]
[12. 8. 1. 8. 0. 4. -7.]
# 通用函数有一个可选参数 out ,结果保存的位置,没有提供就新产生一个数组,长度一致
arr
array([12.02538948, 8.01871831, 1.84609585, 8.0471689 , 0.25140654,
4.12570102, -7.03642332])
np.sqrt(arr,out=arr)
print(arr)
[3.46776434 2.83173415 1.3587111 2.83675323 0.50140457 2.03118217
nan] # 最后这个 nan 是无效的数值。
矩阵的合并
矩阵的合并可以通过numpy中的hstack方法和vstack方法实现:
arr1=np.arange(0,9).reshape((3,3))
arr2=np.arange(-9,0).reshape((3,3))
np.vstack((arr1,arr2))
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[-9, -8, -7],
[-6, -5, -4],
[-3, -2, -1]])
np.hstack((arr1,arr2))
array([[ 0, 1, 2, -9, -8, -7],
[ 3, 4, 5, -6, -5, -4],
[ 6, 7, 8, -3, -2, -1]])
矩阵的合并也可以通过concatenatef方法。
np.concatenate( (a1,a2), axis=0 ) 等价于 np.vstack( (a1,a2) )
np.concatenate( (a1,a2), axis=1 ) 等价于 np.hstack( (a1,a2) )