本文出自<利用Python进行数据分析 第2版> 侵删
NumPy
NumPy 是Python数值计算最重要的基础包,可以高效处理大数组的数据.
NumPy的ndarray:一种多维的数组对象
ndarray是一个快速而又灵活的同构数据多维容器,是一个N维数组对象,其中所有的元素对象必须要是相同的数据类型,每一个对象包含一个元组和一个属性,分别是shape(一个表示各维度大小的元组)和dtype(一个说明数组数据类型的对象)
创建ndarray
创建ndarray最简单的方法是使用array函数,它接受一切序列型的对象(包括其它数组),然后产生一个新的含有传入数据的NumPy数组1
2
3
4
5
6In [1]: list1 = (1,2,3)
In [3]: import numpy as np
In [5]: data = np.array(list1)
In [6]: data
Out[6]: array([1, 2, 3])
嵌套序列会被转换成一个多维的数组,array函数会为新建的数组推断出一个较为合适的数据类型,数据类型保存在一个特殊的dtype对象中1
2
3
4
5
6
7
8
9
10
11
12
13
14In [7]: list2 = [[1,2,3],[4,5,6]]
In [8]: data2 = np.array(list2)
In [9]: data2
Out[9]:
array([[1, 2, 3],
[4, 5, 6]])
In [10]: data2.shape #查看维度大小
Out[10]: (2, 3)
In [11]: data2.dtype #查看元素类型
Out[11]: dtype('int64')
常用函数
zeros:创建指定长度或者形状全为0的数组
ones:创建指定长度或者形状全为1的数组
empty:可以创建一个没有任何具体值的数组
使用这些方法创建数组,只需要传入一个可以表示形状的元组便可1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23In [12]: np.zeros((10))
Out[12]: array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
In [13]: np.ones((2,3))
Out[13]:
array([[ 1., 1., 1.],
[ 1., 1., 1.]])
In [14]: np.empty((2,3,4))
Out[14]:
array([[[ 6.94667955e-310, 4.65986064e-310, 6.94667972e-310,
6.94667971e-310],
[ 6.94667972e-310, 6.94667971e-310, 6.94667852e-310,
6.94667972e-310],
[ 6.94667852e-310, 6.94667852e-310, 3.55727265e-321,
5.53353523e-322]],
[[ 0.00000000e+000, 6.94667867e-310, 6.94666603e-310,
6.94666605e-310],
[ 6.94666603e-310, 6.94667969e-310, 6.94666603e-310,
6.94667725e-310],
[ 6.94667974e-310, 6.94666603e-310, 6.94667974e-310,
6.94667971e-310]]])
arange是Python内置函数range的数组版
1 | In [15]: np.arange(10) |
备注:数据类型基本都是float64(浮点数)
创建时可以指定类型
1 | In [21]: data2 = np.array([1,2,3],dtype=np.float64) |
创建后可以修改类型,astype函数
1 | In [24]: data2.astype(int) |
#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
25In [51]: arr = np.array([[1., 2., 3.], [4., 5., 6.]])
In [52]: arr
Out[52]:
array([[ 1., 2., 3.],
[ 4., 5., 6.]])
In [53]: arr * arr #乘
Out[53]:
array([[ 1., 4., 9.],
[ 16., 25., 36.]])
In [54]: arr - arr #减
Out[54]:
array([[ 0., 0., 0.],
[ 0., 0., 0.]])
In [55]: 1 / arr #除
Out[55]:
array([[ 1. , 0.5 , 0.3333],
[ 0.25 , 0.2 , 0.1667]])
In [56]: arr ** 0.5 #指数
Out[56]:
array([[ 1. , 1.4142, 1.7321],
[ 2. , 2.2361, 2.4495]])
大小相同的数组可以产生布尔值数组
大小不同的数组之间的运算叫做广播1
2
3
4
5
6
7
8
9
10
11In [57]: arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])
In [58]: arr2
Out[58]:
array([[ 0., 4., 1.],
[ 7., 2., 12.]])
In [59]: arr2 > arr
Out[59]:
array([[False, True, False],
[ True, False, True]], dtype=bool)
切片和索引
NumPy产生的切片是视图,而并非是新的对象,当将一个标量值传给一个切片时,如arr[5:8]=12时,该值会自动传播到整个选区,这意味这在视图上,任意数据的修改都会影响到源数组1
2
3
4
5
6
7
8
9
10
11
12
13
14In [32]: data2 = np.array([1,2,3])
In [33]: data3 = data2[1:2]
In [34]: data3
Out[34]: array([2])
In [35]: data3[0] = 12 #通过索引去赋值,也可以通过索引去访问
In [36]: data3
Out[36]: array([12])
In [37]: data2
Out[37]: array([ 1, 12, 3])
切片[:]会给所有值赋值,例如arr[:] = 13
NumPy对数据的处理不包括复制粘贴的优势将体现在处理大规模的数据中 ,如果我们需要的是一份副本而不是一个视图的话,我们可以使用arr[5:8].copy()
索引的返回值可为元素也可为数组1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18In [39]: arr
Out[39]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
In [40]: arr[1]
Out[40]:
array([[ 7, 8, 9],
[10, 11, 12]])
In [41]: arr[1,1] #访问索引以(1,1)开头的那些值
Out[41]: array([10, 11, 12])
In [45]: arr[:1,1:,2:3] #切片的用法基本一致
Out[45]: array([[[6]]])
布尔型索引
常用于数据的匹配1
2
3
4
5
6
7
8
9In [46]: names = np.array(['wt','Bob'])
In [47]: scores = np.array([90,80])
In [48]: names == 'wt'
Out[48]: array([ True, False], dtype=bool)
In [49]: scores[names == 'wt']
Out[49]: array([90])
注意:布尔型数组的长度需要匹配对应数组的最高维度,在匹配的同事,我们还可以索引列,例如scores[name == ‘wt’,2:],还可以通过这样来赋值,例如:scores[names == ‘wt’] = 0
备注:~操作符可以用来反转条件,例如cond = names == ‘wt’,~cond就等同于names != ‘wt’
还有一点值得注意的是:Python关键字and和or在布尔型数组中无效,要使用&和|.
花式索引
数组装置
转置是重塑的一种特殊形式,它返回的是源数据的视图,不会进行任何的复制操作,转置使用数组的T属性
高维数组的装置需要使用transpose1
2
3
4
5
6
7
8
9
10
11
12
13
14
15array([[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.]])
In [11]: arr.T
Out[11]:
array([[ 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0.]])
计算矩阵内积
使用np.dot(arr1, arr2)来计算两个矩阵的内积
通用函数:快速的元素级数组函数
通用函数是一种对ndarray中的数据执行元素级运算的函数1
2
3
4In [15]: arr1 = np.array([2,2])
In [16]: np.sqrt(arr1)
Out[16]: array([ 1.41421356, 1.41421356])
将条件逻辑表述为数组运算
假设我们想根据cond中的值来选取xarr和yarr的值1
2
3
4
5
6
7
8
9
10In [29]: xarr = np.array([1.1,1.2,1.3,1.4,1.5])
In [30]: yarr = np.array([2.1,2.2,2.3,2.4,2.5])
In [31]: cond = np.array([True,False,True,True,False])
In [32]: result = [(x if c else y) for x,y,c in zip(xarr,yarr,cond)]
In [33]: result
Out[33]: [1.1000000000000001, 2.2000000000000002, 1.3, 1.3999999999999999, 2.5]
等同于1
2
3
4In [34]: result = np.where(cond,xarr,yarr)
In [35]: result
Out[35]: array([ 1.1, 2.2, 1.3, 1.4, 2.5])
np.where的第二个和第三个不必是数组,它们都可以是标量值.在数据分析的工作中,where的工作通常是根据一个数组产生另一个数组.假设一个由随机数组组成的矩阵,大于零的数都变成3,小于0的数都变成-3,若此时用利用where,则会变得非常方便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
62
63
64In [36]: arr = np.random.randn(6,6)
In [37]: arr
Out[37]:
array([[-1.45536948, -0.01610929, -0.02849423, -0.82497092, 1.05006367,
-0.20924655],
[-0.4434815 , -0.33147041, -0.61486327, -0.5423556 , 1.512384 ,
-1.35921009],
[-0.53875138, -0.25256538, 0.32190533, -0.20779243, 0.48525456,
0.97019284],
[ 0.12193935, -0.26348046, 0.86740783, -0.32927907, 0.35186663,
2.24697225],
[-0.49439342, 0.38880278, 0.52902035, 0.86600846, 1.31413569,
0.58566283],
[ 0.34011322, 0.96141724, -1.00353822, -0.30896308, -1.03500063,
-0.43719574]])
In [38]: arr>0
Out[38]:
array([[False, False, False, False, True, False],
[False, False, False, False, True, False],
[False, False, True, False, True, True],
[ True, False, True, False, True, True],
[False, True, True, True, True, True],
[ True, True, False, False, False, False]], dtype=bool)
In [39]: np.where(arr>0,3,-3)
Out[39]:
array([[-3, -3, -3, -3, 3, -3],
[-3, -3, -3, -3, 3, -3],
[-3, -3, 3, -3, 3, 3],
[ 3, -3, 3, -3, 3, 3],
[-3, 3, 3, 3, 3, 3],
[ 3, 3, -3, -3, -3, -3]])
In [40]: np.where(arr>0,3,arr) #把大于0的数赋值为3,其余赋值arr
Out[40]:
array([[-1.45536948, -0.01610929, -0.02849423, -0.82497092, 3. ,
-0.20924655],
[-0.4434815 , -0.33147041, -0.61486327, -0.5423556 , 3. ,
-1.35921009],
[-0.53875138, -0.25256538, 3. , -0.20779243, 3. ,
3. ],
[ 3. , -0.26348046, 3. , -0.32927907, 3. ,
3. ],
[-0.49439342, 3. , 3. , 3. , 3. ,
3. ],
[ 3. , 3. , -1.00353822, -0.30896308, -1.03500063,
-0.43719574]])
In [41]: np.where(arr>0,arr,3) #把大于0的赋值为arr,其余赋值为3
Out[41]:
array([[ 3. , 3. , 3. , 3. , 1.05006367,
3. ],
[ 3. , 3. , 3. , 3. , 1.512384 ,
3. ],
[ 3. , 3. , 0.32190533, 3. , 0.48525456,
0.97019284],
[ 0.12193935, 3. , 0.86740783, 3. , 0.35186663,
2.24697225],
[ 3. , 0.38880278, 0.52902035, 0.86600846, 1.31413569,
0.58566283],
[ 0.34011322, 0.96141724, 3. , 3. , 3. ,
3. ]])
数学和统计方法
用于布尔型数组的方法
1 | In [47]: arr = np.array([-1,2,-3]) |
另外还有两个方法any和all,它们对布尔型数组非常有用。any用于测试数组中是否存在一个或多个True,而all则检查数组中所有值是否都是True:1
2
3
4
5
6
7In [192]: bools = np.array([False, False, True, False])
In [193]: bools.any()
Out[193]: True
In [194]: bools.all()
Out[194]: False
这两个方法也能用于非布尔型数组,所有非0元素将会被当做True。
排序
1 | In [195]: arr = np.random.randn(6) |
唯一化以及其它集合逻辑
NumPy提供了一些针对ndarray的基本集合运算,最常用的是np.unique1
2
3
4
5
6In [56]: arr = np.array(['wt','jm','wt'])
In [57]: np.unique(arr) #找到唯一值,并返回
Out[57]:
array(['jm', 'wt'],
dtype='<U2')
线性代数
NumPy提供了一个用于矩阵乘法的dot函数(既是一个数组方法也是numpy命名空间中的一个函数)
伪随机数的生成
numpy.random模块对Python内置的random进行了补充,增添一些可以高效生成多种概率发布的样本值的方法