Python是一门不错的动态语言,其应用的领域非常广泛,如web开发、Linux运维、数据挖掘、机器学习、爬虫、推荐系统等。在学完《廖雪峰Python3教程》感觉受益匪浅,掌握了基本的语法之后开始接触用Python进行数据分析。这里向大家推荐两本书《Python数据分析》和《利用Python进行数据分析》
本期将会涉及到Python模块中的numpy,这是一个处理数组的强大模块,而该模块也是其他数据分析模块(如pandas和scipy)的核心。下面将从这5个方面来介绍numpu模块的内容:
1)数组的创建
2)有关数组的属性和函数
3)数组元素的获取--普通索引、切片、布尔索引和花式索引
4)统计函数与线性代数运算
5)随机数的生成
数组的创建
numpy中使用array()函数创建数组,array的首个参数一定是一个序列,可以是元组也可以是列表。
一维数组的创建
可以使用numpy中的arange()函数创建一维有序数组,它是内置函数range的扩展版。
In [1]: import numpy as np
In [2]: ls1 = range(10)
In [3]: list(ls1)
Out[3]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [4]: type(ls1)
Out[4]: range
In [5]: ls2 = np.arange(10)
In [6]: list(ls2)
Out[6]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [7]: type(ls2)
Out[7]: numpy.ndarray
通过arange生成的序列就不是简简单单的列表类型了,而是一个一维数组。
如果一维数组不是一个规律的有序元素,而是人为的输入,就需要array()函数创建了。
In [8]: arr1 = np.array((1,20,13,28,22))
In [9]: arr1
Out[9]: array([ 1, 20, 13, 28, 22])
In [10]: type(arr1)
Out[10]: numpy.ndarray
上面是由元组序列构成的一维数组。
In [11]: arr2 = np.array([1,1,2,3,5,8,13,21])
In [12]: arr2
Out[12]: array([ 1, 1, 2, 3, 5, 8, 13, 21])
In [13]: type(arr2)
Out[13]: numpy.ndarray
上面是由列表序列构成的一维数组。
二维数组的创建
二维数组的创建,其实在就是列表套列表或元组套元组。
In [14]: arr3 = np.array(((1,1,2,3),(5,8,13,21),(34,55,89,144)))
In [15]: arr3
Out[15]:
array([[ 1, 1, 2, 3],
[ 5, 8, 13, 21],
[ 34, 55, 89, 144]])
上面使用元组套元组的方式。
In [16]: arr4 = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
In [17]: arr4
Out[17]:
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
上面使用列表套列表的方式。
对于高维数组在将来的数据分析中用的比较少,这里关于高维数组的创建就不赘述了,构建方法仍然是套的方式。
上面所介绍的都是人为设定的一维、二维或高维数组,numpy中也提供了几种特殊的数组,它们是:
In [18]: np.ones(3) #返回一维元素全为1的数组
Out[18]: array([ 1., 1., 1.])
In [19]: np.ones([3,4]) #返回元素全为1的3×4二维数组
Out[19]:
array([[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.]])
In [20]: np.zeros(3) #返回一维元素全为0的数组
Out[20]: array([ 0., 0., 0.])
In [21]: np.zeros([3,4]) #返回元素全为0的3×4二维数组
Out[21]:
array([[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.]])
In [22]: np.empty(3) #返回一维空数组
Out[22]: array([ 0., 0., 0.])
In [23]: np.empty([3,4]) #返回3×4二维空数组
Out[23]:
array([[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.]])
有关数组的属性和函数
当一个数组构建好后,我们看看关于数组本身的操作又有哪些属性和函数:
In [24]: arr3
Out[24]:
array([[ 1, 1, 2, 3],
[ 5, 8, 13, 21],
[ 34, 55, 89, 144]])
In [25]: arr3.shape #shape方法返回数组的行数和列数
Out[25]: (3, 4)
In [26]: arr3.dtype #dtype方法返回数组的数据类型
Out[26]: dtype('int32')
In [27]: a = arr3.ravel() #通过ravel的方法将数组拉直(多维数组降为一维数组)
In [28]: a
Out[28]: array([ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144])
In [29]: b = arr3.flatten() #通过flatten的方法将数组拉直
In [30]: b
Out[30]: array([ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144])
两者的区别在于ravel方法生成的是原数组的视图,无需占有内存空间,但视图的改变会影响到原数组的变化。而flatten方法返回的是真实值,其值的改变并不会影响原数组的更改。
通过下面的例子也许就能明白了:
In [31]: b[:3] = 0
In [32]: arr3
Out[32]:
array([[ 1, 1, 2, 3],
[ 5, 8, 13, 21],
[ 34, 55, 89, 144]])
通过更改b的值,原数组没有变化。
In [33]: a[:3] = 0
In [34]: arr3
Out[34]:
array([[ 0, 0, 0, 3],
[ 5, 8, 13, 21],
[ 34, 55, 89, 144]])
a的值变化后,会导致原数组跟着变化。
In [35]: arr4
Out[35]:
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
In [36]: arr4.ndim #返回数组的维数
Out[36]: 2
In [37]: arr4.size #返回数组元素的个数
Out[37]: 12
In [38]: arr4.T #返回数组的转置结果
Out[38]:
array([[ 1, 5, 9],
[ 2, 6, 10],
[ 3, 7, 11],
[ 4, 8, 12]])
如果数组的数据类型为复数的话,real方法可以返回复数的实部,imag方法返回复数的虚部。
介绍完数组的一些方法后,接下来我们看看数组自身有哪些函数可操作:
In [39]: len(arr4) #返回数组有多少行
Out[39]: 3
In [40]: arr3
Out[40]:
array([[ 0, 0, 0, 3],
[ 5, 8, 13, 21],
[ 34, 55, 89, 144]])
In [41]: arr4
Out[41]:
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
In [42]: np.hstack((arr3,arr4))
Out[42]:
array([[ 0, 0, 0, 3, 1, 2, 3, 4],
[ 5, 8, 13, 21, 5, 6, 7, 8],
[ 34, 55, 89, 144, 9, 10, 11, 12]])
横向拼接arr3和arr4两个数组,但必须满足两个数组的行数相同。
In [43]: np.vstack((arr3,arr4))
Out[43]:
array([[ 0, 0, 0, 3],
[ 5, 8, 13, 21],
[ 34, 55, 89, 144],
[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
纵向拼接arr3和arr4两个数组,但必须满足两个数组的列数相同。
In [44]: np.column_stack((arr3,arr4)) #与hstack函数具有一样的效果
Out[44]:
array([[ 0, 0, 0, 3, 1, 2, 3, 4],
[ 5, 8, 13, 21, 5, 6, 7, 8],
[ 34, 55, 89, 144, 9, 10, 11, 12]])
In [45]: np.row_stack((arr3,arr4)) #与vstack函数具有一样的效果
Out[45]:
array([[ 0, 0, 0, 3],
[ 5, 8, 13, 21],
[ 34, 55, 89, 144],
[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
reshape()函数和resize()函数可以重新设置数组的行数和列数:
In [46]: arr5 = np.array(np.arange(24))
In [47]: arr5 #此为一维数组
Out[47]:
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
In [48]: a = arr5.reshape(4,6)
In [49]: a
Out[49]:
array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23]])
通过reshape函数将一维数组设置为二维数组,且为4行6列的数组。
In [50]: a.resize(6,4)
In [51]: a
Out[51]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
通过resize函数会直接改变原数组的形状。
数组转换:tolist将数组转换为列表,astype()强制转换数组的数据类型,下面是两个函数的例子:
In [53]: b = a.tolist()
In [54]: b
Out[54]:
[[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]
In [55]: type(b)
Out[55]: list
In [56]: c = a.astype(float)
In [57]: c
Out[57]:
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[ 12., 13., 14., 15.],
[ 16., 17., 18., 19.],
[ 20., 21., 22., 23.]])
In [58]: a.dtype
Out[58]: dtype('int32')
In [59]: c.dtype
Out[59]: dtype('float64')
数组元素的获取
通过索引和切片的方式获取数组元素,一维数组元素的获取与列表、元组的获取方式一样:
In [60]: arr7 = np.array(np.arange(10))
In [61]: arr7
Out[61]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [62]: arr7[3] #获取第4个元素
Out[62]: 3
In [63]: arr7[:3] #获取前3个元素
Out[63]: array([0, 1, 2])
In [64]: arr7[3:] #获取第4个元素即之后的所有元素
Out[64]: array([3, 4, 5, 6, 7, 8, 9])
In [65]: arr7[-2:] #获取末尾的2个元素
Out[65]: array([8, 9])
In [66]: arr7[::2] #从第1个元素开始,获取步长为2的所有元素
Out[66]: array([0, 2, 4, 6, 8])
二维数组元素的获取:
In [67]: arr8 = np.array(np.arange(12)).reshape(3,4)
In [68]: arr8
Out[68]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [69]: arr8[1] #返回数组的第2行
Out[69]: array([4, 5, 6, 7])
In [70]: arr8[:2] #返回数组的前2行
Out[70]:
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
In [71]: arr8[[0,2]] #返回指定的第1行和第3行
Out[71]:
array([[ 0, 1, 2, 3],
[ 8, 9, 10, 11]])
In [72]: arr8[:,0] #返回数组的第1列
Out[72]: array([0, 4, 8])
In [73]: arr8[:,-2:] #返回数组的后2列
Out[73]:
array([[ 2, 3],
[ 6, 7],
[10, 11]])
In [74]: arr8[:,[0,2]] #返回数组的第1列和第3列
Out[74]:
array([[ 0, 2],
[ 4, 6],
[ 8, 10]])
In [75]: arr8[1,2] #返回数组中第2行第3列对应的元素
Out[75]: 6
布尔索引,即索引值为True和False,需要注意的是布尔索引必须输数组对象。
In [76]: log = np.array([True,False,False,True,True,False])
In [77]: arr9 = np.array(np.arange(24)).reshape(6,4)
In [78]: arr9
Out[78]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
In [79]: arr9[log] #返回所有为True的对应行
Out[79]:
array([[ 0, 1, 2, 3],
[12, 13, 14, 15],
[16, 17, 18, 19]])
In [80]: arr9[~log] #通过‘~’号筛选出所有为False的对应行,在python3.5上
Out[80]:
array([[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[20, 21, 22, 23]])
举一个场景,一维数组表示区域,二维数组表示观测值,如何选取目标区域的观测?
In [81]: area = np.array(['A','B','A','C','A','B','D'])
In [82]: area
Out[82]:
array(['A', 'B', 'A', 'C', 'A', 'B', 'D'],
dtype='<U1')
In [83]: observes = np.array(np.arange(21)).reshape(7,3)
In [84]: observes
Out[84]:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17],
[18, 19, 20]])
In [85]: observes[area == 'A']
Out[85]:
array([[ 0, 1, 2],
[ 6, 7, 8],
[12, 13, 14]])
返回所有A区域的观测。
In [86]: observes[(area == 'A') | (area == 'D')] #条件值需要在&(and),|(or)两端用圆括号括起来
Out[86]:
array([[ 0, 1, 2],
[ 6, 7, 8],
[12, 13, 14],
[18, 19, 20]])
返回所有A区域和D区域的观测。
当然,布尔索引也可以与普通索引或切片混合使用:
In [87]: observes[area == 'A'][:,[0,2]]
Out[87]:
array([[ 0, 2],
[ 6, 8],
[12, 14]])
返回A区域的所有行,且只获取第1列与第3列数据。
花式索引:实际上就是将数组作为索引将原数组的元素提取出来
In [88]: arr10 = np.arange(1,29).reshape(7,4)
In [89]: arr10
Out[89]:
array([[ 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]])
In [90]: arr10[[4,1,3,5]] #按照指定顺序返回指定行
Out[90]:
array([[17, 18, 19, 20],
[ 5, 6, 7, 8],
[13, 14, 15, 16],
[21, 22, 23, 24]])
In [91]: arr10[[4,1,5]][:,[0,2,3]] #返回指定的行与列
Out[91]:
array([[17, 19, 20],
[ 5, 7, 8],
[21, 23, 24]])
In [92]: arr10[[4,1,5],[0,2,3]]
Out[92]: array([17, 7, 24])
请注意!这与上面的返回结果是截然不同的,上面返回的是二维数组,而这条命令返回的是一维数组