Python之Numpy库(7)

补充内容

来自《利用Python进行数据分析》,仅供自己学习使用,严禁转载用于其他商业用途。

神奇的索引

arr = np.empty((8, 4))
for i in range(8):
    arr[i] = i
print(arr)
print('------------')
print(arr[[4, 3, 0, 6]])
print('------------')
print(arr[[-3, -5, -7]])

#结果
[[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.]]
------------
[[4. 4. 4. 4.]
 [3. 3. 3. 3.]
 [0. 0. 0. 0.]
 [6. 6. 6. 6.]]
------------
[[5. 5. 5. 5.]
 [3. 3. 3. 3.]
 [1. 1. 1. 1.]]

 首先,我们生成一个8行4列的数组,然后根据索引进行切片,取出第4,3,0,6四行的数据,最后,我们根据索引,取出倒数第3、5、7行的数据。

传递多个索引数组时情况有些许不同,这样会根据每个索引元组对应的元素选出一个一维数组:

arr = np.arange(32).reshape((8, 4))
print(arr)

#结果
[[ 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]]
print(arr[[1,5,7,2],[0,3,1,2]])

#
[ 4 23 29 10]

上述例子中,元素(1,0)、(5,3)、(7,1)、(2,2)被选中。如果不考虑数组的维数,索引的结果总是一维的。

数组转置和换轴

转置是一种特殊的数据重组形式,可以返回底层数据的视图而不需要赋值任何内容。数组拥有transpose方法,也有特殊的T属性。

import numpy as np
arr = np.arange(15).reshape((3, 5))
print(arr)
print('--------------')
print(arr.T)

#
[[ 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

arr = np.random.randn(6, 3)
print(arr)
print('--------')
print(np.dot(arr.T, arr))

#
[[ 2.36529252  1.45634028 -0.45027236]
 [-1.85345472  1.50493214 -0.13627173]
 [-1.05013824 -0.13728287 -0.24801649]
 [-0.85897001  0.14457997  1.79092397]
 [ 1.24476335 -1.34613385 -0.23993914]
 [-0.77263369  0.04402339 -0.49494594]]
--------
[[13.0169215  -1.03430871 -2.00660628]
 [-1.03430871  6.23951211 -0.26664834]
 [-2.00660628 -0.26664834  3.79277832]]

对于更高维度的数组,transpose方法可以接受包含轴编号的元组,用于置换轴:

arr = np.arange(16).reshape((2, 2, 4))
print(arr)
print('--------')
print(arr.transpose((1, 0, 2)))

#
[[[ 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]]]

这里,轴已经被重新排序,使得原先的第二个轴变为第一个,原先的第一个轴变成第二个,最后一个轴并没有变。

通用函数:快速的逐元素数组函数

通用函数,也可以成为ufunc,是一种在ndarray数据中进行逐元素操作的函数。某些简单函数接受一个或多个标量数值,并产生一个或多个标量结果,而通用函数就是对这些简单函数的向量化封装。

arr = np.arange(10)
print(arr)
print('----------')
print(np.sqrt(arr))
print('----------')
print(np.exp(arr))

#
[0 1 2 3 4 5 6 7 8 9]
----------
[0.         1.         1.41421356 1.73205081 2.         2.23606798
 2.44948974 2.64575131 2.82842712 3.        ]
----------
[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]

使用sqrt()方法对数组内的元素开根号,exp()方法返回e的n次方,e是一个常数为2.71828。

这是所谓的一元通用函数,还有一些通用函数,比如add或maximum则会接受两个数组并返回一个数组作为结果,因此成为二元通用函数:

x = np.random.randn(8)
y = np.random.randn(8)
print(x)
print(y)
print(np.maximum(x, y))

#
[-2.01960726  0.51696239  0.77124305  1.20857829 -1.204375    1.4427587
  0.12709071  0.29780411]
[-0.28531979 -0.32238757 -0.44377128 -0.3816275   1.75887677  0.98860426
 -0.76177926 -0.84858413]
[-0.28531979  0.51696239  0.77124305  1.20857829  1.75887677  1.4427587
  0.12709071  0.29780411]

numpy.maximum逐个元素地将x和y中元素最大的值计算出来。

也有一些返回多个数组的函数。比如modf,是python内建函数divmod的向量化版本,它返回一个浮点值数组的小数部分和整数部分:

arr = np.random.randn(7) * 5
print(arr)
remainder, whole_part = np.modf(arr)
print(remainder)
print(whole_part)

#
[ 8.11757348 -0.70141921 -0.41606526  0.55060716  6.30934265 -5.97310928
  3.95041647]
[ 0.11757348 -0.70141921 -0.41606526  0.55060716  0.30934265 -0.97310928
  0.95041647]
[ 8. -0. -0.  0.  6. -5.  3.]

赋值时,前面的是小数部分,后面的是整数部分。

表1 一元通用函数
函数名 描述
abs、fabs 逐元素地计算整数、浮点数或复数的绝对值
sqrt 计算每个元素的平方根(与arr ** 0.5相等)
square 计算每个元素的平方(与arr**2相等)
exp 计算每个元素的自然指数值e**x
log、log10、log2、log1p 分别对应:自然对数(e为底)、对数10为底、对数2为底、log(1+x)
sign 计算每个元素的符号值:1(正数)、0(0)、-1(负数)
ceil 计算每个元素的最高整数值(即大于等于给定数值的最小整数)
floor 计算每个元素的最小整数值(即小于等于给定数值的最大整数)
modf 分别将数组中的小数部分和整数部分按数组形式返回
isnan 返回数组中的元素是否是一个NaN(不是一个数值),形式为布尔值数组
isfinite、isinf 分别返回数组中的元素是否有限(非inf、非NaN)、是否无限的,形式为布尔值数组
cos、cosh、sin、sinh、tan、tanh 常规的三角函数

arccos、arccosh、arcsin、

arcsinh、arctan、arctanh

反三角函数
logical_not 对数组的元素按位取反(与~arr效果一样)
表2 二元通用函数
函数名 描述
add 将数组的对应元素增加
subtract 在第二个数组中,将第一个数组中包含的元组去除
multiply 将数组的对应元素相乘
divide, floor_divide 除或整除(放弃余数)
power 将第二个数组的元素作为第一个数组对应元素的幂次方
maximum, fmax 逐个元素计算最大值,fmax忽略NaN
minimum, fmin 逐个元素计算最小值,fmax忽略NaN
mod 按元素的求模计算(即求除法的余数)
copysign 将第一个数组的符号值改为第二个数组的符号值

greater, greater_equal, less, 

less_equal, equal, not_equal, 

logical_and, logical_or, 

logical_xor

进行逐个元素的比较,返回布尔值数组(与数学操作符>、>=、<、<=、==、!= 效果一致)进行逐个元素的逻辑操作(与逻辑操作符&、|、^ 效果一致)

使用数组进行面向数组编程

利用数组表达式来替代显示循环的方法,称为向量化。

points = np.arange(-5, 5, 0.01)
xs, ys = np.meshgrid(points, points)
print(ys)

#
[[-5.   -5.   -5.   ... -5.   -5.   -5.  ]
 [-4.99 -4.99 -4.99 ... -4.99 -4.99 -4.99]
 [-4.98 -4.98 -4.98 ... -4.98 -4.98 -4.98]
 ...
 [ 4.97  4.97  4.97 ...  4.97  4.97  4.97]
 [ 4.98  4.98  4.98 ...  4.98  4.98  4.98]
 [ 4.99  4.99  4.99 ...  4.99  4.99  4.99]]
z = np.sqrt(xs ** 2 + ys ** 2)
print(z)

#
[[7.07106781 7.06400028 7.05693985 ... 7.04988652 7.05693985 7.06400028]
 [7.06400028 7.05692568 7.04985815 ... 7.04279774 7.04985815 7.05692568]
 [7.05693985 7.04985815 7.04278354 ... 7.03571603 7.04278354 7.04985815]
 ...
 [7.04988652 7.04279774 7.03571603 ... 7.0286414  7.03571603 7.04279774]
 [7.05693985 7.04985815 7.04278354 ... 7.03571603 7.04278354 7.04985815]
 [7.06400028 7.05692568 7.04985815 ... 7.04279774 7.04985815 7.05692568]]

可以求出根号下x**2 + y**2的值。

将条件逻辑作为数组操作

numpy.where函数式三元表达式x if condition else y的向量化版本。

xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])
result = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)]
print(result)

#
[1.1, 2.2, 1.3, 1.4, 2.5]

假设cond中的元素为True时,我们取axrr中的对应元素值,否则取yarr中的元素值,可以通过以上代码完成。但如果数组很大,速度会很慢,而使用np.where时,就可以非常简单地完成:

result = np.where(cond, xarr, yarr)
print(result)

#
[1.1 2.2 1.3 1.4 2.5]

np.where的第二个和第三个参数并不需要是数组,它们可以是标量。

arr = np.random.randn(4, 4)
print(arr)
print(arr > 0)
print(np.where(arr > 0, 2, -2))

#
[[ 0.61766413  0.05565645  0.17577733 -0.37404451]
 [-0.13572482 -0.86114914 -0.07353302 -0.03741651]
 [-0.27460935  0.41297701  0.27868873 -0.63462777]
 [ 0.18022908 -0.54048348  0.43320103  0.31274484]]

[[ True  True  True False]
 [False False False False]
 [False  True  True False]
 [ True False  True  True]]

[[ 2  2  2 -2]
 [-2 -2 -2 -2]
 [-2  2  2 -2]
 [ 2 -2  2  2]]

例子中可以看到,我们将其中的正值都替换成2,负值都替换为-2,使用np.where很容易实现。

如果仅将正值替换为2,可以写成:print(np.where(arr > 0, 2,arr))

数学和统计方法

arr = np.random.randn(5, 4)
print(arr)
print(arr.mean())
print(np.mean(arr))
print(arr.sum())

#
[[-2.80990453e-01 -7.58276181e-01 -1.14295903e+00 -1.38200808e+00]
 [-1.99594965e-01 -1.38398991e+00 -1.19742730e+00 -3.04548718e-01]
 [-2.27579601e-03 -1.31106338e-01  9.01807874e-01  5.98710554e-01]
 [ 2.30283103e+00  2.25508761e+00 -2.11443469e-01  1.31561031e+00]
 [ 1.34378629e+00  7.02711284e-01  1.58238066e+00  9.33821461e-01]]

0.24710634198581216

0.24710634198581216

4.942126839716243

像mean、sum等函数可以接受一个可选参数axis,这个参数可以用于计算给定轴向上的统计值,形成一个下降一维度的数组:

arr = np.random.randn(5, 4)
print(arr)
print(arr.mean(axis=1))
print(arr.sum(axis=0))

#
[[ 0.59696253  1.11121983 -0.1610959  -1.8332755 ]
 [ 0.07409587 -2.14484861  0.50016975  0.76153254]
 [-1.28510856  0.28761388  0.55825006  0.64558745]
 [-0.38153078  0.83174068 -0.92845526  0.1239845 ]
 [ 0.22249535 -0.68529482 -0.17869785 -0.7053025 ]]

[-0.07154726 -0.20226261  0.05158571 -0.08856521 -0.33669996]

[-0.77308559 -0.59956904 -0.20982921 -1.00747352]

arr.mean(1)表示“计算每一行的平均值”,而arr.sum(0)表示“计算列轴向的累和”。

其他的方法,例如cumsum和cumprod并不会聚合,它们会产生一个中间结果:

arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
print(arr.cumsum())

#
[ 0  1  3  6 10 15 21 28]

在多维数组中,像cumsum这样的累积函数返回相同长度的数组,但是可以在指定轴向上根据较低维度的切片进行部分聚合:

arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
print(arr)
print(arr.cumsum(axis=0))
print(arr.cumprod(axis=1))

#
[[0 1 2]
 [3 4 5]
 [6 7 8]]

[[ 0  1  2]
 [ 3  5  7]
 [ 9 12 15]]

[[  0   0   0]
 [  3  12  60]
 [  6  42 336]]
表格3 基础数组统计方法
方法 描述
sum 沿着轴向计算所有元素的累和,0长度的数组,累和为0
mean 数学平均,0长度的数组平均值为NaN
std, var 标准差和方差,可以选择自由度调整(默认分母是n)
min, max  最大值和最小值
argmin, argmax 最大值和最小值的位置
cumsum 从0开始元素累积和
cumprod 从1开始元素累积积
发布了27 篇原创文章 · 获赞 9 · 访问量 994

猜你喜欢

转载自blog.csdn.net/sinat_42574069/article/details/102057475