0 引言
大数据时代,一切决策的依据都是数据,数据处理和数据分析的重要性毋庸置疑。
本博客不会深入到numpy,pandas的matplotlib的源码,主要介绍常用的API和使用场景,主要参考资料来自官网。
NumPy中文官网: NumPy中文官网.
Pandas中文官网:Pandas中文官网.
Matplotlib中文官网:Matplotlib中文官网.
学习任何技术最好的资源就是官方网站,当然如果英文好的朋友,英文网站的效果最佳,中文翻译后难免会有歧义。
#
import numpy as np
import pandas as pd
import matplotlib as plt
np.__version__
# '1.20.3'
pd.__version__
# '1.2.4'
plt.__version__
# '3.4.2'
1 NumPy
NumPy是使用Python进行科学计算的基础软件包。除其他外,它包括:
- 功能强大的N维数组对象。
- 精密广播功能函数。
- 集成 C/C+和Fortran 代码的工具。
- 强大的线性代数、傅立叶变换和随机数功能。
1.1 创建数组
# 1 np.empty(shape,[dtype]) 返回指定shape的数组,元素是根据内存随机的
n1 = np.empty((2,3),dtype='int32')
n1
# array([[ 0, 0, 0],
# [1071644672, 0, 1072693248]])
# 2 np.empty_like(ndarray,[dtype]) 返回与ndarray数组相同shape的数组,元素也是随机的
n2 = np.empty_like(n1)
n2
# array([[ 0, 1072693248, 0],
# [1072693248, 0, 1072693248]])
# 3 np.eye(N) 返回一个对角线为1,其他位置都有0的二维数组
np.eye(4)
# array([[1., 0., 0., 0.],
# [0., 1., 0., 0.],
# [0., 0., 1., 0.],
# [0., 0., 0., 1.]])
# 4 np.identity(N) 返回一个标识数组,效果与eye相同
# 5 np.ones(shape, [dtype]) # 返回指定形状的指定类型的数组,并填充为1
n1 = np.ones((3,4),dtype='int32')
n1
#array([[1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1]])
# 6 np.ones_like(a, [dtype]) # 返回与a数组相同形状的数组,并且填充为1
n2 = np.ones_like(n1,dtype='float')
n2
#array([[1., 1., 1., 1.],
# [1., 1., 1., 1.],
# [1., 1., 1., 1.]])
# 7 np.zeros() np.zeros_like()与np.ones() np.ones_like() 相同
# 8 np.full(shape, full_value) 填充full value中的数据到shape中并返回
n1 = np.full((2,3), 5)
n1
#array([[5, 5, 5],
# [5, 5, 5]])
# 9 np.full_like(a, full_value) 填充full value到与a相同形状的数组中并返回
n2 = np.full_like(n1,7)
n2
# array([[7, 7, 7],
# [7, 7, 7]])
# 10 reshape 改变数组的形状 shape以元组的形式传参数
## 方式一: b = np.reshape(a,newshape)
a = np.arange(12)
b = np.reshape(a,(3,4))
b
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
## 方式二:a.reshape(shape)
a.reshape((3,4))
a
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
# 11 np.ravel(a) 返回一个连续的一维数组
a = np.arange(12).reshape((3,4))
np.ravel(a)
# array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
# 12 ndarray.flat # 返回一个迭代器
type(a.flat)
# numpy.flatiter
# 13 np.moveaxis(a,src,des) 将数组a的src轴移动到des轴,二维数组只有0轴和1轴,三维数组有0,1,2三根轴,以此类推
a = np.arange(12).reshape((3,4))
np.moveaxis(a,0,1) 或者 np.moveaxis(a,1,0)
#array([[ 0, 4, 8],
# [ 1, 5, 9],
# [ 2, 6, 10],
# [ 3, 7, 11]])
# 从输出结果可以看到,二维数组的横轴与纵轴交换了位置
# 14 np.swapaxes(a,axes1,axes2) 交换数组的两个轴
np.swapaxes(a,0,1) # 返回值与moveaxis() api相同
1.1+ 创建数组random
# +1 np.random.rand(d0,d1,...) 返回标准的随机分布[0,1)
np.random.rand(3,4)
#array([[0.45825097, 0.40145903, 0.73421355, 0.73296766],
# [0.63460903, 0.97759794, 0.7060251 , 0.10444119],
# [0.75560894, 0.96608834, 0.35512846, 0.99682704]])
# +2 np.random.randn(d0,d1,...) 返回标准的正态分布,均值为0,方差为1
np.random.randn(3,4)
# array([[ 0.95871938, -2.85997519, -0.84536782, -0.30606499],
# [ 0.04930978, 0.21062939, 0.66238318, 0.20502361],
# [-2.4039988 , -1.81935625, 0.52349081, -2.37276337]])
# +3 np.random.randint(low[, high, size]) 返回[low, high)区间内size大小的整数
np.random.randint(1,10,(3,4))
#array([[2, 3, 5, 7],
# [9, 1, 4, 8],
# [4, 4, 7, 5]])
# +4 np.random.sample([size]) 返回[0,1.0)区间内的浮点数
# np.random.random([size])/ ranf([size]) / sample([size]) 这四个api相同
np.random.sample((3,4))
#array([[0.84235095, 0.07688947, 0.90903085, 0.58440727],
# [0.09175167, 0.41449593, 0.67110254, 0.31718442],
# [0.52603519, 0.56556646, 0.84109242, 0.89343526]])
# +5 np.random.choice(a[, size, replace, p]) 随机选择数据
# replace 是否原地替换
# p 与a相同元素个数的一维数组
a = np.array(['kobe','wade','james','paul'])
np.random.choice(a,3)
# array(['paul', 'paul', 'james'], dtype='<U5')
# +6 np.random.bytes(length)返回随机长度的字节
np.random.bytes(10)
# b'\xd0\xad"t$\x93Qg\xfc\x03'
# +7 np.random.seed()获取随机种子
np.random.seed(2)
np.random.rand(3,4)
# array([[0.4359949 , 0.02592623, 0.54966248, 0.43532239],
# [0.4203678 , 0.33033482, 0.20464863, 0.61927097],
# [0.29965467, 0.26682728, 0.62113383, 0.52914209]])
np.random.seed(2)
np.random.rand(3,4)
# array([[0.4359949 , 0.02592623, 0.54966248, 0.43532239],
# [0.4203678 , 0.33033482, 0.20464863, 0.61927097],
# [0.29965467, 0.26682728, 0.62113383, 0.52914209]])
# +8 np.random.suffle(x) 原地打乱数组x的次序
a = np.arange(12).reshape((3,4))
np.random.shuffle(a)
a
#array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
# +9 np.random.permutation(x) 打乱x次序后返回一个新的数组
a = np.arange(12).reshape((3,4))
b = np.random.permutation(a)
a,b # a不变,打乱次序后返回给b
#(array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]]),
# array([[ 8, 9, 10, 11],
# [ 4, 5, 6, 7],
# [ 0, 1, 2, 3]]))
1.2 组合数组
# 15 np.concatenate((a1,a2...)) 沿现有轴连接数组
a = np.arange(12).reshape((3,4))
b = np.arange(12,24).reshape((3,4))
np.concatenate((a,b))
#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]])
# 16 np.vstack((a1,a2..)) 垂直合并数组,vertical 垂直
a = np.arange(12).reshape((3,4))
b = np.arange(12,24).reshape((3,4))
np.vstack((a,b))
#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]])
# 17 np.hstack((a1,a2...)) 水平合并数组, horizantal 水平
a = np.arange(12).reshape((3,4))
b = np.arange(12,24).reshape((3,4))
np.hstack((a,b))
#array([[ 0, 1, 2, 3, 12, 13, 14, 15],
# [ 4, 5, 6, 7, 16, 17, 18, 19],
# [ 8, 9, 10, 11, 20, 21, 22, 23]])
# 18 np.column_stack((a,b)) 将一维数组当成一列整合到二维数组中,一维数组的元素个数与二维数组的行数要匹配
a = np.arange(12).reshape((3,4))
c = np.array([77,88,99])
np.column_stack((c,a))
#array([[77, 0, 1, 2, 3],
# [88, 4, 5, 6, 7],
# [99, 8, 9, 10, 11]])
np.column_stack((a,c))
#array([[ 0, 1, 2, 3, 77],
# [ 4, 5, 6, 7, 88],
# [ 8, 9, 10, 11, 99]])
1.3 拆分数组
# 19 np.split(a, indices_or_sections)
"""
If indices_or_sections is an integer, N, the array will be divided into N equal arrays along axis. If such a split is not possible, an error is raised.
If indices_or_sections is a 1-D array of sorted integers, the entries indicate where along axis the array is split. For example, [2, 3] would, for axis=0, result in
ary[:2]
ary[2:3]
ary[3:]
If an index exceeds the dimension of the array along axis, an empty sub-array is returned correspondingly.
"""
# 20 np.vsplit(a) 垂直分割
a = np.arange(12).reshape((4,6))
np.hsplit(a,[1,3]) # 水平方向分割 0~1 1~3 3:
#[array([[ 0],
# [ 6],
# [12],
# [18]]),
# array([[ 1, 2],
# [ 7, 8],
# [13, 14],
# [19, 20]]),
# array([[ 3, 4, 5],
# [ 9, 10, 11],
# [15, 16, 17],
# [21, 22, 23]])]
# 21 np.hsplit(a) 水平分割
a = np.arange(12).reshape((3,4))
np.hsplit(a,2)
#[array([[0, 1],
# [4, 5],
# [8, 9]]),
# array([[ 2, 3],
# [ 6, 7],
# [10, 11]])]
1.4 添加&删除元素
# 22 np.delete(arr, obj, axis=None) arr表示数组,obj可以是数字,列表,范围,axis表示轴,如果是None表示一个平铺的一维数组
a = np.arange(24).reshape((4,6))
np.delete(a,0,axis=0) # 删除数组a的第1行并返回
#array([[ 6, 7, 8, 9, 10, 11],
# [12, 13, 14, 15, 16, 17],
# [18, 19, 20, 21, 22, 23]])
np.delete(a,[0,2],axis=0) # 删除数组a的第1行和第3行并返回
#array([[ 6, 7, 8, 9, 10, 11],
# [12, 13, 14, 15, 16, 17]])
np.delete(a,[1,3,5],axis=None) # 删除1,3,5 元素
#array([ 0, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
# 20, 21, 22, 23])
np.delete(a,np.s_([::2]),axis=1) # 删除偶数列
#array([[ 1, 3, 5],
# [ 7, 9, 11],
# [13, 15, 17],
# [19, 21, 23]])
# 23 np.insert(arr,obj,values,[axis]) axis默认为None,为None将arr打散成一维数组,将values插入到obj索引前,如果不为None,则按照axis的数值插入一行或者一列
a = np.arange(12).reshape((3,4))
np.insert(a,0,[66,77,88,99],None)
#array([66, 77, 88, 99, 1, 1, 1, 2, 2, 2, 3, 3, 3])
np.insert(a,0,[66,77,88,99],0)
#array([[66, 77, 88, 99],
# [ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
np.insert(a,0,[66,77,88],1)
#array([[66, 0, 1, 2, 3],
# [77, 4, 5, 6, 7],
# [88, 8, 9, 10, 11]])
# 24 np.unique(arr) 查找数组的唯一元素
a = np.array([[[1,1,1],[2,2,2],[3,3,3]]])
np.unique(a)
# array([1, 2, 3])
1.5 重排元素
# 25 np.flip(arr,[axis]) 沿指定轴颠倒数组中元素的位置
a=np.arange(12).reshape((3,4))
np.flip(a,axis=None) # 元素合成一维数组后重排
#array([[11, 10, 9, 8],
# [ 7, 6, 5, 4],
# [ 3, 2, 1, 0]])
np.flip(a,axis=0) # 元素所有行重排
#array([[ 8, 9, 10, 11],
# [ 4, 5, 6, 7],
# [ 0, 1, 2, 3]])
np.flip(a,axis=1) # 元素所有列重排
#array([[ 3, 2, 1, 0],
# [ 7, 6, 5, 4],
# [11, 10, 9, 8]])
# 26 np.fliplr(arr) # 左右翻转数组
a=np.arange(12).reshape((3,4))
np.fliplr(a)
#array([[ 3, 2, 1, 0],
# [ 7, 6, 5, 4],
# [11, 10, 9, 8]])
# 27 np.flipud(arr) # 上下翻转数组
a=np.arange(12).reshape((3,4))
np.flipud(a)
#array([[ 8, 9, 10, 11],
# [ 4, 5, 6, 7],
# [ 0, 1, 2, 3]])
# 28 np.roll(arr,shift,[axis]) 沿指定轴滚动元素
# arr:需要滚动数据的数组
# shift :整数,可以正也可以负数
# axis : None 0 1 ... None表示将多维数组转换成一维数组
a=np.arange(12).reshape((3,4))
np.roll(a,1,None)
#array([[11, 0, 1, 2],
# [ 3, 4, 5, 6],
# [ 7, 8, 9, 10]])
np.roll(a,1,0)
#array([[ 8, 9, 10, 11],
# [ 0, 1, 2, 3],
# [ 4, 5, 6, 7]])
np.roll(a,1,1)
#array([[ 3, 0, 1, 2],
# [ 7, 4, 5, 6],
# [11, 8, 9, 10]])
# 29 np.rot90(arr) 在轴指定的平面中将阵列旋转90度
a=np.arange(12).reshape((3,4))
#array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
np.rot90(a)
#array([[ 3, 7, 11],
# [ 2, 6, 10],
# [ 1, 5, 9],
# [ 0, 4, 8]])
1.6 索引取值
# 30 一维数组切片
a = np.arange(10)
方式一: slice(start,stop,step)
s = slice(0,-1,2)
a[s]
# array([0, 2, 4, 6, 8])
方式二:a[start:stop:step]
a[0:-1:2]
# array([0, 2, 4, 6, 8])
==:表示的数据范围含首不含尾 [start,stop)==
# 31 二维数组切片
a = np.arange(12).reshape((3,4))
a[1:] # 取第二行以后的所有值
#array([[ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
a[...,1:] # 取所有行的第二列以后的所有值
#array([[ 1, 2, 3],
# [ 5, 6, 7],
# [ 9, 10, 11]])
a[2,3] # 获取第三行第四列的值
# 11
a[[0,2],...] # 获取第一行和第三行
#array([[ 0, 1, 2, 3],
# [ 8, 9, 10, 11]])
a[[0,2],0] # 获取第一行和第三行的第一列
# array([0, 8])
# 32 条件索引
# ~ 条件非 & 条件与 | 条件或
a = np.arange(12)
a[a>5]
# array([ 6, 7, 8, 9, 10, 11])
a[(a>5)&(a<9)]
# array([6, 7, 8])
a[1] = np.nan
a[~np.isnan(a)]
# array([ 0., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.])
1.7 时间日期
numpy中使用datetime64存储时间日期数据类型
Y-年;M-月;W-周;D-天;h-时;m-分;s-秒;ms-毫秒;us-微秒;ns-纳秒;ps-皮秒;fs-飞秒;as-阿托秒
# 33 生成一个时间序列
np.arange('2020-03-01','2020-03-31',dtype='datetime64')
#array(['2020-03-01', '2020-03-02', '2020-03-03', '2020-03-04',
# '2020-03-05', '2020-03-06', '2020-03-07', '2020-03-08',
# '2020-03-09', '2020-03-10', '2020-03-11', '2020-03-12',
# '2020-03-13', '2020-03-14', '2020-03-15', '2020-03-16',
# '2020-03-17', '2020-03-18', '2020-03-19', '2020-03-20',
# '2020-03-21', '2020-03-22', '2020-03-23', '2020-03-24',
# '2020-03-25', '2020-03-26', '2020-03-27', '2020-03-28',
# '2020-03-29', '2020-03-30'], dtype='datetime64[D]')
# 34 从字符串转换成时间序列后,如果字符串格式不统一,则按照最小的单位
np.array(['2021-03','2021-03-01','2021-03-02 20:00'],dtype='datetime64')
#array(['2021-03-01T00:00', '2021-03-01T00:00', '2021-03-02T20:00'],
# dtype='datetime64[m]')
# 35 时间运算
#方式一:
np.datetime64('2021-07-01','D')-np.datetime64('2021-06-01','D')
# numpy.timedelta64(30,'D')
np.datetime64('2021-07-01','M')-np.datetime64('2021-06-01','M')
# numpy.timedelta64(1,'M')
np.datetime64('2021-07-01','m')-np.datetime64('2021-06-01','m')
numpy.timedelta64(43200,'m')
#方式二:
np.datetime64('2021-07-01','m')+np.timedelta64(10,'D')
# numpy.datetime64('2021-07-11T00:00')
np.datetime64('2021-07-01','m')-np.timedelta64(100,'m')
# numpy.datetime64('2021-06-30T22:20')
# 36 np.datetime64与datetime.datetime之间相互转换
from datetime import datetime
dt = datetime(year=2021,month=7,day=4,hour=20,minute=10,second=30)
np.datetime64(dt)
# numpy.datetime64('2021-07-04T20:10:30.000000')
dt64.astype(datetime)
# datetime.datetime(2021, 7, 4, 20, 10, 30)
# 37 np.is_busday(dates,weekmask)
np.is_busday('2021-07-04',weekmask=[0,0,0,0,0,1,1])
# True
np.is_busday('2021-07-04') # weekmask默认时1111100
# False
# 38 np.count_nonzero() 统计一段时间内工作日的数量,获取数组内true的数量
start_date = '2021-07-01'
end_date = '2021-07-31'
date_range = np.arange(start_date,end_date,dtype='datetime64')
np.count_nonzero(np.is_busday(date_range))
# 39 np.busday_offset(date,offsets, roll, weekmarks) 取当前日期的下一个工作日
# 2021-07-02 星期五
np.busday_offset('2021-07-02',offsets=1,roll='forward')
# numpy.datetime64('2021-07-05')
np.busday_offset('2021-07-05',offsets=-1,roll='backward')
# numpy.datetime64('2021-07-02')
1.8 统计
# 40 np.median(arr,[axis]) 求中位数
a = np.arange(32).reshape((4,8))
np.median(a,axis=None)
# 15.5
np.median(a,axis=0)
# array([12., 13., 14., 15., 16., 17., 18., 19.])
np.median(a,axis=1)
# array([ 3.5, 11.5, 19.5, 27.5])
# 41 np.average(arr,[axis]) 算数平均值
# 42 np.mean(arr,[axis]) 加权平均值
# 43 np.std(arr,[axis]) 标准差
# 44 np.var(arr,[axis]) 方差
# 45 nanmedian,nanmean,nanstd,nanvar 忽略nan值
# 46 histogram(a,bins=10,range=None,weights=None,density=False);
"""
a是待统计数据的数组;
bins指定统计的区间个数;
range是一个长度为2的元组,表示统计范围的最小值和最大值,默认值None,表示范围由数据的范围决定
weights为数组的每个元素指定了权值,histogram()会对区间中数组所对应的权值进行求和
density为True时,返回每个区间的概率密度;为False,返回每个区间中元素的个数
"""
a = np.random.rand(100)
count,bins = np.histogram(a, bins=5, range=(0,1))
count,bins # bins将a中的数据分成5段,0~0.2有23个,0.2~0.4有19个 count是统计数组中在每个段内的数量
#(array([23, 23, 19, 16, 19], dtype=int64),
# array([0. , 0.2, 0.4, 0.6, 0.8, 1. ]))