数据分析常用的第三方库
numpy:数值计算
matplotlib:数据可视化
scipy:科学计算机
pandas:时间和日期序列
1 numpy的基本特点
1)矢量化运算;将包含多个数据的集合作为一个整体参与运算
2)成为几乎所有于数值分析、科学计算以及人工智能有关的功能模块的底层模块
3)性能卓越,运行速度快,绝大部分代码用标准C语言甚至有汇编语言编写
4)数据集合中的元素必须同质,牺牲灵活性换取高性能;注,列表元组里的元素可以不同,但C里面的数组元素必须同质
2 numpy数组
2.1 基本描述
numpy的数组是numpy.ndarray类型(n dimension array 意味n维数组)的对象,用于表示任意维度的数据结构,其维度信息通过shape属性访问
该对象由两部分组成
A)实际数据:数组元素本身(在内存里为一行连续的数据)
B)元数据:对实际数据类型、结构等信息的描述
比如
元素据可能是如下表示方式
base
A B
C
实际的MRO列表为:MRO = [C A B base Object]
有时会出现实际数据是一样的,但是元数据是不一样的。
注:大部分针对数组的操作实际上仅仅是针对其元数据的操作,以此提升性能。
numpy.arange(start, stop, step, dtype),获得一个数组形式序列,注:包含起始值,但不包含终止值
numpy.array(p_object, dtype, copy, order, subok, ndim):获得一个包含给定元素的数组对象,注:只要可迭代对象即可
p_object:Union[ndarray, lterable, int, float]
dtype:Optional[object] = None 元素类型
copy:Optional[bool] = True
order:Optional[str] = "K"
subok:Optional[object] = False
ndim:Optional[int] = 0
可简化为
numpy.array([元素1,元素2,...]):参数可以时同质的列表,元组,数组,注:元素之间的类型完全一致,但是元素内部可以由多个类型构成。
d = np.array([ [np.arange(1, 5), np.arange(5, 9), np.arange(9, 13)], [np.arange(13, 17), np.arange(17, 21), np.arange(21, 25)]])print(d.shape, d, sep='\n')
运行
(2, 3, 4)[[[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] [[13 14 15 16] [17 18 19 20] [21 22 23 24]]]
注意:
# # 一维数组 one_dim = np.arange(1,5) print(one_dim) # [1 2 3 4] 数据之间没有逗号,而数组的元素之间是用逗号隔开的 print(type(one_dim)) #类对象 print(one_dim.dtype) #int32元素的类型,这个数据类型在python中是没有定义的,是numpy库自己定义的 print(one_dim.shape) #(4,)表示4个元素 # 二维数组 two_dim = np.array([ [1,2,3,3], [4,5,6,6], [7,8,9,9]],dtype=float) #float64 [[1. 2. 3. 3.] print(two_dim) # print(type(two_dim)) # 类对象 print(two_dim.dtype) # int32元素的类型,这个数据类型在python中是没有定义的,是numpy库自己定义的 print(two_dim.shape) # (3,4)表示3行4列 two1_dim = np.array([ [1], [4], [7]]) print(two1_dim) # print(two1_dim.shape) # (3,1)表示3行1列
# 三维数组 three_dim = np.array([ [ np.arange(1,5), np.arange(5,9), np.arange(9,13) ], [ np.arange(13,17), np.arange(17,21), np.arange(21,25), ], [ np.arange(14, 18), np.arange(18, 22), np.arange(22, 26), ]]) print(three_dim) # print(type(three_dim)) #类对象 print(three_dim.dtype) # int32元素的类型,这个数据类型在python中是没有定义的,是numpy库自己定义的 print(three_dim.shape) # (3, 3, 4),3页,3行,4列 print(three_dim[1,0,0])
2.2 数组下标
numpy中的数组也可以采用下标访问,其下标也是从0开始
import numpy as npa = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])print(a)print('a[0]:',a[0],sep='\n') print('a[0][0]:', a[0][0]) # a[0][0]: [1 2]print('a[0][0][0]:', a[0][0][0]) #a[0][0][0]: 1
运行
[[[1 2] [3 4]] [[5 6] [7 8]]] a[0]:[[1 2] [3 4]] a[0][0]: [1 2] a[0][0][0]: 1
深刻理解shape属性
import numpy as npa = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])print(a.shape) #a.shape 结果为(2,2,2)的元组for i in range(a.shape[0]): #获得a.shape[0]元组中的第1个元素 2 for j in range(a.shape[1]): #获得a.shape[1]元组中的第2个元素 2 for k in range(a.shape[2]): #获得a.shape[2]元组中的第3个元素 2 print(a[i][j][k], a[i, j, k]) #说明a[i][j][k]与a[i, j, k]等价,取出列表中的每一个元素
通过len 或 numpy.ndarray.size获取元素个数;
对于一维数组,size和len是相等的,
对于高维数组,len返回的是第一维的维数,而size返回的是所有维数的乘积。
import numpy as npa = np.array([ [ [1, 2], [3, 4] ], [ [5, 6], [7, 8] ]])print("a.shape:",a.shape) #(2, 2, 2)print('a.size:',a.size) #8print('a.ndim:',a.ndim) #3print("len(a):",len(a)) #2b = np.array([[ [ [1, 2], [3, 4] ], [ [5, 6], [7, 8] ], [ [9, 10], [11, 12] ]]])print("b.shape:",b.shape) #(1, 3, 2, 2)print('b.size:',b.size) #12 元素个数,b.shape元组中所有元素的乘积print('b.ndim:',b.ndim) #4 维度,相当于b.shape元组的长度,len(b.shape)print("len(b):",len(b)) #1 只算页数,相当于b.shape[0]
注:为了便于观察,将a b的视图写法略作调整
2.3 维度的改变
数组的维度可以在定义后再做适当调整,reshape 和 shape 。
第一种方法 reshape方法
reshape(新维度): 不改变数据,注意,reshape()只接受一个参数,当多个参数时可以选用
import numpy as npa = np.arange(1,9)b = a.reshape((2,4))print('a',a.shape,a,sep='\n') #(8,) [1 2 3 4 5 6 7 8]print('b',b.shape,b,sep='\n') #(2, 4) [[1 2 3 4] # [5 6 7 8]]
具体可以查看print(help(a.reshape)
第二种方法 shape属性
shape = 新维度:这种方法直接修改了所操作
import numpy as npa = np.arange(1, 9)a.shape = (2, 4) # 修改原数组本身print('a', a.shape, a, sep='\n') #(2, 4) [[1 2 3 4] # [5 6 7 8]]
2.4 数据类型
ndarray对象的dtype属性反映了元素的数据类型,可以通过该属性读取或修改数组元素的数据类型
Object(array).astype(新数据类型) -> 新数组对象
a = np.array([1,2,3,4,5])print(a.dtype) #int32
当赋值时不添加数据类型时,numpy会自动匹配默认值
也可以指定数据类型
a = np.array([1,2,3,4,5],dtype=np.int8)print(a.dtype) #int8
也可以通过astype对列表的数据类型进行修改
import numpy as npa = np.array([1,2,3,4,5],dtype=np.int8)b = a.astype(float)print(b.dtype) # float64c = a.astype(str)print(c.dtype,c) #
dtype表达方式的多样性
import numpy as npa = np.array([1,2,3,4],dtype=np.int32)b = np.array([1,2,3,4],"int32")c = np.array([1,2,3,4],"i4")print(a.shape,b.shape,c.shape) # (4,) (4,) (4,) 以上三个是等价的
注释:dtype=np.int32 与 ‘int32’ 表达结果相同。“int32” 与 ‘i4’ 相同,参看数据类型
2.5 数据类型
2.5.1 变长类型,长度
a = np.array(['a1b1c1'], dtype=(np.str_, 1))print(a.dtype, a, a[0]) #
实例二
a = np.array([ 'hello, word !', 'hello, python !'], dtype=(np.str_, 14)) #i4 dtype表示每一个最小单元的数据类型
运行
['hello, word !' 'hello, python ']
2.5.2 定长类型,(维度)
a = np.array([(1, 2, 3, 4)], dtype=(np.int32, 4)) # 每个元素类型是4个int32,若维度不一致则会报错print(a.dtype, a.shape) #int32 (1, 4)
说明:t = numpy.dtype((int,5))每个元素都是由5个int组成的一维数组,将5个int当成一个整体,实际上是二维数组
2.5.3 类型字符串1,类型字符串2,. . .
a = np.array([('1234',(1,2,3,4))],dtype='u4,4i4')print(a) #[(1234, [1, 2, 3, 4])]print(a.dtype) # [('f0', '
当元素中由三个数据构成
a = np.array([('1234','abcd',(1,2,3,4))],dtype='u4,U4,4i4')print(a) # [(1234, 'abcd', [1, 2, 3, 4])]print(a.dtype) # [('f0', '
T:(逗号分隔的多个类型字符串)
t = numpy.dtype('U14,i4')此表示由U14和i4组成的元素,数组中的每个元素都是这个“组合类型”
T :[(子段名称,类型,维度),(子段描述),()...]
t = numpy.dtype([('name',numpy.str_,14),('age',numpy.int32)])此等价于'U14,i4'
2.5.4 元素中数据名修改
a = np.array([('1234', (1, 2, 3, 4)), ('5678', (5, 6, 7, 8))], dtype={ 'names': ['fa', 'fb'], 'formats': ['U4', '4i4']})print(a.shape) #(2,)print(a.dtype) #[('fa', '
2.5.5 [(字段名称,字段类型,字段维度),...]
元素内部的数据构成
a = np.array([('1234', (1, 2, 3, 4))], dtype=[('fa', np.str_, 4), ('fb', np.int32, 4)])print(a.dtype) #[('fa', '
与下段代码等价
b = np.array([('1234', (1, 2, 3, 4))], dtype=[('fa', 'U4'), ('fb', '4i4')])print(b.dtype) #[('fa', '
2.5.6 (基本类型,解释类型)
实例一
a = np.array([0x1234], dtype=('>u2', { 'names': ['lo', 'hi'], 'formats': ['u1', 'u1']}))print('{:x} {:x} {:x}'.format(a[0], a['lo'][0], a['hi'][0])) #1234 12 34
实例二
m = np.array(['python'], dtype=('U6', { 'names': ['codes'], 'formats': ['6u4']}))print(m) #['python']print(m[0]) #pythonprint(m['codes'][0]) #[112 121 116 104 111 110]
a = np.array([('abc', 123), ('def', 456)], dtype='U14,i4')print(a) #[('abc', 123) ('def', 456)]print(a.dtype) #[('f0', '
3 展平
将任意维度转成一维
3.1 a.ravel()
将a数组转变为一维视图(仅是转换了视图输出形式,其a数据的内部存储形式不变)
a = np.array([ [1, 2, 3], [4, 5, 6]])b = a.ravel() print(b) #[1 2 3 4 5 6]print(a)#[[1 2 3] #[4 5 6]]a *= 10print(a) #[[10 20 30] #[40 50 60]] print(b) #[10 20 30 40 50 60]
3.2 flatten()
将a数组转变为一维副本(将a数组复制一份并以一维数组的方式保存到内存中)
a = np.array([ [1, 2, 3], [4, 5, 6]])b = a.flatten() # c是a的一维副本print(b) #[1 2 3 4 5 6]print(a) #[[1 2 3] #[4 5 6]]a *= 10print(a) #[[10 20 30] #[40 50 60]]print(b) #[1 2 3 4 5 6]
4 转置
转置视图实现方式:
Array.transpose() :视图转置方法
Array.T:视图转置属性
无论哪种装置形式,仅改变视图形式,其内部不改变
a = np.arange(1, 9).reshape(2, 4)print(a)# [[1 2 3 4]# [5 6 7 8]]b = a.transpose()print(b)# [[1 5]# [2 6]# [3 7]# [4 8]]c = a.reshape(4, 2)print(c)# [[1 2]# [3 4]# [5 6]# [7 8]]d = a.Tprint(d)# [[1 5]# [2 6]# [3 7]# [4 8]]a *= 10print(a, b, c, d, sep='\n') # 都是视图 略
注:至少是二维数组才支持转置,一维数据不支持转置,严格来讲,一维数据不存在行,只有列
将一列装置为行有两种方法,如下代码所示
a = np.arange(1,5)print(a) #[1 2 3 4]b = np.array([a]).transpose() #将其构造成二维再进行转置print(b)# [[1]# [2]# [3]# [4]]c = a.reshape(-1,1) #这里-1行表示任意行,1,表示一列,print(c)# [[1]# [2]# [3]# [4]]
5 自定义数据类型
自定义的时候,可以先用numpy.dtype(T)创建类型
a = numpy.array([...],dtype = T) t = numpy.dtype(T)a = numpy.array([...],dtype = t)
实例一
# python 或numpy的内置类型t = numpy.dtype(int)t = numpy.dtype(numpy.int32)
python的数据类型会将其转化为numpy数据类型
实例二
# 实例二 类型字符串t = numpy.dtype('int')t = numpy.dtype('int32')
5.1 类型字符编码
t = numpy.dtype('>(2,3)4i4')
这个表示为:
> 大端字节序
(2,3) 维度,2行3列
4:分量数,也就是说2行3列数组中又存在一个一维数组,每个数组中又4个元素,这4个元素中每个元素为4字节整型i,i4相当于int32
i 分量类型 ,每个分量是一个整型,
4 分量字节数,每个整型占据4个字节,每个类型的字长
实例一:
b = np.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), (29,30,31,32), (33,34,35,36)), ((37,38,39,40), (41,42,43,44), (45,46,47,48))) ],dtype = '>(2,3)4i4') # dtype = '>(2,3,4)i4'与dtype = '>(2,3)4i4'等价 print(b) print(b.dtype) #>i4 dtype表示每一个最小单元的数据类型
运行
[[[[ 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]]]]>i4
6 改变维度的4种方式
1)视图变维、2)复制变维、3)就地变维、4)视图转置
6.1 视图变维
import numpya = numpy.arange(1,7)b = a.reshape(2,3) #[[1 2 3] # [4 5 6]]# 可以变回来c = b.reshape(6) #[1,2,3,4,5,6]d = b.ravel() #扁平化 [1,2,3,4,5,6]
6.2 复制变维
e = b.flatten() #扁平化数据,e复制了b数据,e 独立于b存在
6.3 就地变维
a.shape = (2,3) #把已有的数组更变为新的数组类型
shape为a的属性,此时a的数据结构形式就发生了变化
数据是共享的,元数据是独立的,元数据包含了数据,还包括有对数据的描述(数据结构)
元数据,可以简单理解为描述为语言
a.resize((3,2))#就地变维,形参只有一个,(2,3)是以元组形式传参的,
6.4 视图转置
略
7 组合与拆分
垂直组合:vstack((上,下)) 垂直分割:vsplit(数组,分割数)->子数组元组 水平组合:hstack((左,右)) 水平分割:hsplit(数组,分割数)->子数组元组 深度组合:dstack((前,后)) 深度分割:dsplit(数组,分割数)->子数组元组 行组合:row_stack((上,下)) 列组合:column_stack((左,右))
7.1 垂直、水平、深度组合方式
垂直:v = numpy.vstack((u,d))
水平:h = numpy.hstack((l,r))
深度:d = numpy.dstack((a,b)) 可以理解为沿垂直纸面的组合方式
import numpy as npa = np.arange(1,10).reshape(3,3)b = a * 10print(a, b, sep='\n')# a# [[1 2 3]# [4 5 6]# [7 8 9]]# b# [[10 20 30]# [40 50 60]# [70 80 90]]c = np.vstack((a,b))print(c)# [[ 1 2 3]# [ 4 5 6]# [ 7 8 9]# [10 20 30]# [40 50 60]# [70 80 90]]d = np.hstack((a,b))print(d)# [[ 1 2 3 10 20 30]# [ 4 5 6 40 50 60]# [ 7 8 9 70 80 90]]e = np.dstack((a,b))print(e)# [[[ 1 10]# [ 2 20]# [ 3 30]]# # [[ 4 40]# [ 5 50]# [ 6 60]]# # [[ 7 70]# [ 8 80]# [ 9 90]]]
7.2 行组合、列组合
行组合:r = np.row_stack((u,d))
列组合:c = np.column_stack((l,r))
行、列组合一般针对一维数组,
对于二维及二维以上数组,行组合和垂直组合效果一样,列组合和水平组合效果一样
# 行组合r = np.row_stack((u,d))# u [1 2 3]# d [4 5 6]# r [# [1 2 3]# [4 5 6]# ]# 列组合c = np.column_stack((l,r))# l [1 2 3]# r [4 5 6]# c [# [1 4]# [2 5]# [3 6]# ]
7.3 垂直分割、水平分割、深度分割
1)垂直分割
u,d = numpy.vsplit(v,2)
u,m,d = numpy.vsplit(v,3)#分割的份数
2)水平分割
垂直分割、水平分割和垂直合并、水平合并是可逆的
l,m,r = numpy.hsplit(h,3)
3)深度分割
q,r = np.dsplit(e,2)
print(q,r,sep='\n')备注:深度分割和深度合并是不可逆操作;
可以通过下段代码将其还原
q = q.transpose()[0].transpose()
r = r.transpose()[0].transpose()print(q,r,sep='\n')学习代码
import numpy as npa = np.arange(11, 20).reshape(3, 3)print('a')print(a)b = np.arange(21, 30).reshape(3, 3)print(b)c = np.arange(31, 40).reshape(3, 3)print(c)d = np.vstack((a, b, c))print('d')print(d)# concatenate()方法可以选择方向进行合并e = np.concatenate((a, b, c), axis=0) # 沿(行轴)合并print('e')print(e)f, g, h = np.vsplit(e, 3)print('f,g,h')print(f, g, h, sep='\n')i = np.hstack((a, b, c)) # 水平组合print('i')print(i)j = np.concatenate((a, b, c), axis=1)print('j')print(j)k, l, m = np.hsplit(j, 3)print('k')print(k)print('l')print(l)print('m')print(m)n = np.dstack((a, b))print('n')print(n)o, p = np.dsplit(n, 2)print('o')print(o)print('p')print(p)print('o.T[0].T, p.T[0].T')print(o.T)print(o.T[0].T, p.T[0].T, sep='\n')q = np.arange(1, 4)r = np.arange(4, 7)s = np.arange(7, 10)print('q, r, s')print(q, r, s, sep='\n')t = np.row_stack((q, r, s))#t = np.vstack((q, r, s))print('t')print(t)u = np.column_stack((q, r, s))#u = np.hstack((q, r, s))print('u')print(u)
8 复数
import numpy as npa = np.array([ [1 + 1j, 2 + 4j, 3 + 7j], [11 + 11j, 12 + 14j, 13 + 17j], [21 + 21j, 22 + 24j, 23 + 27j],])print(a.dtype) # complex128print(a.dtype.char) # Dprint(a.dtype.str) #
9 numpy.ndarray 类的属性
1)dtype 元素类型
2)shape 维度 几行几列3)ndim 数组维数,也可以理解为最外层的维度4)size 元素个数,元素数len,如果一维size与len是相等的,当二维及以上时,则size仅表示列数,size行列式乘积a [1 2 3]len(a) -> 3a.sise -> 3b [ [1 2 3], [4 5 6]]len(b) ->2b.size ->6
5)itemsize 每个元素的字节数
6)nbytes 数组的总字节数 = size * itemsize
7)T 转置视图
8)real 复数数组的实部视图9)image 复数数组的虚部视图10)flat 扁平迭代器
flat属性将返回一个numpy.flatiter对象。扁平迭代器可以让我们像遍历一维数组一样去遍历任意的多维数组。(迭代器的计算是惰性的,节约内存)11)tolist 转化为python列表 ,转换之后可以明显看到其是用逗号分隔的numpy.ndarray.tolist()-> 列表对象import numpy as npa = np.array( [ (1 + 1j, 2 + 2j, 3 + 7j), (1 + 1j, 2 + 2j, 3 + 7j), (1 + 1j, 2 + 2j, 3 + 7j) ])print(a)# [[1.+1.j 2.+2.j 3.+7.j]# [1.+1.j 2.+2.j 3.+7.j]# [1.+1.j 2.+2.j 3.+7.j]]print(type(a))#print(type(a[0]))# print(type(a[0][0]))# print(a.dtype)# complex128print(a.dtype.type)# print(a.dtype.str) # for item in a.flat: print(item)# (1+1j)# (2+2j)# (3+7j)# (1+1j)# (2+2j)# (3+7j)# (1+1j)# (2+2j)# (3+7j)print('*'*6)# ******print(a.flat[4]) #(2+2j)print(a.flat[[1,3,5]])# [2.+2.j 1.+1.j 3.+7.j]a.flat[[2,4,6]] = 0 # 赋值print(a)# [[1.+1.j 2.+2.j 0.+0.j]# [1.+1.j 0.+0.j 3.+7.j]# [0.+0.j 2.+2.j 3.+7.j]]b = a.tolist()print(b)# [[(1+1j), (2+2j), 0j], [(1+1j), 0j, (3+7j)], [0j, (2+2j), (3+7j)]]
print('flat')for elem in a.flat: # 性能最优 print(elem)print('ravel')for elem in a.ravel(): # 性能居中 print(elem)print('flatten')for elem in a.flatten(): # 性能最差 print(elem)
类似的代码
import numpy as npa = np.array([ [1 + 1j, 2 + 4j, 3 + 7j], [4 + 2j, 5 + 5j, 6 + 8j], [7 + 3j, 8 + 6j, 9 + 9j]])print('a.dtype')print(a.dtype)print('a.dtype.char')print(a.dtype.char)print('a.dtype.str')print(a.dtype.str)print('a.dtype.name')print(a.dtype.name)print('a.shape')print(a.shape)print('a.ndim')print(a.ndim)print('a.size')print(a.size)print('a.itemsize')print(a.itemsize)print('a.nbytes')print(a.nbytes)print('a.real')print(a.real)print('a.imag')print(a.imag)print('a.T')print(a.T)print('flat')for elem in a.flat: # 性能最优 print(elem)print('ravel')for elem in a.ravel(): # 性能居中 print(elem)print('flatten')for elem in a.flatten(): # 性能最差 print(elem)b = a.tolist()print('b')print(b)c = np.array(b)print('c')print(c)d = []for i in range(10): d.append(i)print('d')print(d)e = np.array([], dtype=int)for i in range(10): e = np.append(e, i)print('e')print(e)
a.append(i) a = np.append(a,i) 链表是指针形式,在内存中的空间可以不连续,通过指针形式进行联系 数组,必须是一个整块的空间,数组中的元素需要的是连续内存,如果内存不足,则会开辟或寻找一个新的空间,将原内容拷贝到新的空间,