【笔记】初识NumPy
标准python中,list可以保存任意对象。所以list里实际保存的是对象的指针。例如我们需要保存一个list [1,2,3],那么实际上,就需要有3个指针和3个整数对象。浪费了内存和计算时间。
使用NumPy让科学计算更高效
为什么要使用NumPy的数组结构而不是python标准库的list?
因为python的list的元素在系统内存中是分散存储的。就是上面所提到的指针,指针指向的才是具体元素存储的位置。
而NumPys数组存储在一个均匀连续的内存块中。这样在遍历所有元素的时候,就不需要像list一样再去内存地址中挨个进行查找,从而节省了计算资源。
另外在内存访问模式中,缓存会直接把字节块从 RAM 加载到 CPU 寄存器中。因为数据连续的存储在内存中,NumPy 直接利用现代 CPU 的矢量化指令计算,加载寄存器中的多个连续浮点数。另外 NumPy 中的矩阵计算可以采用多线程的方式,充分利用多核 CPU 计算资源,大大提升了计算效率。
提升python效率的技巧
- 避免采用隐式拷贝,而是采用就地操作的方式。
比如我要把一个数x变为原来的2倍,应该写成:x*=2
, 而不是y=x*2
。这样速度能快两倍甚至更多。
NumPy入门
ndarray对象(N-dimensional array object)
ndarray实际上是多维数组的含义。
- 在NumPy数组中,维数成为秩(rank),一维数组的秩为1,二维数组的秩为2,以此类推。
- 在NumPy中,每一个线性的数组称为一个轴(axes),其实秩就是描述轴的数量。
创建数组
代码:1
2
3
4
5
6
7
8
9
10
11import numpy as np
a = np.array([1,2,3])
b = np.array([[1,2,3], [4,5,6], [7,8,9]])
# 通过下标访问数组元素
b[1,1] = 10
# 通过shape属性获取数组的大小
print(a.shape)
print(b.shape)
# 通过dtype获取元素的属性
print(a.dtype)
print(b)
执行结果:1
2
3
4
5
6
7
8(3,) # 数组a的大小
(3, 3) # 数组b的大小
int64 # 数组元素的属性
# 数组b
[[ 1 2 3]
[ 4 10 6]
[ 7 8 9]]
结构数组
代码: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
32import numpy as np
persontype = np.dtype(
{
'names':['name', 'age', 'chinese', 'math', 'english'],
'formats':['S32', 'i', 'i', 'i', 'f']
}
)
peoples = np.array(
[
('ZhangFei', 32, 75, 100, 90),
('GuanYu', 24, 85, 96, 88.5),
('ZhaoYun', 28, 85, 92, 96.5),
('HuangZhong', 29, 65, 85, 100)
],
dtype=persontype
)
age = peoples[:]['age']
chinese = peoples[:]['chinese']
math = peoples[:]['math']
english = peoples[:]['english']
print(age)
print(chinese)
print(math)
print(english)
print(np.mean(age))
print(np.mean(chinese))
print(np.mean(math))
print(np.mean(english))
执行结果:1
2
3
4
5
6
7
8[32 24 28 29] # age
[75 85 85 65] # chinese
[100 96 92 85] # math
[ 90. 88.5 96.5 100. ] # english
28.25 # average of age
77.5 # average of chinese
93.25 # average of math
93.75 # average of english
ufunc(universal function object)
代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14import numpy as np
# arange() 类似内置函数 range(),通过指定初始值,终值,步长来创建等差数列d额一维数组,默认是不包括终值的。
x1 = np.arange(1, 10, 2)
print(x1)
# linspace 是 linear space 的缩写,代表线性等分向量的含义。linspace() 通过指定初始值、终值、元素个数来创建等差数列的一维数组,默认是包括终值的。
x2 = np.linspace(1, 9, 5)
print(x2)
print(np.add(x1, x2))
print(np.subtract(x1, x2))
print(np.multiply(x1, x2))
print(np.divide(x1, x2))
print(np.power(x1, x2))
print(np.remainder(x1, x2))
print(np.mod(x1, x2))
执行结果:1
2[1 3 5 7 9]
[1. 3. 5. 7. 9.]
算数运算
代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import numpy as np
x1 = np.arange(1, 10, 2)
x2 = np.linspace(1, 9, 5)
# 数组元素相加
print(np.add(x1, x2))
# 数组元素相减
print(np.subtract(x1, x2))
# 数组元素相乘
print(np.multiply(x1, x2))
# 数组元素相除
print(np.divide(x1, x2))
# 数组元素求n次方
print(np.power(x1, x2))
# 数组元素求n取余数
print(np.remainder(x1, x2))
# 数组元素求n取余数
print(np.mod(x1, x2))
执行结果:1
2
3
4
5
6
7
8[ 2. 6. 10. 14. 18.]
[0. 0. 0. 0. 0.]
[ 1. 9. 25. 49. 81.]
[1. 1. 1. 1. 1.]
[1.00000000e+00 2.70000000e+01 3.12500000e+03 8.23543000e+05
3.87420489e+08]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
统计函数
计算数组 / 矩阵中的最大值函数 amax(),最小值函数 amin()
代码:1
2
3
4
5
6
7
8import numpy as np
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(np.amin(a))
print(np.amin(a,0))
print(np.amin(a,1))
print(np.amax(a))
print(np.amax(a,0))
print(np.amax(a,1))
1 | 1 |
amin() 用于计算数组中的元素沿指定轴的最小值。对于一个二维数组 a,amin(a) 指的是数组中全部元素的最小值,amin(a,0) 是延着 axis=0 轴的最小值,axis=0 轴是把元素看成了 [1,2,3], [4,5,6], [7,8,9] 三个元素,所以最小值为 [1,2,3],amin(a,1) 是延着 axis=1 轴的最小值,axis=1 轴是把元素看成了 [1,4,7], [2,5,8], [3,6,9] 三个元素,所以最小值为 [1,4,7]。同理 amax() 是计算数组中元素沿指定轴的最大值。
统计最大值和最小值之差ptp()
代码:1
2
3
4
5import numpy as np
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(np.ptp(a))
print(np.ptp(a,0))
print(np.ptp(a,1))
执行结果:1
2
38
[6 6 6]
[2 2 2]
对于相同的数组 a,np.ptp(a) 可以统计数组中最大值与最小值的差,即 9-1=8。同样 ptp(a,0) 统计的是沿着 axis=0 轴的最大值与最小值之差,即 7-1=6(当然 8-2=6,9-3=6,第三行减去第一行的 ptp 差均为 6),ptp(a,1) 统计的是沿着 axis=1 轴的最大值与最小值之差,即 3-1=2(当然 6-4=2, 9-7=2,即第三列与第一列的 ptp 差均为 2)。
统计数组的百分位数(percentile)
代码:1
2
3
4
5import numpy as np
a = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(np.percentile(a, 50))
print(np.percentile(a, 50, axis=0))
print(np.percentile(a, 50, axis=1))
执行结果:1
2
35.0
[4. 5. 6.]
[2. 5. 8.]
percentile() 代表着第 p 个百分位数,这里 p 的取值范围是 0-100,如果 p=0,那么就是求最小值,如果 p=50 就是求平均值,如果 p=100 就是求最大值。同样你也可以求得在 axis=0 和 axis=1 两个轴上的 p% 的百分位数。
统计数组中的中位数 median(), 平均数 mean()
1 | import numpy as np |
执行结果:1
2
3
4
5
65.0
[4. 5. 6.]
[2. 5. 8.]
5.0
[4. 5. 6.]
[2. 5. 8.]
统计数组中的加权平均值
代码:1
2
3
4
5
6
7import numpy as np
a = np.array([1,2,3,4])
wts = np.array([1,2,3,4])
# np.average(a)=(1+2+3+4)/4=2.5
print(np.average(a))
# np.average(a,weights=wts)=(1*1+2*2+3*3+4*4)/(1+2+3+4)=3.0
print(np.average(a,weights=wts))
执行结果:1
22.5
3.0
统计数组中的标准差 std()、方差 var()
代码:1
2
3
4import numpy as np
a = np.array([1,2,3,4])
print(np.std(a))
print(np.var(a))
执行结果:1
21.118033988749895
1.25
方差的计算是指每个数值与平均值之差的平方求和的平均值,即 mean((x - x.mean())** 2)。标准差是方差的算术平方根。在数学意义上,代表的是一组数据离平均值的分散程度。所以 np.var(a)=1.25, np.std(a)=1.118033988749895。
NumPy排序
那么这些排序算法在 NumPy 中实现起来其实非常简单,一条语句就可以搞定。这里你可以使用 sort 函数,sort(a, axis=-1, kind=‘quicksort’, order=None),默认情况下使用的是快速排序;在 kind 里,可以指定 quicksort、mergesort、heapsort 分别表示快速排序、合并排序、堆排序。同样 axis 默认是 -1,即沿着数组的最后一个轴进行排序,也可以取不同的 axis 轴,或者 axis=None 代表采用扁平化的方式作为一个向量进行排序。另外 order 字段,对于结构化的数组可以指定按照某个字段进行排序。
1 | a = np.array([[4,3,2],[2,4,1]]) |
1 | [[2 3 4] |