Numpy - 多维数组(下)

  • 一操作 numpy 数组的常用函数
  • 二线性代数
    • 标量运算
    • Element-wise逐项乘 数组-数组 运算
    • 矩阵代数
    • 数组矩阵 变换
    • 矩阵计算
      • 数据处理例子用 numpy 来处理斯德哥尔摩天气的数据
      • 对子数组的操作
      • 对高维数组的操作
    • 改变形状与大小
    • 增加一个新维度 newaxis
    • 叠加与重复数组
    • 浅拷贝与深拷贝
    • 遍历数组元素
    • 矢量化函数
    • 数组与条件判断
    • 类型转换


一、操作 numpy 数组的常用函数

  • where
    使用 where 函数能将索引掩码转换成索引位置:
indices = where(mask)  
indices
=> (array([11, 12, 13, 14]),)

x[indices] # this indexing is equivalent to the fancy indexing x[mask]
=> array([ 5.5,  6. ,  6.5,  7. ])
  • diag
    使用 diag 函数能够提取出数组的对角线:
diag(A)
=> array([ 0, 11, 22, 33, 44])

diag(A, -1)
=> array([10, 21, 32, 43])
  • take
    take 函数与高级索引(fancy indexing)用法相似:
v2 = arange(-3,3)
v2
=> array([-3, -2, -1,  0,  1,  2])

row_indices = [1, 3, 5]
v2[row_indices] # fancy indexing
=> array([-2,  0,  2])

v2.take(row_indices)
=> array([-2,  0,  2])

但是 take 也可以用在 list 和其它对象上:

take([-3, -2, -1,  0,  1,  2], row_indices)
=> array([-2,  0,  2])
  • choose
    选取多个数组的部分组成新的数组:
which = [1, 0, 1, 0]
choices = [[-2,-2,-2,-2], [5,5,5,5]]
choose(which, choices)
=> array([ 5, -2,  5, -2])

二、线性代数

矢量化是用 Python/Numpy 编写高效数值计算代码的关键,这意味着在程序中尽量选择使用矩阵或者向量进行运算,比如矩阵乘法等。

1.标量运算

使用一般的算数运算符,比如加减乘除,对数组进行标量运算。

v1 = arange(0, 5)
v1 * 2
=> array([0, 2, 4, 6, 8])

v1 + 2
=> array([2, 3, 4, 5, 6])

A * 2, A + 2 #分别作用在矩阵每个元素上

2. Element-wise(逐项乘) 数组-数组 运算

在矩阵间进行加减乘除时,它的默认行为是 element-wise(逐项乘) 的:
A * A # 元素相乘

3. 矩阵代数

使用 dot 函数进行 矩阵-矩阵,矩阵-向量,数量积乘法:

dot(A, A)
dot(A, v1)
=> array([ 30, 130, 230, 330, 430])

dot(v1, v1)
=> 30

将数组对象映射到 matrix 类型。 加减乘除不兼容的维度时会报错

M = matrix(A)
v = matrix(v1).T # make it a column vector
v
=> matrix([[0],
           [1],
           [2],
           [3],
           [4]])

 M * v
=> matrix([[ 30],
           [130],
           [230],
           [330],
           [430]])

v.T * v   # inner product
=> matrix([[30]])

查看其它运算函数: inner, outer, cross, kron, tensordot可以使用 help(kron)。

4. 数组/矩阵 变换

之前使用 .T 对 v 进行了转置,也可以使用 transpose 函数完成同样的事情。其他函数:

共轭conjugate(C)

C = matrix([[1j, 2j], [3j, 4j]])
conjugate(C)
=> matrix([[ 0.-1.j,  0.-2.j],
           [ 0.-3.j,  0.-4.j]])

共轭转置C.H

C.H
=> matrix([[ 0.-1.j,  0.-3.j],
           [ 0.-2.j,  0.-4.j]])

real 与 imag 能够分别得到复数的实部与虚部:

 real(C) # same as: C.real
=> matrix([[ 0.,  0.],
           [ 0.,  0.]])

imag(C) # same as: C.imag
=> matrix([[ 1.,  2.],
           [ 3.,  4.]])

angle 与 abs 可以分别得到幅角和绝对值:

angle(C+1) # heads up MATLAB Users, angle is used instead of arg
=> array([[ 0.78539816,  1.10714872],
          [ 1.24904577,  1.32581766]])

abs(C)
=> matrix([[ 1.,  2.],
           [ 3.,  4.]])

5. 矩阵计算

矩阵求逆C.I

from scipy.linalg import *
inv(C) # equivalent to C.I 

行列式linalg.det(C)

数据处理例子:用 numpy 来处理斯德哥尔摩天气的数据。

shape(data)
=> (77431, 7)

平均值

mean(data[:,3])# the temperature data is in column 3
=> 6.1971096847515925

标准差 与 方差

std(data[:,3]), var(data[:,3])
=> (8.2822716213405663, 68.596023209663286)

最小值 与 最大值

data[:,3].min()  # lowest daily average temperature
=> -25.800000000000001

data[:,3].max()  # highest daily average temperature
=> 28.300000000000001

总和, 总乘积 与 对角线和

d = arange(0, 10)
d
=> array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

sum(d)# sum up all elements  
=> 45

prod(d+1)  # product of all elements  +1从下标为1开始
=> 3628800

cumsum(d)# 累计总和
=> array([ 0,  1,  3,  6, 10, 15, 21, 28, 36, 45])

cumprod(d+1)# 累计乘积
=> array([      1,       2,       6,      24,     120,     720,    5040,
            40320,  362880, 3628800])

trace(A)# same as: diag(A).sum()
=> 110

对子数组的操作

通过在数组中使用索引,高级索引,和其它从数组提取数据的方法来对数据集的子集进行操作。
上述温度数据集的格式是:年,月,日,日均温度,最低温度,最高温度,地点。如果只关注一个特定月份的平均温度,比如2月份,那么可以创建一个索引掩码,只选取出需要的数据进行操作:

unique(data[:,1]) # the month column takes values from 1 to 12    只选出不同的值
=> array([  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,
        12.])

mask_feb = data[:,1] == 2 #选出第一列即月份为2的行
mean(data[mask_feb,3])# the temperature data is in column 3 二月份的平均温度
=> -3.2121095707366085

计算每个月的平均温度

months = arange(1,13)
monthly_mean = [mean(data[data[:,1] == month, 3]) for month in months]

对高维数组的操作

当诸如 min, max 等函数对高维数组进行操作时,有时希望对整个数组进行该操作,有时则希望对每一行进行该操作。使用 axis 参数可以指定函数的行为:

m = rand(3,3)

m.max() # global max

m.max(axis=0) # max in each column

m.max(axis=1) # max in each row

6. 改变形状与大小

Numpy 数组的维度可以在底层数据不用复制的情况下进行修改,所以 reshape 操作的速度非常快,即使是操作大数组。

A
=> array([[ 0,  1,  2,  3,  4],
          [10, 11, 12, 13, 14],
          [20, 21, 22, 23, 24],
          [30, 31, 32, 33, 34],
          [40, 41, 42, 43, 44]])

n, m = A.shape
B = A.reshape((1,n*m))  #数组B依然是二维,只是变成1*25
B
=> array([[ 0,  1,  2,  3,  4, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,
           32, 33, 34, 40, 41, 42, 43, 44]])

B[0,0:5] = 5 # modify the array    
B
=> array([[ 5,  5,  5,  5,  5, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,
           32, 33, 34, 40, 41, 42, 43, 44]])

A # and the original variable is also changed. B is only a different view of the same data
=> array([[ 5,  5,  5,  5,  5],
          [10, 11, 12, 13, 14],
          [20, 21, 22, 23, 24],
          [30, 31, 32, 33, 34],
          [40, 41, 42, 43, 44]])

也可以使用 flatten 函数创建一个高阶数组的向量版本,但是它会将数据做一份拷贝。

B = A.flatten()  #B是一维向量,25个元素
B
=> array([ 5,  5,  5,  5,  5, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,
          32, 33, 34, 40, 41, 42, 43, 44])

B[0:5] = 10    
B
=> array([10, 10, 10, 10, 10, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,
          32, 33, 34, 40, 41, 42, 43, 44])

A # now A has not changed, because B's data is a copy of A's, not refering to the same data
=> array([[ 5,  5,  5,  5,  5],
          [10, 11, 12, 13, 14],
          [20, 21, 22, 23, 24],
          [30, 31, 32, 33, 34],
          [40, 41, 42, 43, 44]])

7. 增加一个新维度: newaxis

newaxis 可以为数组增加一个新维度,比如将一个向量转换成列矩阵和行矩阵

v = array([1,2,3])
shape(v)
=> (3,)

v[:, newaxis]       # make a column matrix of the vector v
=> array([[1],
          [2],
          [3]])

v[:,newaxis].shape       # column matrix
=> (3, 1)

v[newaxis,:].shape       # row matrix
=> (1, 3)

8. 叠加与重复数组

函数 repeat, tile, vstack, hstack, 与 concatenate能以已有的矩阵为基础创建规模更大的矩阵。

tile 与 repeat

a = array([[1, 2], [3, 4]])

repeat(a, 3)  # repeat each element 3 times
=> array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])


tile(a, 3)  # tile the matrix 3 times 
=> array([[1, 2, 1, 2, 1, 2],
          [3, 4, 3, 4, 3, 4]])

concatenate

b = array([[5, 6]])
concatenate((a, b), axis=0)#加在最后一行
=> array([[1, 2],
          [3, 4],
          [5, 6]])

concatenate((a, b.T), axis=1) #加在最后一列
=> array([[1, 2, 5],
          [3, 4, 6]])

hstack 与 vstack

vstack((a,b))
=> array([[1, 2],
          [3, 4],
          [5, 6]])

hstack((a,b.T))
=> array([[1, 2, 5],
          [3, 4, 6]])

9. 浅拷贝与深拷贝

为了获得高性能,Python 中的赋值常常不拷贝底层对象,这被称作浅拷贝。

A = array([[1, 2], [3, 4]])    

B = A          # now B is referring to the same array data as A 

B[0,0] = 10    # changing B affects A

B
=> array([[10,  2],
          [ 3,  4]])

A
=> array([[10,  2],
          [ 3,  4]])

如果我们希望避免改变原数组数据的这种情况,那么我们需要使用 copy 函数进行深拷贝:

B = copy(A)

B[0,0] = -5               # now, if we modify B, A is not affected

B
=> array([[-5,  2],
          [ 3,  4]])

A
=> array([[10,  2],
          [ 3,  4]])

10. 遍历数组元素

通常情况下尽可能避免遍历数组元素,因为迭代相比向量运算要慢的多。当迭代不可避免时用 for 是最方便的:

M = array([[1,2], [3,4]])

for row in M:
    print("row", row)
    for element in row:
        print(element)

=> row [1 2]
   1
   2
   row [3 4]
   3
   4

需要遍历数组并更改元素内容时,用 enumerate 函数同时获取元素及对应的序号:

for row_idx, row in enumerate(M):
    print("row_idx", row_idx, "row", row)
    for col_idx, element in enumerate(row):
        print("col_idx", col_idx, "element", element)
        M[row_idx, col_idx] = element ** 2             # update the matrix M: square each element

row_idx 0 row [1 2]
col_idx 0 element 1
col_idx 1 element 2
row_idx 1 row [3 4]
col_idx 0 element 3
col_idx 1 element 4
# each element in M is now squared

11. 矢量化函数

为避免遍历向量和矩阵,用矢量算法代替。首先将标量算法转换为矢量算法:

def Theta(x):
    """
    Scalar implemenation of the Heaviside step function.
    """
    if x >= 0:
        return 1
    else:
        return 0

Theta 函数不是矢量函数所以无法处理向量。为了得到 Theta 函数的矢量化版本可以使用 vectorize 函数:

Theta_vec = vectorize(Theta)
Theta_vec(array([-3,-2,-1,0,1,2,3]))
=> array([0, 0, 0, 1, 1, 1, 1])

自己实现矢量函数:

def Theta(x):
    """
    Vector-aware implemenation of the Heaviside step function.
    """
    return 1 * (x >= 0)      #(x >= 0)已经矢量化

Theta(array([-3,-2,-1,0,1,2,3]))
=> array([0, 0, 0, 1, 1, 1, 1])

12. 数组与条件判断

M
=> array([[ 1,  4],
          [ 9, 16]])

if (M > 5).any():
    print("at least one element in M is larger than 5")
else:
    print("no element in M is larger than 5")
=> at least one element in M is larger than 5

if (M > 5).all():
    print("all elements in M are larger than 5")
else:
    print("not all elements in M are larger than 5")
=> not all elements in M are larger than 5

13. 类型转换

使用 astype 函数显示地对某些元素数据类型进行转换生成新的数组(可查看功能相似的 asarray 函数):

M.dtype
=> dtype('int64')

M2 = M.astype(float)    
M2
=> array([[  1.,   4.],
         [  9.,  16.]])

M2.dtype
=> dtype('float64')

M3 = M.astype(bool)
M3
=> array([[ True,  True],
          [ True,  True]], dtype=bool)

你可能感兴趣的:(Python科学计算)