Numpy是Python中用于科学计算的核心库。它提供了高性能的多维数组对象,以及相关工具
绘制雪花 转自博客上看到的一位大牛的程序,利用Numpy + matplotlib 绘制雪花,效果如下:
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif' ] = ['FangSong' ] plt.rcParams['axes.unicode_minus' ] = False def rotate (p, d ): """返回点p绕原点逆时针旋转d度的坐标""" a = np.radians(d) m = np.array([[np.cos(a), np.sin(a)], [-np.sin(a), np.cos(a)]]) return np.dot(p, m) def koch_curve (p, q ): """将线段pq生成科赫曲线,返回uvw三个点""" p, q = np.array(p), np.array(q) u = p + (q - p) / 3 v = q - (q - p) / 3 w = rotate(v - u, 60 ) + u return u.tolist(), v.tolist(), w.tolist() def snow (triangle, k ): """给定三角形,生成封闭的科赫雪花""" for i in range (k): result = list () t_len = len (triangle) for j in range (t_len): p = triangle[j] q = triangle[(j + 1 ) % t_len] u, v, w = koch_curve(p, q) result.extend([p, u, w, v]) triangle = result.copy() triangle.append(triangle[0 ]) return triangle def plot_snow (snow_list ): """绘制雪花""" for triangle, k in snow_list: data = np.array(snow(triangle, k)) x, y = np.split(data, 2 , axis=1 ) plt.plot(x, y) plt.axis('equal' ) plt.show() snow_list = [ ([(0 , 0 ), (0.5 , 0.8660254 ), (1 , 0 )], 5 ), ([(1.1 , 0.4 ), (1.35 , 0.8330127 ), (1.6 , 0.4 )], 4 ), ([(1.1 , -0.1 ), (1.25 , 0.15980761 ), (1.4 , -0.1 )], 3 ) ] plot_snow(snow_list)
数组Arrays numpy数组是一个由不同数值组成的网格。网格中的数据都是同一种数据类型 ,可以通过非负整型数的元组来访问。
我们可以从列表创建数组,然后利用方括号访问其中的元素。
1 2 3 4 5 6 7 8 9 10 11 import numpy as npa = np.array([1 ,2 ,3 ]) print(type (a)) print(a[0 ],a[1 ],a[2 ]) a[0 ] = 5 print(a) <class 'numpy .ndarray '> 1 2 3 [5 2 3]
函数shape()用法 shape函数功能室查看矩阵或者数组的维度 。
例如:建立一个3✖3的单位矩阵e,e.shape()为(3,3),表示三行三列 ,第一维的长度是3,第二维的长度也是3。
1 2 3 4 5 6 7 8 9 10 e = np.eye(3 ) print(e) print(e.shape) print(e[0 ,0 ],e[1 ,1 ]) [[ 1. 0. 0. ] [ 0. 1. 0. ] [ 0. 0. 1. ]] (3 , 3 ) 1.0 1.0
建立一个一维矩阵b,b.shape为矩阵的长度。
1 2 3 4 b = np.array([1 ,2 ,3 ,4 ]) print(b.shape) (4 ,)
建立一个4✖2的矩阵c,c.shape[1]为第一维的长度,c.shape[0]为第二维的长度,c.shape[1]为第一维的长度。
1 2 3 4 5 6 c = np.array([[1 ,2 ],[3 ,5 ],[9 ,5 ],[4 ,0 ]]) print(c.shape[0 ]) print(c.shape[1 ]) 4 2
一个单独的数值,返回值为空。
其他创建数组的方法 Numpy还提供了很多其他创建数组的方法:
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 32 33 34 35 36 37 38 39 40 import numpy as npa = np.zeros((2 ,3 )) print(a) print("\n" ) b = np.ones((1 ,2 )) print(b) print("\n" ) c = np.full((4 ,2 ),7 ) print(c) print("\n" ) d = np.eye(2 ) print(d) print("\n" ) e = np.random.random((2 ,2 )) print(e) [[ 0. 0. 0. ] [ 0. 0. 0. ]] [[ 1. 1. ]] [[7 7 ] [7 7 ] [7 7 ] [7 7 ]] [[ 1. 0. ] [ 0. 1. ]] [[ 0.82662589 0.93604335 ] [ 0.20764393 0.53211415 ]]
访问数组 切片 切片:和Python列表类似,numpy数组可以使用切片语法。因为数组是多维的,所以必须为每个维度指定好切片。
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 import numpy as npa = np.array([[1 ,2 ,3 ,4 ],[5 ,6 ,7 ,8 ],[9 ,10 ,11 ,12 ]]) print(a) print("\n" ) b = a[:2 ,1 :3 ] print(b) print("\n" ) print(a[0 ,1 ]) b[0 ,0 ] = 77 print(a) [[ 1 2 3 4 ] [ 5 6 7 8 ] [ 9 10 11 12 ]] [[2 3 ] [6 7 ]] 2 [[ 1 77 3 4 ] [ 5 6 7 8 ] [ 9 10 11 12 ]]
你可以同时使用整型和切片语法来访问数组 。但是,这样会产生一个比原数组低阶的新数组。
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 import numpy as npa = np.array([[1 ,2 ,3 ,4 ],[5 ,6 ,7 ,8 ],[9 ,10 ,11 ,12 ]]) print(a) print(a.shape) print("\n" ) row_r1 = a[1 ,:] row_r2 = a[1 :2 ,:] print(row_r1) print(row_r1.shape) print("\n" ) print(row_r2) print(row_r2.shape) print("\n" ) [[ 1 2 3 4 ] [ 5 6 7 8 ] [ 9 10 11 12 ]] (3 , 4 ) [5 6 7 8 ] (4 ,) [[5 6 7 8 ]] (1 , 4 )
整型数组访问 当我们使用切片语法访问数组时,得到的总是原数组的一个子集。整型数组访问允许我们利用其他数组的数据构建一个新的数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import numpy as npa = np.array([[1 ,2 ],[3 ,4 ],[5 ,6 ]]) print(a) print("\n" ) print(a[[0 ,1 ,2 ],[0 ,1 ,0 ]]) print([a[0 ,0 ],a[1 ,1 ],a[2 ,0 ]]) [[1 2 ] [3 4 ] [5 6 ]] [[1 4 5 ]] [1 , 4 , 5 ]
整型数组访问语法还有一个有用的技巧,可以用来选择或者更改矩阵中每行中的一个元素:
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 import numpy as npa = np.array([[1 ,2 ,3 ],[4 ,5 ,6 ],[7 ,8 ,9 ],[10 ,11 ,12 ]]) print(a) print("\n" ) b = np.array([0 ,2 ,0 ,1 ]) print(a[np.arange(4 ),b]) print("\n" ) a[np.arange(4 ),b] += 10 print(a) [[ 1 2 3 ] [ 4 5 6 ] [ 7 8 9 ] [10 11 12 ]] [ 1 6 7 11 ] [[11 2 3 ] [ 4 5 16 ] [17 8 9 ] [10 21 12 ]]
布尔型数组访问 布尔数组访问可以让你选择数组中任意元素。通常,这种访问方式用于选取数组中满足某些条件的元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import numpy as npa = np.array([[1 ,2 ],[3 ,4 ],[5 ,6 ]]) bool_idx = (a > 2 ) print(bool_idx) print(a[bool_idx]) print(a[a > 2 ]) [[False False ] [ True True ] [ True True ]] [3 4 5 6 ] [3 4 5 6 ]
数组计算 既可利用操作符重载,也可以使用函数方式:
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 32 33 34 35 import numpy as npx = np.array([[1 ,2 ],[3 ,4 ]],dtype=np.float64) y = np.array([[5 ,6 ],[7 ,8 ]],dtype=np.float64) print(x+y) print(np.add(x,y)) print(x-y) print(np.subtract(x,y)) print(x*y) print(np.multiply(x,y)) print(x/y) print(np.divide(x,y)) print(np.sqrt(x)) a = np.array([[1 ,2 ],[3 ,4 ]]) b = np.array([[5 ,6 ],[7 ,8 ]]) v = np.array([9 ,10 ]) w = np.array([11 ,12 ]) print(v.dot(w)) print(np.dot(v,w)) print(a.dot(v)) print(np.dot(a,v))
Numpy提供了很多计算数组的函数,其中最常用的一个是sum:
1 2 3 4 5 6 7 8 9 10 11 12 import numpy as npx = np.array([[1 ,2 ],[3 ,4 ]]) print(np.sum (x)) print(np.sum (x,axis=0 )) print(np.sum (x,axis=1 ))
查看更多函数,查看SciPy.org
1 2 3 4 5 import numpy as npx = np.array([[1 ,2 ],[3 ,4 ]]) print(x.T)
查看更多操作数组的方法
广播Broadcasting 广播是一种强有力的机制,它让Numpy可以让不同大小的矩阵在一起进行数学计算。我们常会有一个小的矩阵和一个大的矩阵,然后需要用小的矩阵对大的矩阵做一些计算。
例如,我们想要把一个向量加到矩阵的每一行,我们可以这样做:
1 2 3 4 5 6 7 8 9 10 11 import numpy as npx = np.array([[1 ,2 ,3 ],[4 ,5 ,6 ],[7 ,8 ,9 ],[10 ,11 ,12 ]]) v = np.array([1 ,0 ,1 ]) y = np.empty_like(x) for i in range (4 ): y[i,:] = x[i,:] + v print(y)
这样是行的通的,但是当x矩阵非常大,利用循环开计算就会变得很慢很慢。我们可以换一种思路。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import numpy as npx = np.array([[1 ,2 ,3 ],[4 ,5 ,6 ],[7 ,8 ,9 ],[10 ,11 ,12 ]]) v = np.array([1 ,0 ,1 ]) vv = np.tile(v,(4 ,1 )) print(vv) y = x + vv print(y) [[1 0 1 ] [1 0 1 ] [1 0 1 ] [1 0 1 ]] [[ 2 2 4 ] [ 5 5 7 ] [ 8 8 10 ] [11 11 13 ]]
Numpy广播机制可以让我们不用创建vv,就能直接运算 ,看看下面的例子。
1 2 3 4 5 6 7 8 9 10 11 12 import numpy as npx = np.array([[1 ,2 ,3 ],[4 ,5 ,6 ],[7 ,8 ,9 ],[10 ,11 ,12 ]]) v = np.array([1 ,0 ,1 ]) y = x + v print(y) [[ 2 2 4 ] [ 5 5 7 ] [ 8 8 10 ] [11 11 13 ]]
对两个数组使用广播机制要遵守下列规则:
1.如果数组的秩不同,使用1来将秩小的数组进行扩展,直到两个数组的尺寸长度都一样。
2.如果两个数组在某个维度上的长度是一样的,或者其中一个数组在该维度上的长度为1,那么我们说这两个数组在该维度上是相容 的。
3.如果两个数组在所有维度上都是相容的,它们就能使用广播。
4.如果两个输入数组的尺寸不同,那么注意其中较大的那个尺寸。因为广播之后,两个数组的尺寸将和较大的尺寸一样。
5.在任何一个维度上,如果一个数组的长度为1,另一个数组的长度大于1,那么在该维度上,就好像是对第一个数组进行了复制。
参阅文档 和注释 。支持广播机制的函数是全局函数。哪些是全局函数可以在文档 中查找。
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 32 33 34 35 import numpy as npv = np.array([1 ,2 ,3 ]) w = np.array([4 ,5 ]) print(np.reshape(v,(3 ,1 )) * w) x = np.array([[1 ,2 ,3 ],[4 ,5 ,6 ]]) print(x + v) print(x.T + w) print(x + np.reshape(w,(2 ,1 ))) print(x * 2 ) [[ 4 5 ] [ 8 10 ] [12 15 ]] [[2 4 6 ] [5 7 9 ]] [[ 5 9 ] [ 6 10 ] [ 7 11 ]] [[ 5 6 7 ] [ 9 10 11 ]] [[ 2 4 6 ] [ 8 10 12 ]]
Numpy文档 此文介绍了numpy中的一些重要内容,但是numpy远不止如此,可以查阅numpy 文献来学习更多。
SciPy
Numpy提供了高性能的多维数组,以及计算和操作数组的基本工具。Scipy基于Numpy,提供了大量的计算和操作数组的函数,这些函数对于不同类型的科学和工程计算非常有用。
SciPy文档 。
点之间的距离 SciPy定义了一些有用的函数,可以计算集合中点之间的距离。
函数scipy.spatial.distance.pdist能够计算集合中所有两点之间的距离。
1 2 3 4 5 6 7 8 import numpy as npfrom scipy.spatial.distance import pdist, squareformx = np.array([[0 ,1 ],[1 ,0 ],[2 ,0 ]]) print(x) d = squareform(pdist(x,'euclidean' )) print(d)
具体细节请阅读文档 。
函数scipy.spatial.distance.cdist 可以计算不同集合中点的距离,具体请查看文档 。