最近的爬虫学习告一段落,后续补上爬虫的笔记。现在到数据分析部分,先从NumPy开始(环境python-3.6.5) 2019/1/23

NumPy基础

NumPy是高性能科学计算和数据分析的基础包。包括以下几个功能:

  • ndarray,一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组;
  • 用于对整组数据进行快速运算的标准数学函数(无需编写循环);
  • 用于读写磁盘的工具以及用于操作内存映射文件的工具;
  • 线性代数,随机数生成以及傅里叶变换功能;
  • 用于集成由C,C++,Fortran等语言编写的代码的工具。

例子引入

用python原生代码对两个向量相加

def pythonsum(n):
    a = list(range(n))
    b = list(range(n))
    c = []
    for i in range(len(a)):
        a[i] = i ** 2
        b[i] = i ** 3
        c.append(a[i] + b[i])
    return c

arr = pythonsum(2)
print(arr)

利用NumPy对向量相加。

import numpy as np
def numpysum(n):
    a = np.arange(n) ** 2
    b = np.arange(n) ** 3
    c = a + b
    return c
arr = numpysum(2)
print(arr)

两种方法都可以对向量进行相加,相比而言利用NumPy库的代码会更简洁一点。可以对两种方法计算出执行时间,结果也是NumPy的效率高些。

ndarray,多维数组对象

NumPy中的ndarray是一个多维数组对象,这个对象是一个快速而且灵活的大数据集容器,该对象由两个部分组成:

  • 实际的数据
  • 描述这些数据的元数据

ndarray是一个通用的同构数据多维容器,指的是其中的元素必须是相同的数据类型,每一个数组都有一个shape(表示各维度大小的元组)和一个dtype(用于说明数据类型的对象)。

In [12]: import numpy as np

In [13]: a = np.arange(5)

In [14]: a.dtype
Out[14]: dtype('int32')

In [15]: a.shape
Out[15]: (5,)

In [16]: a
Out[16]: array([0, 1, 2, 3, 4])

NumPy中创建数组的函数

函数 说明
array 将输入数据(元组,列表或其他序列类型)转换为ndarray。要么推断出dtype,要么显示指定dtype。默认直接复制输入数据
asarray 将输入转换为ndarray,如果输入就是一个ndarray就不进行复制
arange 类似内置的range,但返回的是一个ndarray而不是一个列表
ones,ones_like 根据指定的形状和dtype创建一个全是1的数组。ones_like以另一个数组为参数,并根据其形状和dtype创建一个全为1的数组
zeros,zeros_like 类似于ones,ones_like,只不过创建的是全为0的数组

示例1:创建一维数组

In [12]: import numpy as np

In [29]: data = [1,2,3,4]

In [30]: arr = np.array(data)

In [31]: arr
Out[31]: array([1, 2, 3, 4])

示例2:创建多维数组

In [32]: data2 = [[1,2,3,4],[5,6,7,8]]

In [33]: arr2 = np.array(data2)

In [34]: arr2
Out[34]:
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])

In [35]: arr2.dtype
Out[35]: dtype('int32')

In [36]: arr2.shape
Out[36]: (2, 4)

示例3:使用zeros()函数创建元素全为0的数组

In [37]: np.zeros(5)
Out[37]: array([0., 0., 0., 0., 0.])

In [38]: np.zeros((2,4))
Out[38]:
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.]])

In [39]: np.zeros((4,2))
Out[39]:
array([[0., 0.],
       [0., 0.],
       [0., 0.],
       [0., 0.]])

示例4:使用empty()函数

In [44]: np.empty((2,4))
Out[44]:
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.]])
#empty函数大多数情况是返回一些未初始化的垃圾值

示例5:arange()函数

In [51]: np.arange(10)
Out[51]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

NumPy数据类型

图片描述

示例

In [4]: print(np.float64(42))
42.0

In [5]: print(np.int8(42.0))
42

In [6]: print(np.bool(42))
True

In [7]: print(np.bool(0))
False

定义数组的数据类型
创建数组的时候如果没有指定dtype的话,那么它会自动推断出数组元素的数据类型。如果指定了dtype,那么定义的数据类型是什么,数组元素的数据类型就是什么。

In [10]: print(np.arange(7,dtype=np.float64))
[0. 1. 2. 3. 4. 5. 6.]

In [11]: print(np.arange(7,dtype=np.complex64))
[0.+0.j 1.+0.j 2.+0.j 3.+0.j 4.+0.j 5.+0.j 6.+0.j]

数据类型的转换
数组的数据类型转换可以使用ndarray的astype方法显示地转换dtype。

In [12]: arr = np.array([1,2,3])#整型

In [13]: arr.dtype
Out[13]: dtype('int32')

In [14]: float_arr = arr.astype(np.float64)#整型转换为浮点型

In [15]: float_arr
Out[15]: array([1., 2., 3.])

In [16]: float_arr.dtype
Out[16]: dtype('float64')

用简洁的类型代码定义dtype

In [27]: print(np.arange(7,dtype='f'))
[0. 1. 2. 3. 4. 5. 6.]

In [28]: print(np.arange(7,dtype='D'))
[0.+0.j 1.+0.j 2.+0.j 3.+0.j 4.+0.j 5.+0.j 6.+0.j]

#查看代码表示的数据类型
In [29]: print(np.dtype('f'))
float32

In [30]: print(np.dtype('F'))
complex64

In [31]: print(np.dtype('d'))
float64

In [36]: print(np.dtype('U'))
<U0

In [37]: print(np.dtype('S'))
|S0

In [38]: print(np.dtype('?'))
bool

自定义数据类型
需求:假如需要有一个存储商店库存信息的数据类型,格式是有一个长度为40字节的字符串来记录商品的名称,32位的整数来记录商品的库存数量,32位的单精度浮点数来记录商品的价格。
可以这样定义数据类型

In [39]: t = np.dtype([('name',np.str_,40),('num',np.int32),('price',np.float32)])

In [40]: t
Out[40]: dtype([('name', '<U40'), ('num', '<i4'), ('price', '<f4')])

In [41]: data = [('Meaning of life DVD', 42, 3.14), ('Butter', 13, 2.72)]

In [42]: arr_data = np.array(data,dtype=t)

In [43]: arr_data
Out[43]:
array([('Meaning of life DVD', 42, 3.14), ('Butter', 13, 2.72)],
      dtype=[('name', '<U40'), ('num', '<i4'), ('price', '<f4')])

In [44]: arr_data[1]
Out[44]: ('Butter', 13, 2.72)

数组与标量之间的运算

数组不用编写循环就可以对数据进行批量运算。

In [45]: arr = np.array([[1., 2., 3.], [4., 5., 6.]])

In [46]: arr
Out[46]:
array([[1., 2., 3.],
       [4., 5., 6.]])

In [47]: arr * arr
Out[47]:
array([[ 1.,  4.,  9.],
       [16., 25., 36.]])

In [48]: arr - arr
Out[48]:
array([[0., 0., 0.],
       [0., 0., 0.]])

In [49]: arr + arr
Out[49]:
array([[ 2.,  4.,  6.],
       [ 8., 10., 12.]])

大小相同的数组之间进行算术运算都会作用到每个元素上

In [50]: arr = np.array([[1,2],[3,4]])

In [51]: arr
Out[51]:
array([[1, 2],
       [3, 4]])

In [52]: arr * 2
Out[52]:
array([[2, 4],
       [6, 8]])

In [53]: arr + 2
Out[53]:
array([[3, 4],
       [5, 6]])

In [54]: arr - 1
Out[54]:
array([[0, 1],
       [2, 3]])

注:除了数组和标量之间的运算以及相同大小数组之间的运算之外,不同大小的数组之间也可以进行运算,叫做广播。(关于广播后续再谈...)

数组的索引和切片

一维数组的索引和切片(与python的列表非常相似)

In [57]: a = np.arange(9)

In [58]: a
Out[58]: array([0, 1, 2, 3, 4, 5, 6, 7, 8])

In [59]: a[3]
Out[59]: 3

In [60]: a[3:5]
Out[60]: array([3, 4])

In [61]: a[:7:2]
Out[61]: array([0, 2, 4, 6])

In [62]: a[::-1]
Out[62]: array([8, 7, 6, 5, 4, 3, 2, 1, 0])

In [63]: a[3:7] = 666

In [64]: a
Out[64]: array([  0,   1,   2, 666, 666, 666, 666,   7,   8])

多维数组的索引和切片

In [14]: arr = np.arange(24).reshape(2,3,4)

In [15]: arr
Out[15]:
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 [16]: arr[0,0,0]
Out[16]: 0

#第一个维度不要,选取第一行第一列的元素
In [17]: arr[:,0,0]
Out[17]: array([ 0, 12])

#第一个维度的下标0代表的元素,后面的维度都不选取的话可以加省略号,也可以写arr[0,:,:]效果是一样的。
In [18]: arr[0, ...]
Out[18]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

#第一个维度的下标0代表的元素
In [19]: arr[0]
Out[19]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [20]: arr[0,1]
Out[20]: array([4, 5, 6, 7])

In [21]: arr[0,1,::2]
Out[21]: array([4, 6])

In [22]: arr[...,1]
Out[22]:
array([[ 1,  5,  9],
       [13, 17, 21]])

In [23]: arr[:,1]
Out[23]:
array([[ 4,  5,  6,  7],
       [16, 17, 18, 19]])

In [24]: arr[0,:,-1]
Out[24]: array([ 3,  7, 11])

In [25]: arr[0,::-1,-1]
Out[25]: array([11,  7,  3])

布尔型索引
布尔型索引指可以利用一个布尔型数组来对目标数组进行索引,找到布尔数组中值为True对应的目标数组的值。而需要注意的一点是布尔数组的长度必须和目标数组的轴长度一致。下面举例说明

一维数组的布尔型索引
创建一个布尔型数组和一个目标数组。

In [27]: bool_arr = np.array([True,False,False,True,False])

In [29]: dest_arr = np.arange(5)

In [30]: dest_arr
Out[30]: array([0, 1, 2, 3, 4])

In [31]: bool_arr
Out[31]: array([ True, False, False,  True, False])

#布尔型数组会匹配True中对应的目标数组的值
In [32]: dest_arr[bool_arr]
Out[32]: array([0, 3])

#可以对这些值进行算术操作,比如将匹配的数据都赋值为-5
In [35]: dest_arr[bool_arr] = -5

In [36]: dest_arr
Out[36]: array([-5,  1,  2, -5,  4])

多维数组的布尔型索引
数组的比较运是矢量化的,将names数组和字符串'Bob'比较会产生一个布尔型数组

In [2]: names = np.array(['Bob','Joe','will','Bob','Joe','Joe'])

In [3]: arr = np.arange(24).reshape((6,4))

In [4]: arr
Out[4]:
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 [5]: names
Out[5]: array(['Bob', 'Joe', 'will', 'Bob', 'Joe', 'Joe'], dtype='<U4')

#names数组和字符串的比较得到一个布尔型数组
In [6]: names == 'Bob'
Out[6]: array([ True, False, False,  True, False, False])

#将数组的逻辑运算作为索引,找到True对应的目标元素
In [7]: arr[names == 'Bob']
Out[7]:
array([[ 0,  1,  2,  3],
       [12, 13, 14, 15]])

#添加的索引操作
In [8]: arr[names == 'Bob',0]
Out[8]: array([ 0, 12])

#常规的切片操作
In [9]: arr[names == 'Bob',2:]
Out[9]:
array([[ 2,  3],
       [14, 15]])

#将目标数组中数字小于10的数据都设置为0
In [12]: arr[arr<10] = 0

In [13]: arr
Out[13]:
array([[ 0,  0,  0,  0],
       [ 0,  0,  0,  0],
       [ 0,  0, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23]])
       
#将Bob和Joe这两个人的数据都设置为100
In [15]: arr[(names == 'Bob')|(names == 'Joe')] = 100

In [16]: arr
Out[16]:
array([[100, 100, 100, 100],
       [100, 100, 100, 100],
       [  0,   0,  10,  11],
       [100, 100, 100, 100],
       [100, 100, 100, 100],
       [100, 100, 100, 100]])

布尔索引实现的是通过列向量中的每个元素的布尔量数值对一个与列向量有着同样行数的矩阵进行符合匹配。而这样的作用,其实是把列向量中布尔量为True的相应行向量给抽取了出来。如果进行变量或者标定量的大数据处理,这种筛选功能的使用肯定会给程序的设计带来极大的便捷。

花式索引
花式索引指的是利用整型数组进行索引,它是将索引数组的元素的值作为目标数组的下标,来获取目标数组下标对应的值。它是将数据复制到新的数组当中。

In [17]: arr = np.empty((8,4))

In [18]: for i in range(8):
    ...:     arr[i] = i
    ...:

In [19]: arr
Out[19]:
array([[0., 0., 0., 0.],
       [1., 1., 1., 1.],
       [2., 2., 2., 2.],
       [3., 3., 3., 3.],
       [4., 4., 4., 4.],
       [5., 5., 5., 5.],
       [6., 6., 6., 6.],
       [7., 7., 7., 7.]])
#这里的[4,3,0,6]就是索引数组,同时4,3,0,6是arr数组的下标值,
#取出的数据就是array[arr[4],arr[3],arr[0],arr[6]]
In [20]: arr[[4,3,0,6]]
Out[20]:
array([[4., 4., 4., 4.],
       [3., 3., 3., 3.],
       [0., 0., 0., 0.],
       [6., 6., 6., 6.]])

In [21]: arr[[-1,-2,-3]]
Out[21]:
array([[7., 7., 7., 7.],
       [6., 6., 6., 6.],
       [5., 5., 5., 5.]])

参考链接:


syushin
948 声望316 粉丝