原文来自http://cs231n.github.io/python-numpy-tutorial/#python-containers
Numpy 数学处理
Numpy 是Python中科学计算的核心库,提供高性能多维度的数组阵列,还有处理这些数组的工具。
Arrays 数组、阵列
一个numpy数组是一个网格化的数值,数组是同样的类型,由一组非负整数索引。维数是数组的秩,数组的shape是一个整数元组,给出每个维度数组的大小。
我们可以通过嵌套的Python lists初始化numpy arrays,并用方括号访问每个元素。
import numpy as np
a = np.array([1, 2, 3]) # 创建秩为1 的数组
print(type(a)) # 输出 "<class 'numpy.ndarray'>"
print(a.shape) # 输出 "(3,)"
print(a[0], a[1], a[2]) # 输出 "1 2 3"
a[0] = 5 # 改变数组中的一个元素
print(a) # 输出 "[5, 2, 3]"
b = np.array([[1,2,3],[4,5,6]]) # 创建秩为2的数组
print(b.shape) # 输出 "(2, 3)"
print(b[0, 0], b[0, 1], b[1, 0]) # 输出 "1 2 4"
Numpy也提供了很多函数来创建数组。
import numpy as np
a = np.zeros((2,2)) # 创建一个全为0的数组
print(a) # 输出 "[[ 0. 0.]
# [ 0. 0.]]"
b = np.ones((1,2)) # 创建一个全为1的数组
print(b) # 输出 "[[ 1. 1.]]"
c = np.full((2,2), 7) # 创建一个常数数组
print(c) # 输出 "[[ 7. 7.]
# [ 7. 7.]]"
d = np.eye(2) # 创建一个2x2单位矩阵
print(d) # 输出 "[[ 1. 0.]
# [ 0. 1.]]"
e = np.random.random((2,2)) # 创建一个由随机值组成的数组
print(e) # 可能输出 "[[ 0.91940167 0.08143941]
# [ 0.68744134 0.87236687]]"
Array indexing数组索引
Numpy提供了几种索引数组的方法。
Slicing: 与Python lists类似,numpy arrays 可以被切分。因为数组一定是多维的,你必须为数组的每一个维度确定一个切分。
import numpy as np
#创建如下rank为2、shape为 (3, 4)的数组
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
# 运用slicing抽出包含前两行以及第2、3列的子数组,。
# b为shape为 (2, 2) 的子数组:
# [[2 3]
# [6 7]]
b = a[:2, 1:3]
#数组的切分是投射到相同数据上面去的,所以改变切分就会改变原来的数组数值。
print(a[0, 1]) # 输出 "2"
b[0, 0] = 77 # b[0, 0] 是a[0, 1]的数据
print(a[0, 1]) # 输出 "77"
你可以混合整数索引和切分索引。但是这样会产生一个秩比以前低的数组。这和MATLAB处理数组切分时完全不同:
import numpy as np
# 创建一个rank为2,shape为(3, 4)的数组
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
# 有两种方式可以访问到数组的中间行
# 将整数索引和切分索引混合,将会产生一个降秩数组
# 而只用切分的话,会产生一个和原先数组秩相同的数组
row_r1 = a[1, :] # 访问a的第二行,Rank为1
row_r2 = a[1:2, :] #访问a的第二行,Rank为2
print(row_r1, row_r1.shape) # 输出 "[5 6 7 8] (4,)"
print(row_r2, row_r2.shape) # 输出 "[[5 6 7 8]] (1, 4)"
# 对于列也一样:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape) # 输出 "[ 2 6 10] (3,)"
print(col_r2, col_r2.shape) # 输出 "[[ 2]
# [ 6]
# [10]] (3, 1)"
Integer array indexing整数数组索引: 当你用sllicing索引numpy数组的时候,得到的数组是原始数组的子数组。相反地,整数数组索引可以让你用其他数组的数据构造任意数组。如下:
import numpy as np
a = np.array([[1,2], [3, 4], [5, 6]])
# 一个整数数组索引的例子
# 返回数组的shape为 (3,)
print(a[[0, 1, 2], [0, 1, 0]]) # 输出 "[1 4 5]"
# 上述整数数组索引的例子与下面的索引是等价的:
print(np.array([a[0, 0], a[1, 1], a[2, 0]])) # 输出 "[1 4 5]"
# 运用整数数组索引的时候,你可以重复利用原数组里面同样的元素
print(a[[0, 0], [1, 1]]) # 输出 "[2 2]"
# 等价于之前的整数数组索引
print(np.array([a[0, 1], a[0, 1]])) # 输出 "[2 2]"
整数数组索引的一个小窍门是可以选择并改变矩阵中每一行的一个元素:
import numpy as np
# 创建一个新的数组,我们将在里面选择元素
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
print(a) # 输出 "array([[ 1, 2, 3],
# [ 4, 5, 6],
# [ 7, 8, 9],
# [10, 11, 12]])"
# 创建指号数组
b = np.array([0, 2, 0, 1])
# 运用b里面的指号,从a的每一行选择一个元素
print(a[np.arange(4), b]) # 输出 "[ 1 6 7 11]"
# 运用b里面的指号,改变a的每一行中的一个元素
a[np.arange(4), b] += 10
print(a) # 输出 "array([[11, 2, 3],
# [ 4, 5, 16],
# [17, 8, 9],
# [10, 21, 12]])
Boolean array indexing: 布尔型数组索引让你能够从数组中挑选出任意元素。经常地,这种索引方式用于选择数组中满足特定条件的元素。如下例:
import numpy as np
a = np.array([[1,2], [3, 4], [5, 6]])
bool_idx = (a > 2) # 找出a中大于2的元素,返回一个和a的shape相同的布尔型numpy数组,bool idx中的每一个元素表示了原数组中对应的该元素是否大于2;
print(bool_idx) # 输出 "[[False False]
# [ True True]
# [ True True]]"
# 我们用布尔型数组索引构造一个rank为 1 的数组,包含对应bool idx中True值得元素
print(a[bool_idx]) # 输出 "[3 4 5 6]"
# 我们可以用一个简明的陈述来完成上述所有操作
print(a[a > 2]) # 输出 "[3 4 5 6]"
Datatypes数据类型
每个numpy数组的元素都是同样的类型。Numpy提供了可供构造数组的多种数据类型。当你构造一个数组的时候,numpy试着去猜测一种数据类型。而函数也可用来指定一种数据类型。如下例:
import numpy as np
x = np.array([1, 2]) # 让numpy选择数据类型
print(x.dtype) # 输出 "int64"
x = np.array([1.0, 2.0]) #让numpy选择数据类型
print(x.dtype) # 输出 "float64"
x = np.array([1, 2], dtype=np.int64) # 强制一种特定的数据类型
print(x.dtype) # 输出 "int64"
Array math 数组数学
基本数学函数能够操作数组元素,数学函数可以是运算符,也可以是numpy模块中的函数。
import numpy as np
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)
# 元素与元素的和;都输出数组
# [[ 6.0 8.0]
# [10.0 12.0]]
print(x + y)
print(np.add(x, y))
#元素与元素的差;都输出数组
# [[-4.0 -4.0]
# [-4.0 -4.0]]
print(x - y)
print(np.subtract(x, y))
#元素与元素的积;都输出数组
# [[ 5.0 12.0]
# [21.0 32.0]]
print(x * y)
print(np.multiply(x, y))
#元素与元素的商;都输出数组
# [[ 0.2 0.33333333]
# [ 0.42857143 0.5 ]]
print(x / y)
print(np.divide(x, y))
#元素的平方根;都输出数组
# [[ 1. 1.41421356]
# [ 1.73205081 2. ]]
print(np.sqrt(x))
注意,不同于MATLAB, *是元素的乘法,不是矩阵的乘法。我们用dot函数计算向量的内部乘积,以及向量与矩阵的乘积,还有矩阵之间的乘积。dot函数可作为numpy模块中的一个函数,或者数组对象的一个实例方法。
import numpy as np
x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])
v = np.array([9,10])
w = np.array([11, 12])
# 向量之间的内部乘积; 都输出219
print(v.dot(w))
print(np.dot(v, w))
# 矩阵和向量乘积; 产生一个rank为1的数组[29 67]
print(x.dot(v))
print(np.dot(x, v))
# 矩阵和矩阵乘积; 产生一个rank为2的数组
# [[19 22]
# [43 50]]
print(x.dot(y))
print(np.dot(x, y))
Numpy提供了许多用于数组计算的函数,最有用的之一是sum:
import numpy as np
x = np.array([[1,2],[3,4]])
print(np.sum(x)) # 计算所有元素的和; 输出 "10"
print(np.sum(x, axis=0)) # 计算每一列的和; 输出 "[4 6]"
print(np.sum(x, axis=1)) #计算每一行的和; 输出 "[3 7]"
除了在数组间进行数学运算,我们经常需要改变数组的形状,或者操作数组中的数据。这种类型的操作中最简单的例子就是转置矩阵。让一个矩阵变成转置矩阵,只需要运用数组对象的T属性:
import numpy as np
x = np.array([[1,2], [3,4]])
print(x) # 输出 "[[1 2]
# [3 4]]"
print(x.T) # 输出 "[[1 3]
# [2 4]]"
# 注意,对rank为1的矩阵作转置没有变化:
v = np.array([1,2,3])
print(v) # 输出 "[1 2 3]"
print(v.T) # 输出 "[1 2 3]"