《利用python进行数据分析》是一本利用python的Numpy、Pandas、Matplotlib库进行数据分析的基础介绍,非常适合初学者。
重要的python库
NumPy
http://numpy.org
Pandas
http://pandas.pydata.org
matplotlib
http://matplotlib.org
IPython 和 Jupyter
http://ipython.org
http://jupyter.org
Scipy
http://scipy.org
scikit-learn
http://scikit-learn.org
statsmodels
http://statsmodels.org
nbviewer
https://nbviewer.jupyter.org/
软件安装和环境配置:
安装Anaconda:https://www.anaconda.com/
下载安装包或者pip install jupyter notebook
Jupyter notebook用法:
内省
?, 对象前后加?号可以显示对象概要信息,针对魔术字也是生效的,即可以查看魔术字的参数
??, 使用??可以显示函数源码
?,可以作为通配符使用,与*结合可以查询符合规范的名称
Ipython magic
https://ipython.readthedocs.io/en/stable/interactive/magics.html
%,一个%只作用于命令行
%%,两个%表示作用于命令框
%run
%run script_name.py
可以运行外部脚本
%run -i script_name.py
使用Ipython命名空间已有的变量
%load script_name.py
可以将脚本加载到单元代码
ctrl+c
终止程序运行
%paste和%cpaste
将剪贴板代码黏贴过来,或者会提醒检查。
没用成功过?
%timeit
检查一段python语句的执行时间,计算平均值
%time
报告单个语句的执行时间
%automagic
可以关闭魔术字前面的%符号
%quickref
显示Ipython快速参考卡
%magic
显示所有magic
%debug
从报错底部进入交互调试器,通过u和d可以切换堆栈的不同层级
%pdb
出现任意错误自动进入调试器
%reset
重启变量/名称,命名空间
%who, %who_ls, %whos
展示命名空间定义的变量
%xdel variable
删除变量
%matplotlib, %matplotlib inline
设置matplotlib与Ipython集成,后者是用于jupyter notebook中
%xmode
控制错误栈上下文的数量,有Plain和Verbose两种模式,前者同Cpython,后者是Ipython独有
%hist,可打印全部、部分历史输入记录
IPython扩展
ipython是一个python的交互式shell,是jupyter notebook的内核。
搜索历史命令
%run some.py
以后可输入%run s然后用上下箭头查询历史命令
输入和输出变量引用
_和__分别表示最近的第一个和第二个命令执行结果的输出
_number表示第number行的输出结果
_inumber表示第number行的输入变量
exec(_i27)可以直接执行一次第27行命令
与操作系统交互
可以直接输入win或shell命令
!cmd 执行cmd命令
output = !cmd args 运行命令并保存输出结果
%alias alias_name cmd 起别名
%bookmark 使用IPython的目录书签系统。 %bookmark pydata /home/ccc/code/pydata
%cd dir 更改目录
%pwd 返回当前工作目录
%pushd dir 将当前目录放在堆栈上,并更改伪目标目录
%popd 切换到堆栈顶部弹出的目录
%dirs 返回包含当前目录堆栈的列表
%dhist 打印访问目录的历史记录
%env 以字典形式返回系统环境变量
%matplotlib 配置matplotlib集成选项
调试程序
出问题后,通过%debug进入堆栈最底层,通过u和d可以切换堆栈的不同层级
也可用%pdb直接让程序出错时进入调试模式
run -d test.py,可以进入单步调试模式, s表示进入脚本,可以设置断点,可以用c继续运行程序
b linenumber, 可以设置断点
b path/file.py:number 在指定文件行设置断点
n, next意思
c, continue意思
s,step单步意思
!variable, 变量前面加!可以显示变量值
u/d, 在调用栈中上下移动
a, args显示当前函数的参数
debug statement, 在新的调试器中调用语句statement
l statement, 显示当前堆栈的当前位置和上下文
w, where意思,在当前位置打印带有上下文的完整堆栈回溯
h, help显示命令列表
help command, 显示command命令的文档
q,quit退出调试器
%run -d test.py, 可以直接进入调试器
%run -d b2 test.py, 加断点
pdb.set_trace
from IPython.core.debugger import Pdb
def set_trace():
Pdb(color_scheme="Linux").set_trace(sys.__getgrame().f_back)
可以在程序任何地方调用set_trace(),比如在抛出异常前调用,可以进入调试模式
pdb.runcall
from IPython.core.debugger import Pdb
def debug(f, *args, **kwargs):
pdb = Pdb(color_scheme="Linux")
return pdb.runcall(f, *args, **kwargs)
可以单独调试一个函数
def f(x, y, z=1):
return (x+y)/z
debug(f, 1,2,z=3)就可以进入调试模式
测试代码运行时间: %time和%timeit
%time,执行一次
%timeit,多次执行取平均值,可以精确到ns级别
分析代码性能:%prun, %run -p
python有个cProfile模块可以用于分析程序性能。
举例:
python -m cProfile -s cumulative test.py #-s指定排序字段
Ipython分析
%prun -l 7 -s cumulative function()
可以分析单个函数
%run -p -s cumulative test.py
%%prun 可以分析整个代码块。
其他第三方库:SnakeViz,使用d3.js生成配置文件结果的交互式可视化
%lprun,这是第三方模块,需要自己配置,可以逐行分析函数代码性能,而不仅仅限制于函数级别
配置方式:
方法1:c.TerminalIPythonApp.extensions = ['line_profiler']
方法2:%load_ext line_profiler
使用方式:
%lprun -f add_and_sum -f call_function call_function()
重载模块
有时候被装载的模块代码被修改,这时除了退出重新进入装载外,还有下面方法:
import some_lib
import importlib
importlib.reload(som_lib)
Ipython有个dreload(some_lib)可以用
代码设计技巧
扁平优于嵌套
适当的大文件比零散的多个小文件好管理
配置文件:
ipython profile create #可以形成ipython配置文件
文件路径C:\\Users\\guangxinwang\\.ipython\\profile_default\\ipython_config.py
也可以创建一个新的配置文件,并自己使用:
ipython profile create secret_project
ipython --profile=secret_project
jupyter notebook的配置文件:
jupyter notebook --generate-config
默认路径.jupyter/jupyter_notebook_config.py
jupyter notebook --config=~/.jupyter/my_custom_config.py
配置内容摘要有:
主题
启动扩展模块等
自定义魔术函数等
NumPy基础:数组和向量化计算
NumPy的重要性:
1、NumPy的设计对于含有大量数组的数据非常有效;
2、NumPy在内部将数据存储在连续的内存块上,NumPy的算法库是C语言写的,不需要任何类型检查。而且占用的内存量也小
3、NumPy可以针对全部数组进行复杂计算而不需要写python循环
导入:推荐import numpy as np
NumPy的核心——N维数组对象ndarray
一个ndarray是一个通用的多维同类数据容器,即它包含的每一个元素都是相同类型
属性:
shape
表示ndarray的维度
dtype
表示ndarray的数据类型,ndarray的默认数据类型是float64
ndim
表ndarray数组的维度
形成ndarray数组的方法
array, 将输入数据转换成ndarray数组,如果不指定类型,会自动推断
asarray, 同上,只是如果输入已经是ndarray就不再复制
arange, range函数,返回一个数组。np.arange(0.0, 1.0, 0.01),返回从[0,1)间隔0.01的共100个dnarray数组
ones, 全1数组
ones_like, 根据所给数组形成全1数组,即shape同所给数组,值全1
zeros, 全零数组
zeros_like,参照数组形成全0数组
empty, 空输入,内容随机
empty_like,参照数组形成空数组
full, 形成指定数值的数组
full_like,参照指定数组形成指定数值的数组
eye, identity, 形成对角线全是1的数组
random.randn,形成随机数,满足正态分布
random.randint,返回随机整数
ndarray的数据类型
int/float/complex/bool/object/string_/unicode_
长度有8/16/32/64/128/256等等
默认int为32,float为64
类型转换方法astype
my_int_arra.astype(float)
astype一定会形成新的数组
数组运算
*,-,+,/,** 逐个元素相乘,减,加,除,幂
>,<,逐个元素比较大小
索引和切片
切记:
NumPy的切片不生成新数组,而是原数组的引用,相关操作会直接作用在原数组上面,这样做好处是节省内存
如果希望新创建数组需要显示的用copy方法,比如arr[5:8].copy()
下面2种方法效果相同:
arr2d[0][2]
arr2d[0,2]
可以对切片后的数组直接赋值
寻址:
对于一个N维数组a
当需要定位到一个元素时需要同时输入N个坐标才能取到单个元素的值。
每少一个坐标,取到的值就会多一个维度。少的一个坐标轴就会返回该坐标轴上面的所有数据;
每多一个坐标,就可以少一个维度的不确定性。
降维就是通过指定一个坐标轴,取该坐标轴上面其他维度的数据
在一个轴上面切片是可以取到同维度的数组的
布尔索引
假设a数组维度为3*4即a(3,4)
a>0,会形成同样维度的bool类型数组,里面的每个值都会是True或False
可以用bool类型的数组作为索引,对同维度的数组进行取值,比如a(3,4),b是一维3元素数组,这样a[b>0]可以对a的行取值
同理,更高维度也可以。比如a(5,7,4),b(7,4)执行a[:b>0]会形成一个(5,x)的维度数组,x取决于b>0的个数。注意这里会做降维处理。
注意,两者维度不同时会报错。
这里支持用==,>,<,!=,~取反,&,|等操作
and or操作在这里不生效,需要用&/|
利用布尔索引可以对一个数组的指定元素进行操作,比如a[a>0]=0,就可以将a数组里面所有大于0的元素赋值为0,而操作后a的维度不变。
再举例:a(5,7,4),b(7,4),执行a[:,b>0]=0可以对a中所有行执行同样赋值操作,结束后a还是(5,7,4)维度不变
神奇索引
可以用数组作为索引值
举例:
arr(8,4)数组,arr[[4,3,0,6]]会返回第4、3、0、6行的数据,也支持负数索引
arr[[4,3,0,6],[1,2,3,0]]返回的是一个一维数组取值(4,1),(3,2),(0,3),(6,0)
行与列索引
行索引arr[:2]
列索引arr[:,:2]
转置和转轴
reshape(),变换形状
np.arange(8).reshape((2,4)) #变为2*4数组
np.arange(8).reshape((2,-1)) #作用同上,传入-1表示让numpy自己推断数组维度
np.arrage(8).reshape(other_arr.shape) #shape也可以作为参数传入
扁平
np.arange(8).reshape((2,-1)).ravel() #ravel是分散意思,会扁平成一个一维数组,不会形成副本
np.arange(8).reshape((2,-1)).flatten() #flatten作用同ravel,区别是这个会形成一个新的副本
arr.T,转置,是一种特殊的转轴,对于多维数组的转轴,就是将所有的轴完成倒序操作
np.dot(arr, arr.T),计算矩阵内积
arr.transpose()转轴,参数是轴索引
转轴计算方法:
第一步先变形,比如一个arr(2,3,4)矩阵,如果轴0和轴1转轴,该矩阵将变为arr(3,2,4)
第二步填值,新的变形后的矩阵的每个元素比如arr[i,j,k]就等于原来数组的arr[j,i,k]
arr.swapaxes()方法可以将轴进行调整重组成新数组,也是转轴的一个方法,仅支持2个轴交换
通用函数ufunc
一元通用函数:
abs,fabs, 绝对值
sqrt,平方根
square, 平方
exp, e的指数值
log,log10,log2,log1p,分别是以e,10,2为底,最后一个是log(1+x),默认以e为底
sign, 求符号值,1,0,-1
cell,最高整数,遇到小数往上取整
floor,往下取整
rint,保留整数位,且保留dtype
modf, 分别返回小数和整数部分
isnan,判断是否为NaN,不是一个数值
isfinite,isinf, 是否有限还是无限
cos,cosh,sin,sinh,tan,tanh三角函数
arccos,arccosh,arcsin,arcsinh,arctan,arctanh,反三角函数
logical_not,对数组元素按位取反,同~arr
二元通用函数:
add,元素对应相加
subtract,减
multiply,乘
divide,floor_divide,除,整除
power, 幂
maximum,fmax,最大值
minimum, fmin,最小值
mod,取模求余数
copysign,将第一个数组的符号值改成第二个数组的
greater,greater_euqal,less,less_equal,equal,not_equal,逐元素比较,返回布尔型
logical_and,logical_or,logical_xor,逻辑与,或,异或
面向数组编程
np.where
等同于python的 x if condition else y
格式:
new_arr = np.where(condition, xarr, yarr)
解释:
condition是条件判断,如果为真元素取xarr中值,false取yarr中的值
举例:
np.where(arr>0, 2, -2)
arr中元素如果大于0会被置为2,小于0会被置为-2
统计方法
数组方法和np方法都可以
arr.mean()或np.mean(arr),平均值
mean(axis=0),计算给定轴的平均值,就是把该轴上面的值求和然后再平均,这样会导致该轴的维度扁平为1维。
mean(0),不带axis也可以
如果是一个三维数组(2,3,4),mean(axis=2)会把轴2扁平化,形成(2,3)数组
sum(),求和
cumsum()累计求和
cumsum(axis=0),沿着行做累计求和,就是从第2行开始,每个元素都是上一行对应列加本行对应列的和。即把所有axis轴数据都加起来。
std()标准差
var()方差
cov()协方差
min(),max()最小最大值
argmin(),argmax(),最小最大值得位置
cumprod(),从1开始元素累积积运算,cumsum是和运算
布尔值数组方法
(arr > 0).sum()可以计算True数量
any(),任意为True就为True
all(),所有为True才为True
排序
sort(),可以沿着axis排序如sort(0)就是沿着x轴对y轴进行排序,就是只对y轴排序
唯一值
np.unique()
针对一维数组,返回的是去重后的数组,并且还完成排序
np.in1d(arr1, arr2)
判断数组1中值是否在数组2中,返回bool类型的数组,长度同arr1
intersect1d(x, y)
x,y交集并排序
union1d(x,y)
x,y并集并排序
setdiff1d(x, y)
差集,在x但不在y中的x的元素
setxor1d(x,y)
异或,在x或y中,但不同时在x和y中
装载与存储
np.save(file, arr, allow_pickle=True, fix_imports=True)
np.load(file,mmap_mode=None,allow_pickle=False,fix_imports=True,encoding='ASCII',)
默认都是二进制形式存取的
文件后缀默认是npy
np.savez(file, *args, **kwds)
压缩存储
举例:
np.savez("array_arhive.npz", a=arr1, b=arr2)
此时用np.load会返回一个字典类型
arch = np.load("array_archive.npz")
可以用arch['a']或arch['b']取到存储的数组
np.savez_compressed(file, *args, **kwds)
将新的数组存入已经压缩好的文件中
线性代数
*, 表示矩阵逐元素乘法
dot(),表示矩阵点乘
arr1.dot(arr2)
np.dot(arr1,arr2)
arr1 @ arr2
@也是点乘,属于一元运算符
numpy.linalg库函数(linear algebra)线性代数
diag, 用于将一个方阵的对角元素转换为一维数组,或者把一维数组转换为方阵
dot,点乘
trace,计算对角元素和
det,计算矩阵的行列式
eig,(eigen)计算方阵的特征值和特征向量
inv,(inverse)计算方阵的逆矩阵
pinv,计算矩阵的Moore-Penrose伪逆
qr,计算QR分解
svd,计算奇异值分解(SVD)
solve,求解x的线性系统Ax = b, 其中A是方阵
lstsq,(least square)计算Ax=b的最小二乘解
伪随机数的形成
np.random.normal(size=(4,4))
形成4*4的正态分布数组
np.random.seed(1234)
更改伪随机种子,作用于全局。随机种子类似于产生随机数的初始值,随机种子相同情况下产生的随机数也相同,所以要产生不同随机数需要重置随机种子。
np.random.RandomState(1234)
创建伪随机生成器,独立于全局随机种子的影响
rng = np.random.RandomState(1234)
rng.randn(10)
常用函数列表:
seed, 种子
permutation, 返回一个序列的随机排列,或返回一个乱序的整数范围序列
shuffle, 随机排列一个序列
rand,从均匀分布中抽取样本
randint, 根据给定的由低到高的范围抽取随机整数
randn, 从均值0方差1的正态分布中抽取样本
binomial, 从二项分布中抽取样本
normal, 从正态分布中抽取样本
beta,从beta分布中抽取样本
chisquare, 从卡方分布中抽取样本
gamma,从伽马分布中抽取样本
uniform,从均匀[0,n)中抽取样本,np.random.uniform(0,10000,size=50)
举例1:
import matplotlib.pyplot as plt
nsteps = 1000
draws = np.random.randint(0, 2, size=nsteps) #从0,1中随机抽取1000次
steps = np.where(draws > 0 , 1, -1) #把0,1格式化成-1和1
walk = steps.cumsum() #对数组做累计求和
plt.plot(walk) #打印折线图
walk.min() #求连续走最小或最大步数
(np.abs(walk) >= 10).argmax() #求第一次连续一个方向走10步的位置
举例2:
nwalks = 5000
nsteps = 1000
draws = np.random.randint(0, 2, size=(nwalks,nsteps)) #形成一个二维数组
steps = np.where(draws > 0, 1, -1)
walks = steps.cumsum(1) #沿着1轴做累计和
hits30 = (np.abs(walks) >= 30).any(1) #沿着1轴做任何一个元素为True就总结果为True,返回的hits30是一个5000行的一维数组,元素都是True和False
crossing_times = (np.abs(walks[hits30]) >= 30).argmax(1) #walks[hits30]获取hits30中为True的行,比如有3000行,argmax沿着1轴求最大值第一次出现的位置索引
crossing_times.mean() #请第一次出现位置的平均值
NumPy进阶:
数组构成
NumPy数组包含下面内容:
指向数据的指针
数据类型dtype
表示形状的元组
步长元组
比如np.ones((2,3,4),dtype=np.int32).strides是(48, 16, 4)
解析:
最后一个4是数据长度为4字节
第一个48表示344,表示每行的跨度是48字节
第二个16表示4*4,表示最小一维数组的跨度是16字节
dtype层次结构和类型判断
generic -> number -> integer -> unsigned int 各种字节的无符号数,下同
| | -> signed int
| -> inexact -> floating
| -> complex
-> character -> string _
| -> unicode_
-> bool _
-> object_
np.issubdtype(obj.dtype, np.interger)
通过issubdtype方法可以判断数组类型是否属于某一类型
np.float64.mro()
可以通过mro方法查看该类型的父类
C顺序和F顺序
C顺序/行方向顺序,即C语言顺序
首先遍历更高维度(在轴0上行进之前先在轴1上行进)
F顺序/列方向顺序,即Fortran语言顺序
首先遍历高低维度
NumPy默认是C顺序,比如ravel()默认参数是C,如果ravel('F')就会返回F顺序的数据
数组的连接和分隔
arr1,arr2都是(2,3)数组,那么np.concatenate([arr1,arr2], axis=0)就会连接成一个(4,3)数组, axis=1会连接成(2,6)数组
arr是一个(5,2)数组,first, second, third = np.split(arr, [1,3]),会被分隔成3个数组,分隔位置就是1和3,first是一维,secode是1和2行的2维数组,third是2维
所有连接分隔函数:
concatenate, 通用连接函数
vstack, row_stack, 按行堆叠,沿轴0
hstack, 按列堆叠
colum_stack, 类似hstack,但会先把一维数组转换为2维列向量
dstack, 按深度堆叠数组,沿着轴2
split, 沿指定轴分隔数组
hsplit,vsplit,沿轴0和轴1分隔
r_和c_堆叠助手:
arr = np.arange(6)
arr1 = arr.reshape((3,2))
arr2 = np.random.randn((3,2))
np.r_[arr1, arr2] #将返回一个(6,2)数组,类似vstack
np.c_[np.r_[arr1,arr2], arr] #返回一个(6,3)数组,类似hstack
数据重复
repeat
arr.repeat(2,axis=0),将arr所有元素重复2遍,并沿着0轴做扩展。如果arr是(2,2),重复后是(4,2)
如果不指定axis,会被扁平化为一维数组
arr.repeat([2,3], axis=0),如果arr是(2,2),重复后为(5,2),传入[2,3]数组分别指定第一行重复2次,第二行重复3次
tile
俗称瓷砖铺设,将原始数组理解成1个大瓷砖,然后重复这个瓷砖
比如arr(2,2)
np.tile(arr, 2),将变为(2,4),默认在列方向扩展
np.tile(arr,(3,2)),将变为(6,4)
tile和repeat区别是前者是将整个数组作为一个整体进行复制,而后者是对每个元素进行复制。所以后者重复的行或列会连续出现,而前者是间隔出现
神奇索引等价操作
take
take可以根据索引取对应轴的数据
比如arr是(2,4),inds=[2,0,2,1]
那么arr.take(inds, axis=1)就会得到(2,4)数组,4列分别是原数组的第2、0、2、1列
put
向数组赋值,put需要注意是不接受axis参数的,而是会做扁平化处理。
比如arr.put(inds, [1,2,3,4])就会把inds里面索引的元素分别赋值为1、2、3、4.注意索引会做扁平化处理。默认按C顺序进行编号
广播机制
广播需要慎重,仔细,容易出错
广播规则:
如果对于每个结尾维度(即从尾部开始的),轴长度都匹配,两个二维数组就是可以兼容广播的。之后,广播会在丢失的轴上进行。
如果不是在轴0广播,而是其他轴上面广播,要求广播的轴维度为1。如果有多个轴为1,那么所有维度为1的轴都会广播。
举例:
arr是(4,3),那么arr.mean(0)是4,arr.mean(1)是3
那么arr-arr.mean(0)就是(4,3)与3的运算,可以进行行方向的广播
arr-arr.mean(1)就是(4,3)与4的运算,由于3和4不同,无法进行列方向的广播,这时进行arr.mean(1).reshape(4,1)变形,就是(4,3)与(4,1)运算,因为是1可以广播
同理,多维数组也是可以广播的,比如(3,4,2)和(4,2)数组是可以沿着轴0广播。
np.newaxis
reshape可以加一个1维的轴。替代方案用np.newaxis插入一个新轴。
arr如果是(3,4),变成(3,1,4)方法:arr[:,np.newaxis,:]
其实np.newaxis就是None,直接用None其实也可以
多维数组的广播
arr是(2,3,4),和数组(2,1,4)进行运算时,会沿着1维的轴1进行广播。
举例:求arr-轴2平均值
arr - arr.mean(axis=2)[:,:,np.newaxis]
举例:一个通用函数
def demean_axis(arr, axis=0):
indexer = [slice(None)] * arr.ndim #slice(None)等同于[:],将切片扩展到多维[:,:,:]
indexer[axis] = np.newaxis #等同于[:,newaxis,:]
return arr - arr.mean(axis)[indexer]
通过数组索引完成广播赋值
arr = np.zeros((4,3))
arr[:] = 5 #arr所有元素将全部赋值为5
col = np.array([1,2,3,4])
arr[:] = col[:, np.newaxis] #col[:, np.newaxis]可以转为(4,1)数组, arr[:]索引全部列,最终arr所有3列的值相同都是1、2、3、4
arr[:2] = [[8],[9]] # [[8],[9]]是一个(2,1)数组,arr的第一行全是8,第2行全是9
高阶ufunc用法
在普通的ufunc运算后面可以再跟高阶的ufunc函数,比如np.add.reduce(arr)。
reduce(x)
聚合操作
举例:
arr=np.arange(10)
np.add.reduce(arr) #等同于arr.sum()就是求和
np.logical_and.reduce(arr[:,:-1] < arr[:,1:], axis=1)
等同于对每行求all方法。
accumulate(x)
累计聚合,两两相加
举例:
np.add.accumulate(np.arange(15).reshape((3,5)), axis=1) 会沿着轴1,对轴0做累计求和
reduceat(x, bins)
group by缩聚方法
举例:
np.add.reduceat(np.arange(10),[0,5,8]) #会对[0,5],[5,8],[8:10]分3组聚合
也可以加axis参数
outer(x,y)
操作应用于x,y所有元素对,执行结果的维度是x和y的维度和,比如x和y是一维数组,那么运算完后就变成2维数组。
举例:
np.multiply.outer(np.arange(4),np.arange(5))
得到一个(4,5)二维数组
用python编写ufunc方法
下面2个方法是用python编写ufunc方法,因为都是用python编写的,所以运行速度会很慢,比C语言的差可能1000倍
numpy.frompyfunc
举例:
def add_element(x, y):
return x + y
add_them = np.frompyfunc(add_element, 2,1) #2表示输入参数2个,1表示输出参数1个
add_them(np.arange(8), np.arange(8)) #返回结果是一个object类型,而不是numpy类型对象
numpy.vectorize
这个可以指定返回值类型
举例:
add_them = np.vectorize(add_element, otypes=[np.float64]) #add_element是一个自定义python函数,otype是定义函数输出类型
add_them(np.arange(8), np.arange(8))#返回float64类型
结构化
numpy用的是同构数据,即所有数据类型都是dtype,同一类型。如果想表示异构或者表格数据也有方法。
方法:
使用(field_name, field_data_type)作为元组的列表传给构建数组时的dtype值
dtype=[('x',np.float32),('y',np.int32)]
arr=np.array([(1.5,6),(np.pi,-2)],dtype=dtype)
arr将是一个一维数组,而且元素是2个。但是可以用arr['x']或者arr['x'][0]等方式来取值
嵌套和多维字段
dtype=[('x',np.int64,3),('y',np.int32)]
arr=np.zeros(4,dtype=dtype)
这样arr['x']或者arr[0]['x']等方式访问3个元素
dtype=[('x', [('a', 'f8'), ('b', 'f4')]), ('y',np.int32)
也可以这样嵌套定义
排序
sort排序
arr.sort()是原位排序,不形成新数组
np.sort(arr)会形成新数组
所有排序都是升序排序,如果要降序,可以用arr[:,::-1]方式获取
间接排序
argsort
返回排序后的索引值
np.array([5,0,1,3,2]).argsort()返回的是array([1,2,4,3,0])这个数组是索引,用arr[index]方式可以获取排序后的数组
按第一行重新排序:
arr[:,arr[0].argsort()] #arr[0].argsort()返回比如array([2, 1, 0, 4, 3], dtype=int64),这样类似arr[:,[2,1,0,4,3]],重新排列列
numpy.lexsort
和argsort类似,也是返回index。区别是numpy.lexsort可以完成多键排序
举例:
sorter = np.lexsort((first_name, last_name))
注意,这里会先根据last_name进行排序,在有相同值时,会比较对应列的值大小,来决定最终排序。
返回结果也是索引值,比如[1,2,3,0,4]
稳定排序
针对的是有相同元素的排序,当元素相同时,靠前的元素会排在前面
举例:
value.argsort(kind='mergesort')
kind有3种可用排序选项:
种类 速度 是否稳定 工作空间 最差情况
'quicksort' 速度最快 不稳定 O O(n^2)
'mergesort' 速度中等 稳定 n/2 O(n log n)
'heapsort' 速度低 不稳定 O O(n log n)
分组排序
numpy.partition和numpy.argpartition
可用完成分段/分组排序,后者同argsort返回的是等价信息索引
举例:
np.partition(arr,3),会将arr分成2组,前面3个元素一组,后面的一组,其中前面3个是最小的3个元素。注意只是组间有排序,具体到组内元素是随机的不排序。
在已排序数据中寻找插入位置
numpy.searchsorted
注意,必须是已经排序的数组
举例:
arr.searchsorted([0,8,11,16]) #返回这4个值在arr数组中的插入位置索引
可以用于分组:
group=np.array([0,100,1000,5000,10000])
group.searchsorted(data) #将data中元素归类到group中的区间
numba库
http://numba.pydata.org
建议好好研究下,该库使用LLVM将python代码编译成机器码,大大加快python执行速度
举例1:
from numba import vectorize
@vectorize
def nb_add(x, y):
return x + y
x = np.arange(10)
nb_add(x, x)
nb_add.accumulate(x, 0)
举例2:
from numba import float64, njit
@njit(float64(float64[:], float64[:]))
def mean_distance(x, y):
return (x - y).mean()
高阶数组的输入和输出
内存映射文件mmap
mmap = np.memmap('mymmap', dtype='float64', mode='w+', shape=(10000,10000))
和打开文件类似,需要指定文件名、数据类型、打开模式、形状
该文件会被映射到连续内存中,可以对其操作
mmap.flush() #将数据刷回到磁盘中
HDF5或其他数组存储选择
PyTalbes和h5py是2个为NumPy提供友好接口的Python项目,可以高效和可压缩的HDF5格式存储。(Hierarchical Data Fram)分层数据格式
可参阅pandas官方文档
NumPy性能技巧
将Python循环和条件逻辑转换为数组操作和布尔数组操作
尽可能使用广播
使用数组视图(切片)来避免复制数据
使用ufunc和ufunc方法
如果实在无法获得所需性能,请考虑在C、Fortran或Cython中编写代码。用Cython可以获得近乎C语言的性能
内存连续对性能很重要
通常C顺序数组比F顺序数组速度快,因为C在存储方面的优势
arr.flags可以查看数组的一些属性
arr.flags.f_contiguous
常用方法汇总:
np.linspace(start,stop,num=50,endpoint=True,retstep=False,dtype=None,axis=0,)
Return evenly spaced numbers over a specified interval.
举例:返回从开始到结束,间隔相同的50个数。
np.meshgrid(*xi, **kwargs)
Return coordinate matrices from coordinate vectors.
举例:x为长度20的标量,y是长度30的标量,都是一维数组
那么arr1,arr2=np.meshgrid(x,y)会返回2个数组,维度都是(30*20)的二维数组,
其中数组1的数据就是x的0轴广播,数组2就是y变成列向量,然后在y轴广播
pandas
pandas与Numpy最大区别
pandas用于处理表格型或异构数据
Numpy用于处理同构数据,即数组中所有数据类型是一样的
导入:
import pandas as pd
from pandas import Series, DataFrame
数据结构:
Series
一维数组型对象,包含了值和索引,默认索引从0到N-1
构建:
obj = pd.Series([3,9,1,-5])
obj.value #返回array([ 3, 9, 1, -5], dtype=int64)
obj.index #返回RangeIndex(start=0, stop=4, step=1)
指定索引名
obj = pd.Series([3,9,1,-5], index=['a', 'b', 'c', 'd'])
用标签获取值
obj['a']
数学运算
obj[obj > 0]
obj * 2
np.exp(obj)
字典类操作:
另外,因为Series很像字典的key:value结构,所以字典的一些操作也适用于Series
'b' in obj
obj = pd.Series({'a':'ohio', 'b':'texas', 'c':'utah'}
生成的Series是按照字典key排序后的序列,如果想指定索引顺序,可以在Series构造时传入index=参数
NaN
panda表示缺失值Not a Number
pandas使用isnull() 和 notnull()函数来检查缺失值
pd.isnull(obj) 或 serieas_obj.isnull() #返回True和False的bool型对象数组
pd.notnull(obj) 或 serieas_obj.notnull()
自动对齐索引
obj1 + obj2 #会自动根据索引进行相加运算,如果有一项为NaN,那最终结果也是NaN
改变索引
obj.index = ['bob', 'steve', 'jeff', 'ryan'] #可以改变obj的索引名
name属性
series_obj.name = "any_name" #Series对象可以有name属性
series_obj.index.name = "index_name" #索引也可以有自己的名字,这里是整个索引的名字
DataFrame
特性:
每一列可以是不同的数据类型。
既有行索引,也有列索引
尽管DataFrame是二维的,但是可以通过分层实现多维数组
构建:
根据字典创建
data = {'state' : ['bhio', 'ohio', 'ohio', 'nevada', 'neveada', 'nevada'],
'year': [2001, 2000, 2001, 2003, 2004, 2006],
'pop':[1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = pd.DataFrame(data)
data = {'shanghai':{2000:11,2001:12},'beijing':{2001:44,2000:55,2002:90}}
frame = pd.DataFrame(data)
通过这种方式创建的DataFrame数据,列会使用字典的key,行会使用嵌套字典的key
frame = pd.DataFrame(data, index=[2000, 2001,2002) #也可以自己制定排列顺序
创建时指定列顺序
frame = pd.DataFrame(data, columns=['year', 'state', 'pop'])
如果指定的列不存在,会由NaN填充
创建时指定索引
frame = pd.DataFrame(data, columns=['year', 'pop', 'state', 'non'], index=['one', 'two', 'three', 'four', 'five', 'six'])
frame.index = ['one', 'two','three','four','five','six'] #修改行索引
其他构造DataFrame方法:
2D ndarray, 用2维的ndarry数据构造
数组、列表、元组构成的字典, 每个序列成为DataFrame的一列,所有的序列必须长度相当
NumPy结构化/记录化数组, 与数组构成的字典一致
Series构成的字典, 每个值成为一列,每个series的索引联合起来形成结果的行索引,也可以显示的传递索引
字典构成的字典, 每个字典键值对成为一列,子字典联合起来成为行
字典或Series构成的列表, 列表中一个元素构成DataFrame中一行,字典键或Series索引联合起来形成DataFrame的列标签
列表或元组构成的列表, 同2D ndarray类似
其他DataFrame, 如果不显示传递索引,则会使用原DataFrame的索引
NumPy MaskedArray, 与2D ndarray的情况类似,但隐蔽值会在结果DataFrame中成为NA/缺失值
方法属性:
frame.head() #默认获取前5行
frame.columns #获取列名
frame.T #转置,行列变换位置
获取列与设置列:
frame['year'] #通过列名可以索引一列,这一列的数据类型是pandas.core.series.Series
frame.year #也可以用属性方式进行引用,这个有点局限,就是列名是有效python变量名
frame['debt'] = 15.5 #可以对整列进行赋值
frame['debt1'] = np.arange(6) #注意,赋值时元素个数必须一致
frame['new_colum'] = pd.Series([-1.2, -1.5, -1.7], index=['three','five','one']) #列赋值,Series数据根据索引自动和frame索引对齐,缺失值为NaN
通过frame.year的方式无法创建新的列,但是可以对已经创建的列进行赋值。
year = frame.year, 通过该方式获得的值为series类型,并且关键的是只获得了DataFrame的数据视图,而不是拷贝,所以对series赋值也同时改变DataFrame值
如果需要复制值,需要显示的使用copy方式。
df.insert(1,'D',data) #insert可以在指定位置插入一列数据
删除列:
del frame['new_colum'] #用del可以删除一列,
但用del frame.new_colum却无法删除列,和上面介绍的frame.new_colun无法创建新列,但可以赋值对称
df.drop(['D','E'], axis=1) #可以用drop删除列
获取行列:
frame[:10] #获取前10行
frame.loc[2] #通过loc方法获取行的值
frame.loc['B':'D'] #完成行切片
frame.loc[:,'B','D'] #完成列索引与切片,同frame['B':'D']
frame.loc[2:'B']可以完成行和列同时索引
frame.iloc[1] #提取第一行数据
frame.iloc[2:3, 4:5] #提取第2行,第4列数据
frame.iloc[[2,4,5], [2,4,8]] #提取不连续的行和列
frame.at[2,'B'] #使用at提取元素
frame.iat[2,4] #使用iat提取元素,索引用的都是整数
name属性:
frame3.index.name = 'year' #给索引name属性
frame3.columns.name = 'state' #给列name属性
value属性:
frame3.value #可以获取DataFrame的值,如果数据类型一致会返回ndarray数组,如果数据类型不一致会返回object类型ndarray
索引对象
obj = pd.Series(rang(3), index=['a', 'b', 'c'])
obj.index #这是一个索引对象
index = pd.Index(np.arange(3)) #可以主动构建索引对象
obj = pd.Series(rang(3), index=pd.Index(np.arange(3)) #可以将索引对象传入index参数
索引可以像集合一样操作,但是索引是可以重复的,用重复索引进行筛选会将所有重复索引数据呈现出来。
索引对象的方法和属性:
append, 索引追加
difference, 差集
intersection, 交集
union, 并集
isin, 计算表示每一个值是否在传值容器中的布尔数组
delete, 将位置i处元素删除,并产生新的索引
drop, 根据传参删除指定索引值,并产生新的索引
insert, 在位置i插入元素,并删除新的索引
is_monotonic, 如果索引序列递增返回True
is_unique, 如果索引序列唯一则返回True
unique, 计算索引的唯一值序列
筛选
df[df['D'] > 0] #筛选D列大于0
df[(df['D'] > 0) & (df['E']<0)] #&可以完成与操作
df[(df['D'] > 0) | (df['E']<0)] #|可以完成或操作
df[df['D'].isin(['white','black'])] #isin可以完成包含操作
基本功能
重建索引reindex
普通用法:
obj2 = obj.reindex(['a','b','c','d'])
reindex会根据新的索引重新排列数据
顺序数据的填充方法,比如时间序列
obj3.reindex(range(6), method='ffill') #向前填充,即当顺序数据缺失时,用当前值往前填充没有值的数据
比如如果原索引为[0,2,5],那么填充后索引1的值等于0索引的值
DataFrame的reindex
针对DataFrame可以改变行索引、列索引或同时更改二者。默认是更改行索引。
frame2 = frame.reindex(['a','b','c','d'])
frame2 = frame.reindex(columns=states) #根据列重建索引
reindex方法的参数说明:
index, 根据index重建索引
method, 插值方法,'ffile'前向插值, 'bfill'后向填充
fill_value, 重新索引后引入的缺失值的默认值
limit, 向前或向后填充时所需填充的最大尺寸间隙
tolerance, 向前或向后填充时所需填充的不精确匹配下的最大尺寸间隙
level, 匹配Multiindex级别的简单索引,否则选择子集
copy, 如果为True,即使新索引等于旧索引,也总是复制数据。False时,则在索引相同时不要复制数据。
轴向上删除条目,drop方法
new_series_obj = old_series_obj.drop(['b','c']) #删除2个元素,并返回新的对象
new_frame_obj = old_frame_obj.drop(['b','c']) #删除2行,返回新对象
new_frame_obj = old_frame_obj.drop(['b','c'], axis=1) #删除2列,返回新对象,1也可以是axis='columns'
old_frame_obj.drop(['b','c'], inplace=True) #直接在原对象上面操作,而不产生新的对象
索引
切记:普通python的索引是[a,b),后面b是开区间。但是series这里的索引是闭区间[a,b]
series_obj['a':'d'] #会返回'a','b','c','d'这4个元素
frame_obj['a'] #返回的是列数据,传入一个元素或者一个列表可以选择列
frame[['ohio', 'texas']] #返回多列数据
frame[:2] #选择行可以用切片方式
frame[frame['ohio'] >2] #利用True、False对行进行选择
DataFrame索引选项
df[val], 可以选择单列、多列、通过布尔数组过滤行、对行切片、布尔值DataFrame
df.loc[val], 根据标签选择行
df.loc[:, val], 根据标签选择列
df.iloc[where], 根据整数值选择行
df.iloc[:, where], 根据整数值选择列
df.iloc[where_i, where_j], 根据整数值选择行和列
df.at[lable_i, label_j], 根据行列标签选择单个值
df.iat[i,j], 根据行列值选择单个值
reindex, 通过标签选择行列
get_value, set_value, 根据行列标签设置单个值,好像最新的版本不支持这2个方法了
loc/iloc索引方法
可以通过DataFrame的loc方法,用slice获取数组的重新排序
frame.loc[['a','d','c'],['texas','california','ohio']]
loc是通过轴的标签进行索引,iloc是通过整数标签类似NumPy风格进行索引
frame.iloc[1,[1,2]]
数据对齐:
当两个Series或DataFrame做相加或其他操作时,如果2个对象的标签没有对齐,那么在新形成的对象中没对齐的标签将会被填充NaN缺失值。
举例:
series1=pd.Series([1,2], index=['a','c'])
series2=pd.Series([1,2], index=['b','c'])
series1 + series2会得到(NaN,NaN,4)的series对象
DataFrame会同时在行和列上面做数据对齐
默认填充值fill_value参数
可以判断,当值为NaN时,可以用fill_value替代。
df1.add(df2, fill_value=0) #df1+df2相加,遇到NaN时用0替代,比如df1中值是1,而df2中的值是NaN时,两者相加结果是1,而不是NaN。
算术方法:
add, radd, #带r的翻转运算
sub, rsub
div, rdiv
floordiv, rfloordiv, #整除//
mul, rmul
pow, rpow
DataFrame和Series之间操作
默认会在行方向进行广播,比如frame1 - series1 实际是frame1的每一行都会减去series,这点同NumPy的广播机制
遇到数据不对齐情况,默认会填充NaN
如果需要改成在列方向的广播,需要用上面提到的算术方法,参数里面加axis
举例:
series1 = frame1['colum1']
frame1.sub(series1, axis="index") #在列上面广播,在行上面匹配。axix=0或者axis="index"
frame1.sub(series1, axis="columns") #默认值,在行上面广播,在列上面匹配。axix=1或者axis="columns"
函数应用和映射
应用到每一个元素: np.abs(frame)
应用到一行或一列:DataFrame.apply()
举例:
frame.apply(fuc) #将函数func应用到frame的每一列,默认是列
frame.apply(func, axis='columns') #每行调用一次,应用到每一行。得到的结果是一个series类型
def func(x):
return pd.Series([x.min(), x.max()], index=['min', 'max'])
frame.apply(func) #apply返回的类型不止是标量,也可以是向量类型
逐元素的python函数也可以使用:
举例:
format = lambada x: ‘%.2f' %x
frame.applymap(format)
可以将函数应用到每一个元素中
series.map(format) # series使用map方法, DataFrame使用applymap方法
排序和排名
sort_index()
可以按索引进行排序
举例:
series_obj.sort_index() #返回一个新对象,按照索引进行排序,默认升序
frame_obj.sort_index() #默认按照行索引进行排序
frame_obj.sort_index(axis=1) #对列索引进行排序
frame_obj.sort_index(axis=1, ascending=False) #也可以按降序排序
sort_values()
可以按值进行排序
举例:
series_obj.sort_values() #按值排序,NaN数据会排在最后面
frame_obj.sort_value(by='['a','b']) #DataFrame按值排序可以根据多行进行,需要传入by参数
rank()排名
se1 = pd.Series([7,-5,7,4,2,0,4])
se1.rank()返回结果如下:
0 6.5 #这2个数字意义 se1索引0元素排名6.5,因为这里默认方法是并列情况进行平分
1 1.0
2 6.5
3 4.5
4 3.0
5 2.0
6 4.5
obj.rank(ascending=False) #按照降序排名
平级关系打破方法:
'average', 默认值, 平均分配排名
'min', 整个组使用最小排名
'max', 整个组使用最大排名
'first', 按照出现次序排名
'dense', 类似method='min',但组之间排名总是增加1,而不是增加组的数量个数
含有重复标签的轴索引
有些情况下标签是可以重复的
is_unique属性可以判断索引是否存在重复情况
series_obj.index.is_unique,返回值是True或False
统计
对NA的处理
与NumPy类似,只是內建了处理缺失值的功能。
NA默认排除,如果所有值都是NA,那结果也是NA。
通过skipna可以控制NA的处理措施,比如frame.sum(skipna=False)就不会忽略NaA值了。
归约方法的常用参数:
axis
skipna
level, 如果轴是多层索引的,该参数可以缩减分组层级
描述性统计与汇总统计
count, 非NA值的个数, frame.count()这里默认是按列统计
describe, 计算Series或DataFrame各列的汇总统计集合,比如count,max,min,mean, std, 25%,50%,75%分位
min,max,
argmin, argmax, 计算最大最小值的索引位置,返回整数
inxmin, inxmax, 计算最大最小值得索引标签
quantile, 计算样本的从0到1的分位数,或者是中位数
sum, 默认是对列求和。如果sum(axis=1)或者sum(axis='columns')就会对行求和。
mean, 均值
median, 中位数50%分位数
mad, 平均值的平均绝对偏差
prod,所有值的积
var, 方差
std, 标准差
skew, 样本偏度(第三时刻)值
kurt, 样本峰度(第四时刻)值
cumsum,累计值
cummin, cummax, 累计值的最大和最小值
cumprod, 累计积
diff, 计算第一个算术差值(对时间序列有用)
pct_change, 计算百分比
corr和cov,相关性与协方差
corr,计算2个Series或DataFrame的重叠的、非NaN的、按索引对齐的值得相关性
cov,计算协方差
corrwith, 计算2个DataFrame与另一个Series或DataFrame的相关性,如果是Series会计算与所有列的相关性,如果是DataFrame会计算匹配列的相关性
axis如果传入columns的话,会逐行计算相关性
唯一值、计数、成员属性
unique()
series_obj.unique()可去重
value_counts()
series_obj.value_counts()计算series包含值的个数,默认降序
pd.value_counts(obj.values, sort=False) #可以直接使用pandas顶层方法
下面是应用于DataFrame方法:
frame.apply(pd.value_counts).fillna(0) #对每一列进行归类
isin()
series_obj.isin([0,3,4]) #判断是否在集合内
Index.get_indexer()
返回的是索引
pd.Index(unique_vals).get_indexer(to_match)
返回to_match元素再unique_vals列表中的索引位置,整数类型
match()
计算每个值的整数索引,形成一个唯一值数组。有助于数据对齐和join类型的操作
pandas-datareader库
功能:从网络资源读取数据成pandas格式
安装方法:conda install padas-datareader
导入方法:import pandas_datareader.data as web
数据的载入、存储、文件格式
文本格式数据的读写
下面是pandas的解析函数
read_csv, 从文件、url、文件对象中读取分隔好的数据,逗号是默认分隔符
read_table, 同上,只是TAB是默认分隔符
read_excel, 从excel文件中读取数据
read_sql, 将SQL查询结果(使用SQLAlchemy)读取为pandas的DataFrame
read_fwf, 从特定宽度格式的文件中读取数据,无分隔符
read_clipboard, read_talbe的剪贴板版本,在将表格从Web页面上转换成数据时有用
read_hdf, 读取用pandas存储的HDF5文件
read_html, 从HTML中读取所有的表格数据
read_json, 从JSON字符串中读取数据
read_msgpack, 读取MessagePack二进制格式的pandas数据
read_pickle, 读取Python pickle格式存储的任意对象
read_stata, 读取stata个数数据
read_feather, 读取Feather二进制格式
上面函数的主要可选参数:
索引,
类型推断和数据转换
日期时间解析,包括将多个列组成一个列,比日期+时间
迭代, 支持对大型文件的分块迭代
未清洗数据问题, 可以跳过一些次要数据,比如用逗号分隔的千位数字,页脚,注释等
举例:
df = pd.read_csv('ex1.csv')
df = pd.read_table('ex1.csv', sep=',')
pd.read_csv('ex1.csv', header=None) #读取没有表头数据,列索引会pandas会自己添加
pd.read_csv('ex1.csv', names=['a','b','c','d','message']) #可以自己指定列名
pd.read_csv('ex1.csv', names=['a','b','c','d','message'], index_col='message') #index_col可以按列对DataFrame数据进行索引
pd.read_csv('ex1.csv', index_col = ['key1', 'key2']) #列可以按照key1和key2分层索引
pd.read_table('ex1.csv', sep='\s+') #使用正则表达式作为分隔符,便于各种形式的分隔情况,\s+是空格,而不管多少个空格
pd.read_csv('ex1.csv', skiprows=[0,2,3]) #跳过指定列
pd.read_csv('ex1.csv', na_values=['NULL'] #指定默认缺失值填充
pd.read_csv('ex1.csv', na_values={'message':'foo'}) #可以用字典方式,指定每个列的替换方法,比如这里就是将message列的foo元素替换成NaN
read_csv/read_table函数参数
path
sep/delimiter, 分隔符或正则表达式
header, 列名,默认第一行
index_col, 用列名对行做分层显示
names, 和header=None一起使用,指定表头
skiprows, 跳过指定行
na_values, 需要用NA替换的值序列
comment, 在行结尾处分隔注释的字符,比如#符号
parse_dates, 将数据解析成日期时间格式,默认是False。如果是True,可以解析所有列,或指定列号或列名的列表。会把多个列一起解析,比如Date+time
keep_date_col, 如果连接列到解析日期上,保留被连接的列,默认False
converters, 将列名称映射到函数。比如{'foo':fuc}就是把func函数映射到foo列
dayfirst, 按June 7, 2020解析日期
date_parser, 用于解析日期的函数
nrows, 从文件开头处读入的行数
iterator, 返回一个TextParser对象,用于零散的读入文件
chunksize, 用于迭代的块大小
skip_footer, 忽略文件尾部的行数
verbose, 打印详细输出
encoding, 编码方式
squeeze, 如果解析数据只包含一列,返回Series
thousands, 千位分隔符
分块读入文本文件
pd.options.display.max_rows = 10 #可以对pandas进行设置
pd.read_csv('ex1.csv', nrows=2) #指定行数
pd.read_csv('ex1.csv', chunksize=1000) #返回的是一个可迭代对象
ck.get_chunk() #用get_chunk()方法可以持续迭代获取对象值
写入保存数据
data.to_csv("out.csv") #to_csv()保存数据
data.to_csv(sys.stdout, sep='|') #输出到屏幕
data.to_csv(sys.stdout, na_rep='NULL') #替换NaN值
data.to_csv(sys.stdout, index=False, header=False) #行和列的标签不会输出
data.to_csv(sys.stdout, index=False, columns=['a','b','c']) #指定输出列
csv使用方法
使用csv库导入数据,进行清理
import csv
with open("test.csv") as fp:
lines = list(csv.reader(fp))
csv方言选项
delimiter, 分隔字段字符,默认,逗号
lineterminator, 行终止符,默认\r\n,
quotechar, 引号字符
quoting, 默认QUOTE_MINIMAL,只使用特殊字符,比如分隔符,这个字段用途不详
skipinitialspace, 忽略每个分隔符后的空白
doublequote, 如何处理字段内部的引号,True表示双引号
escapechar, 转义字符
方言使用方法举例:
class my_dialect(csv.Dialect):
linetermianator = '\n'
delimiter = '"'
quoterchar = '"'
quoting = csv.QUOTE_MINIMAL
reader = csv.reader(f, dialect=my_dialect)
也可以直接使用方言关键字:
reader = csv.reader(f, delimiter='|')
对于更复杂的多字符分隔符,将无法直接使用csv,可以使用split或者正则表达式的re.split进行拆分和清洗
cs_writer()
writer = csv.writer(f, dialect=my_dialect)
writer.writerow(('1','2','3'))
JSON数据
JSON数据已经成为WEB浏览器和其他应用之间通过HTTP请求发送数据的标准格式
用法:
pd.read_json('test.json')
默认每一行为DataFrame的一行数据
pd_data.to_json('test.json')
将数据转化成json数据存储
XML和HTML
pandas.read_html依赖下面库:
1xml, beautifulsoup4, html5lib
默认行为
pandas.read_html默认读取html中的表中数据,转为DataFrame数据
html使用举例:
tables = pd.read_html('test.html')
header = talbes[0] #取头
date1 = pd.to_datetime(header['Closing Date']) #将列转化为日期时间格式
date1.dt.year.value_counts() #统计年个数
1xml使用举例:
from 1xml import objectify
parsed = objectify.parse(open('test.xml'))
root = parsed.getroot()
for elt in root.INDICATOR:
el_data = {}
for child in elt.getchildren()
if child.tag in skip_fields:
continue
el_data[child_tag] = child.pyval
data.append(el_data)
perf = pd.DataFrame(data)
二进制格式
pickle
frame1.to_pickle('out.pickle') #存储成pickle格式文件
pd.read_pickle('out.pickle') #读取pickle文件
pickle只适合用于临时存储,不适合长期存储,因为这个格式经常变化,导致无法反序列化
pandas支持的二进制还有
HDF5,
MessagePack,
bcolz, 基于Blosc压缩库的可压缩列式二进制格式
feather, R语言社区设计的跨语言列式文件格式
HDF5格式
用于存储大量科学数组数据,以C语言形式提供,具有多种语言接口,java、python都支持。
HDF表示分层数据格式,每个HDF5可以存储多个数据集,并支持元数据。
举例:
store = pd.HDFStore('my.h5')
store['obj1']=frame
store['obj1_co1']=frame['a']
store['obj1']
HDFStore支持2种存储模式,'fixed'和'table',后者速度慢,但支持一种特殊语法的查询操作
举例:
store.put('obj2', frame, format='table') #是store['obj2'] = frame的显式方法,但是允许设置参数
store.select('obj2', where=['index >= 10' and index <=15'])
读取:
frame.to_hdf('mydata.h5', 'obj3', format='table')
pd.read_hdf('mydata.h5', 'obj3', where=['index < 5'])
本地处理大量数据:
推荐:PyTables, h5py
远程服务器处理数据:
Apache Parquet
HDF5不是数据库,适合一次写入多次读取,多个写入者同时写入可能会破坏文件
excel文件
依赖库:
xlrd, openpyxl
举例:
ex=pd.ExcelFile('test.xlsx')
pd.read_excel(ex, 'Sheet1') #读取数据
或者
pd.read_excel('test.xlsx', 'Sheet1') #可以直接输入文件名读取
写入数据:
writer = pd.ExcelWriter('test.xlsx') #需要创建一个writer
frame.to_excel(writer, 'Sheet1')
writer.save()
或者
frame.to_excel('test.xlsx')
与WEB API交互
推荐库
requests
举例:
import requests
url = 'https://api.github.com/repos/pandas-dev/pandas/issues'
resp = requests.get(url)
data = resp.json() #resp有json方法可以直接转化成本地json数据
issues = pd.DataFrame(data, columns=['number', 'title', 'labels', 'state']) #可以直接转换成DataFrame数据
与数据库交互
pandas提供了read_sql函数,允许从通用的SQLAlchemy连接中轻松获得数据。
import sqlalchemy as sqla
db = sqla.create_engine('sqlite://mydata.sqlite')
pd.read_sql('select * from test', db)
数据清洗与准备
处理缺失值
pandasNA处理方法
dropna,
fillna, 用某些值填充NA,比如ffill,bfill
isnull, 返回BOOL类型
notnull, 同上
过滤缺失值,dropna
举例:
data = pd.Series([1,np.nan, 3.5, np.nan, 7])
data.dropna() #将返回没有NA的值与索引,NA值被抛弃
data1 = pd.DataFrame([[1,6.5,3], [1, np.nan, np.nan], [np.nan, np.nan, np.nan], [np.nan, 6.5, 3]])
data1.dropna() #默认只返回没有NA的行,所有包含NA的行都被删除
data1.dropna(how='all') #删除整行都是na的行,只要有一个非na值就不能删除
data1.dropna(how='all', axis=1) #对列进行操作
data1.dropna(thresh=2,axis=1) #thresh规定需要多少个非NA值,thresh=2表示非NA的值列要多于2个
补全缺失值,fillna
fillna参数
value, 用标量或字典类型对象填充缺失值
method, 插值方法,默认ffill
axis,默认0
inplace, 直接修改对象,而不形成新对象
limit, 和method配合,最大填充数
举例:
data1.fillna(0)
data1.fillna({1:0.5, 2:0}) #按列填充不同值
data1.fillna(0, inplace=True) #不返回新对象,在原data1上面直接修改
data1.fillna(data.mean()) #用平均值进行填充
数据转换
删除重复值,drop_duplicates
举例:
data2 = pd.DataFrame({'k1':['one','two']*3 + ['two'], 'k2':[1,1,2,3,3,4,4]})
data2.duplicated() #返回是否有重复值,从第二次观察到重复值开始算True
data2.drop_duplicates() #按行丢弃重复行
data2['v1']=range(7)
data2.drop_duplicates(['k1']) #针对k1列,对k1列中重复值丢弃,影响其他2列数据
data2.drop_duplicates(['k1','k2'], keep='last') #keep参数是保留最后观察到的数据,而不是默认第一次观察到的数据
使用函数或映射进行数据转换,map
使用map函数可以将数组元素转换成其他值,map函数可以接收字典、函数,用与元素转换
举例:
data3['animal'] = data3['food'].str.lower().map(meat_to_animal) #meat_to_animal是一个字典,用于元素转换
data3['food'].map(lambda x : meat_to_animal[x.lower()]) #利用函数方式完成元素转换
替代值, replace
举例:
data4 = pd.Series([1, -999, 2, -1000,3])
data4.replace([-999], np.nan) #将-999替换成NaN
data4.replace([-999,-1000], np.nan) #替换多个值
data4.replace([-999,-1000], [np.nan,0]) #通过列表替换
data4.replace({-999:0, -1000:1}) #通过字典替换
重命名轴索引,index, rename
举例:
data5.index = data5.index.map(lambda x : x[:4].upper()) #将轴索引重命名映射为其他值
data5.rename(index=str.title, columns=str.upper) #renanme可以对轴索引重新命名
data5.rename(index={'OHIO':'INDIANA'}, columns={'three':'peekaboo'}) #用字典方式进行替换
data5.rename(index={'OHIO':'INDIANA'}, columns={'three':'peekaboo'}, inplace=True) #在原有数据集上面修改
离散化和分箱, cut, qcut
举例:
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
cats = pd.cut(ages, [18, 25, 35, 60, 100]) #将ages按照给定区间进行划分,输出是一个Categories对象
cats.codes #返回属于哪一类的编码,默认从0、1、2.。。
cats.categories #返回类的列表,比如(18,25]
cats = pd.cut(ages, [18, 25, 35, 60, 100] , right=False) #加了right表示分类区间的右边是括号,而不是中括号
pd.value_counts(cats) #统计每一类的数量
cats = pd.cut(ages, [18, 25, 35, 60, 100], lables=['a','b','c','d']) #lables给每个区间起一个名字
data6 = np.random.rand(20)
pd.cut(data6, 4, precision=2) #如果不指定分箱规则,而仅仅指定箱子数量4,cut会平均进行分割,precision表示小数点精度
data7 = np.random.randn(1000)
cats = pd.qcut(data7, 4) #qcut是按照分位进行分割,即每个箱子里面的样本数是大体相等的,cut是按值进行划分,每个箱子的个数未知
pd.value_counts(cats) #会看到共4个箱子,每个箱子都是250个值
cats1 = pd.qcut(data7, [0, 0.1, 0.5, 0.9, 1]) #也可以自己定义分位数,这里最大和最小的都占10%,中间的各占40%样本
检测和过滤异常值, abs, sign
举例:
data8 = pd.DataFrame(np.random.randn(1000,4))
np.abs(data8) > 2 # 返回一个(1000,4)的BOOL型数组
(np.abs(data8) > 2).any(axis=1) #返回一个1000向量的一维BOOL型数组,一行中只要有一个是True,那么就返回True
data8[(np.abs(data8) > 2).any(axis=1)] #将一行中包含绝对值大于2的元素
data8[(np.abs(data8) > 2)] = np.sign(data8) * 2 #将大于2的值视为异常值,超过2的格式化为2,低于-2的格式化为-2
置换和随机抽样, permutation, take, iloc
举例:
df = pd.DataFrame(np.arange(20).reshape(5,4))
sampler = np.random.permutation(5) #返回array([4, 2, 1, 0, 3])一种排列
df.take(sampler) #随机排列5行数据
df.sample(3) #随机抽样3行
choices =pd.Series([5,7,-1,6,4])
draws = choices.sample(n=10, replace=Ture) #随机抽样10个,允许重复
计算指标,虚拟变量, get_dummies
可以将一列数据,按照值扩充为一个矩阵。将分类变量转换为伪/指示符变量。
举例:
df = pd.DataFrame({'key':['b','b','a','c','a','b'], 'data1': range(6)})
pd.get_dummies(df['key']) #会将key列的数据转化成一个二维数据,其中列是key列的值,行是0与1取值,一行中只有原数据中的值才取1,其他全0
dummies = pd.get_dummies(df['key'], prefix='key') #可以将列加上前缀
df[['data1']].join(dummies) #将2个DataFrame数组结合在一起
type(df['data1']) #pd.Series类型
type(df[['data1']]) #pd.DataFrame类型
pd.get_dummies(pd.cut(values, bins)) #get_dummies和cut结合使用方法
字符串操作
字符串内建处理方法
count
endswith
startswith
join
index
find
rfind
replace
strip, rstrip, lstrip
split
lower
uppper
casefold
ljust, rjust #左对齐、右对齐
contains,包含
正则表达式
方法:
findall, 返回列表
finditer,返回迭代器
match, 从起始位置开始匹配
search, 可以匹配任意位置,只返回一个匹配对象
split, 分拆
sub, 替换
subn, 替换第n次出现位置
过程:
python内建的re模块,会先根据patern编译,然后再执行匹配,替代,拆分等操作。
如果没有显式的执行re.compile动作,re也会自动先执行编译
通常流程都是
regex = re.compile(patern) #可以一次编译,多次使用,节约时间
regex.split(text)
举例:
re.split('\s+', text) #按照空格、制表符分隔文本
regex = re.compile('\s+')
regex.findall(text) #返回所有匹配值
regex = re.compile(r'c:\') #r意思是raw, 表示后面的字符串是原始字符串,里面没有转义字符,也就是里面的特殊字符不用转义
同
regex = re.compile('c:\\') #\\第一个是转义字符
转义字符是以‘\’为开头的字符,后面跟一个或几个字符,其意思是将反斜杠‘\’后面的字符转变成为另外的意义
m = regex.search(text) #返回的是一个匹配对象,主要包含下面的方法
m.start(),匹配的起始位置
m.end(), 匹配的结束位置,可以用text[m.start():m.end()]获取匹配的字符串
m.group(), 匹配的字符串
regex.sub("XXX", text) # 用XXX字符替换匹配的字符串
分组():
pattern = r'([A-Z]+)@([A-Z]+)\.([A-Z]{2,4})
regex = re.compile(pattern, flags=re.IGNORECASE) #flags可以忽略大小写
m = regex.match('[email protected]')
m.groups() #返回匹配到的三个分组
regex.findall() #会以元组形式返回所有匹配的对象
用\1 \2引用分组
pattern = r'([A-Z]+)@([A-Z]+)\.([A-Z]{2,4})
regex=re.compile(pattern, flags=re.IGNORECASE)
regex.sub(r'Username: \1, Domain: \2, suffix: \3', text) #会匹配字符串,然后替换,替换时会引用匹配到的分组,比如分组1会替换成Username: \1
pandas中的向量化字符串函数 pd.Series.str
data = pd.Series({'Dave': '[email protected]', 'steve':'[email protected]', 'Rob':'[email protected]', 'wes':np.nan})
data.str.contains('gmail') #返回Bool类型,判断元素是否包含gmail字符
data.str.findall(pattern, flags=re.IGNORECASE) #str函数调用re方法,返回的是Series类型
match = data.str.match(pattern) #返回一个BOOL类型的Series对象,表示是否匹配成功
字符串向量化函数
cat, 根据可选的分隔符按元素粘合字符串
contains, 包含关系,可以是正则表达式
count, 模式出现次数计数
extract, 使用正则表达式从字符串Series中分组抽取一个或多个字符串,返回的结果是每个分组形成的一列DataFrame
endswitch, 等于每个元素执行x.endwith模式
startswitch, 等价于每个元素执行x.startwith模式
findall, 列表返回
get, 对每个元素进行索引,获取第i个元素
isalnum,
isalpha
isdecimal
isdigit
islower
isnumeric
isupper
join
len
lower, upper,大小写转换
match
pad,将空白加到字符串左右或两边
center, 等价于pd(side='both')
repeat, 等价于x*3
slice, 进行切片
strip,对字符串两侧的空白进行消除,包括换行符
rstrip, 消除字符串右边空白
lstrip,消除字符串左边空白
数据规整:连接、联合、重塑
分层索引
data = pd.Series(np.random.randn(9), index=[[‘a’,‘a’, ‘a’, ‘b’, ‘b’, ‘c’, ‘c’, ‘d’, ‘d’], [1,2,3,1,3,1,2,2,3]])
data.index #返回的是一个MultiIndex索引
外层索引:
data['b']
data['b':'c']
data.loc[['b','c']]
内层索引:
data.loc[:,2]
数据重塑unstack()、stack()
data.unstack() #会根据2层索引形成一个DataFrame数据
data.unstack().stack() #stack将数据堆叠成多层索引
DataFrame的多层索引
frame = pd.DataFrame(np.arange(12).reshape((4,3)),
index=[['a', 'a', 'b', 'b'], [1,2,1,2]],
columns=[['Ohio', 'Ohio', 'Colorardo'], ['Green', 'REd', 'Green']])
DataFrame可以对每个轴进行多层索引。
frame.index.names=["key1", "key2"]
frame.columns.names=["state", "cloor"] #可以给每一层索引命名
frame['Ohio'] #列外层索引
frame.loc['key1'] #行外层索引
DataFrame的内层索引???
使用MultiIndex对象的构造方法直接创建多层索引
MultiIndex.from_array([['Ohio', 'Ohio', 'Colorardo'], ['Green', 'REd', 'Green']], names=["state", "cloor"])
重排序和层级排序, swaplevel, sort_index
swaplevel,可以将两个层级交换,接受两个层级名称或者索引
sort_index, 只能在单一层级对数据进行排序
举例:
frame.swaplevel('key1', 'key2')
frame.swaplevel(0,1) #和上面的等价,交换2层索引
frame.sort_index(level=0) #对层级0进行排序
按层级进行汇总统计
Series和DataFrame的统计函数的参数都有level可以进行汇总统计
举例:
frame.sum(level='key2') #在行上面,对列进行汇聚
frame.sum(level='cloor', axis=1) #对行进行汇聚
使用DataFrame的列进行索引, set_index, reset_index
可以将列与行索引进行互换,这里操作会形成新的对象
举例:
frame1.set_index(['c','d']) #将列索引c和d转换成行索引
frame.reset_index(["key1"]) #将行索引转换成列索引
frame.reset_index(["key1"], drop=False) #进行转换时,原来所在行的数据也不删除,仍保留
top1000.reset_index(inplace=True, drop=True) #当列上已经存在行的内容,会导致重复,此时加了drop=True可以保证丢弃已经存在的索引
联合与合并数据集
数据连接, pd.merge, join
pd.merge(df1, df2) #将2个DataFrame对象进行连接,不指定连接键时会自动使用相同名字的列名
pd.merge(df1, df2, on='key') #指定连接键
pd.merge(df1, df2, on='key', how='outer') #默认都是内连接就是取交集,可以通过how方法指定连接方法
连接方法how:
'inner', 内连接
'left', 左连接,对所有左表的键进行联合
'right', 右连接
'outer' ,两张表取并集
数据连接是行的笛卡尔积,第一个数组如果有3组,第二个数组有2组,那merge后就是6组
pd.merge(df1, df2, on=['key1', 'key2'], how='outer') #多键联合
pd.merge(left, right, on='key1', suffixes=('_left', '_right') #使用suffixes解决列重名情况
pd.merge参数列表
left, 左边DataFrame
right, 右边DataFrame
how,
on, 连接键
left_on, 左列键
right_on,右列键
left_index, 左行键
right_index, 右行键
sort, 默认是True,通过连接键字母顺序排序,在大数据集情况下关闭该功能会有性能改善
suffixes, 重叠情况下区分左右列名
copy, 默认True,总是复制。
indicator,添加一个特殊列,指示每一行的来源。值分别为'left_only', 'right_only", 'both'
根据索引index合并
pd.merge(left, right, left_on='key', right_index=True) #将列和行进行合并
pd.merge(left, right, left_on='key', right_index=True, how='outer') #外键联合
righth = pd.DataFrame(np.arange(12).reshape((6,2)),
index = [['Nevada', 'Nevada', 'Ohio', "Ohio", "Ohio", 'Ohio'],[2001,2000,2000,2000,2001,2002]],
columns = ['envent1', 'envent2'] )
pd.merge(lefth, righth, left_on=['key1', 'key2'], right_index=True) #列与行合并, 多重索引合并
pd.merge(lefth, righth, left_on=['key1', 'key2'], right_index=True, how='outer')
pd.merge(left, right, left_index=True, right_index=True) #行与行索引合并
left2.join(right2, how='outer') #join方法可以完成行索引的合并
left2.join([right2, another]) #join可以合并多个DataFrame对象
沿轴向连接,不合并, concat
举例:
Series对象:
pd.concat([s1, s2, s3]) #将3个Series对象连接成1个Series对象
pd.concat([s1, s2, s3] , axis=1) #在axis=1轴上拼接,输出一个DataFrame对象
pd.concat([s1, s2, s3] , axis=1, join='outer') #通过join完成连接
pd.concat([s1, s2, s3] , axis=1, join_axis=[['a', 'c', 'b', 'e']]) #指定连接轴,不在指定范围内的轴不连接
pd.concat([s1, s2, s3] , keys=['one', 'two', 'three']) #分别为s1,s2, s3加上一层索引,形成一个多层索引
pd.concat([s1, s2, s3] , keys=['one', 'two', 'three'], axis=1) #one,two,three会成为列索引
DataFrame对象:
pd.concat([df1,df2]) #将2个DataFrame连接,默认在行方向叠加
pd.concat([df1,df2], axis=1) #在列方向叠加,默认所有字段都会显示,不叠加
pd.concat([df1,df2], axis=1, keys=['level1', 'level2']) #分层索引
pd.concat({'level1':df1, 'level2':df2}, axis=1) #效果同上,用字典方式完成分层索引
pd.concat([df1,df2], axis=1, keys=['level1', 'level2'], names=['upper', 'lower']) #还可以给分层索引起一个名字
pd.concat([df1,df2], ignore_index=True) #ignore_index,忽略索引,新对象不继承老对象的索引,而形成新的索引
concat参数:
objs, 需要连接的对象
axis
join, 'inner'或'outer', 默认时outer
join_axis, 指定连接轴
keys, 指定分层索引名
levels, 指定多层索引的层级
names, 用于给keys和levels层级命名
verify_integrity, 检查连接对象中的新轴是否重复,如果是,则引发异常,默认时允许重复
ignore_index, 不沿着连接轴保存索引,而是产生新的索引
联合重叠数据:combine_first
将没有的数据合入进来,相当于用另一个数据集填充当前数据集的缺省值
举例:
df1.combine_first(df2)
重塑和透视
使用多层索引进行重塑,stack(堆叠),unstack(拆堆)
stack():该操作会“旋转”或将列中的数据透视到行
unstack():该操作会将行中的数据透视到列
举例:
data.unstack(0) #0表示把最外层透视到列上
result.unstack('number') #指定索引名进行透视
data.stack(dropna=False) #默认情况如果一列数据都是NaN,会自动不显示。dropna设置为False后,nan值也会显示
result.unstack('number') #拆堆后,number会变成最低一层索引
将长透视为宽, pivot(枢轴)
pivot等同于set_index创建分层索引然后调用unstack方法
作用:返回按给定索引/列值组织的重塑数据帧。
举例:
pivoted = data.pivot('data', 'item', 'value') #将data置为行索引, item置为列索引, value是填充值
将宽透视为长,pandas.melt
pandas.melt是pivot的逆操作
举例:
melted = pd.melt(df, ['key']) #行索引按照key列透视
pd.melt(df, id_vars=['key'], value_vars=['A', 'B']) #可以指定列的子集作为直列
pd.melt(df, value_vars=['A', 'B', 'C]) #也可以不指定任何分组
绘图和可视化
参考网址:
https://matplotlib.org/
matlab的可视化作品库和文档是好的学习材料
导入:
import matplotlib.pyplot as plt
%matplotlib notebook
图片和子图
matplotlib绘制的图片位于Figure对象中。
可以使用plt.figure生成一个新的图片
fig = plt.figure() #Ipython中会形成一个空白的窗口,Jupyter中则没有任何显示
figsize选项,设置图片大小,存储到硬盘时的长宽
ax1 = fig.add_subplot(2,2,1) #添加子图,共2*2个子图,这里添加第一个。我们不能直接在fig里面画图,需要先添加子图才能绘制
注意:绘制子图时会对整个图片重新绘制,建议一个图片的绘制放在一个Jupyter Notebook单元格中完成
举例:
fig = plt.figure()
ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
ax3 = fig.add_subplot(2,2,3)
plt.plot(np.random.randn(50).cumsum(), 'k--') #默认在最后创建的子图中绘制,这里就是在第3个子图中绘制
k--, 绘制黑色分段线的style选项
fig.add_subplot()返回的是AxesSubplot对象,可以直接调用这个对象进行绘图
ax1.hist(np.random.randn(100), bins=20, color='k', alpha=0.3) #直方图
ax2.scatter(np.arange(30), np.arange(30) + 3*np.random.randn(30)) #散点图
创建子图的2个方法:
方法1:
fig = plt.figure()
ax1 = fig.add_subplot(2,2,1)
方法2:
fig, axes = plt.subplots(2,3) #直接创建子图,返回一个2*3子图numpy.ndarray数组axes, 还有图片fig
plt.subplots()参数解释
nrows
ncols
sharex, 所有子图使用相同x轴刻度, 调整xlim会影响所有子图
sharey, 所有子图使用相同y轴刻度, 调整ylim会影响所有子图
subplot_kw, 传入add_subplot的关键字参数字典,用于生成子图
**fig_kw, 生成图片时使用的额外关键字参数,例如figsize=(8*6)
plt.subplot()作用同plt.subplots()都是切割子窗口
subplot(nrows, ncols, index, **kwargs) #图片切成nrow*ncols,当前使用index子窗口
subplot(pos, **kwargs) #类似221,表示切割成2*2,当前使用第1个索引
subplot(ax)
举例:
ax = plt.subplot(221+i) #
调整子图周围的间距
plt.subplots_adjust(wspace=0, hspace=0) #subplots_adjust是顶层方法,可以调整子图之间间隔的宽和高
颜色、标记、线类型
plt.plot(np.random.randn(30).cumsum(), 'ko--') #颜色、标记、线性的一种混合表示方法
plt.plot(np.random.randn(30).cumsum(), color='k', linestyle="--", marker='o') #显示标注法,效果同ko--
举例:
data = np.random.randn(30).cumsum()
plt.plot(data, 'k--', label='Default') #label添加标签
plt.plot(data, 'k--', drawstyle='steps-post', label='steps-post') #drawstyle,默认点与点之间是线性内插的,这里设置成台阶类型
plt.legend(loc='best') #legend解释图片,显示标签,规定位置。也可以使用ax.legend的轴引用的显示label
plt.legend(loc='best', ncol=4, mode="expand", shadow=True)
leg.get_frame().set_alpha(alpha) #获得legend对象可以进一步操作
刻度、标签、图例
图表装饰工作的两种方式:
1、使用程序性的pyplot接口,即matplotlib.pyplot
2、使用面向对象的原生matplotlib API
plt.xlim(ax.get_lim, ax_set_lim)
绘图范围
plt.xticks(ax.get_xticks, ax.set_xticks)
刻度位置
plt.xticklabels(ax.get_xticklabels, ax.set_xticklabels)
刻度标签
举例:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(np.random.randn(1000).cumsum())
ticks = ax.set_xticks([0,250,500,750,1000]) #设置x轴刻度
labels = ax.set_xticklabels(['one', 'two', 'three', 'four', 'five'], rotation=30, fontsize='small') #设置刻度标签,rotation标签旋转30度
ax.set_title('My first matplotlib plot') #设置图片标题
ax.set_xlabel('Stages') #设置x轴名称
直接利用字典和ax.set方法的关键字参数完成设置:
props = {'title':"My frist plot", 'xlable':'Stages'}
ax.set(**props)
y轴设置:将上述x换成y就可以
添加图例:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(np.random.randn(1000).cumsum(), 'k', label='one') #直接通过label
ax.plot(np.random.randn(1000).cumsum(), 'k--', label='two')
ax.plot(np.random.randn(1000).cumsum(), 'k.', label='three')
ax.legend(loc='best')
注释、子图加工
注释方法:
text
ax.text(50,20,'hello world', family='monospace', fontsize=10) #在(x,y)位置文件注释
arrow
annote
ax.annotate('test anno', xy=(500, 0), xytext=(500,10), arrowprops=dict(facecolor='black', headwidth=4, width=2, headlength=4),
horizontalalignment='left', verticalalignment='top') #箭头可以理解成从xytest 到 xy
matplotlib.patches 添加图形
举例:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
rect = plt.Rectangle((0.2,0.75), 0.4, 0.15, color='k', alpha=0.3) #长方形
circle = plt.Circle((0.7,0.2), 0.15, color='b', alpha=0.3) #圆形
pgon = plt.Polygon([[0.15, 0.15], [0.35, 0.4], [0.2, 0.5]], color='g', alpha=0.5) #三角形
ax.add_patch(rect)
ax.add_patch(circle)
ax.add_patch(pgon)
将图片保存到文件
fig=df.plot().get_figure()
fig.savefig('test.svg')
plt.savefig('test.svg')
两种方法都可以保存,后者会保存当前活动图片
保存参数:
fig.savefig('test.svg', dpi=400, bbox_inches='tight')
常见选项:
fname, 保存路径和文件名,文件类似是通过扩展名来自动识别的,如png、pdf
dpi, 每英寸点数分辨率,默认100
facecolor, edgecolor, 子图之外的图形背景颜色,默认白色'w'
format, 文件格式,png, pdf, svg, ps, eps
bbox_inches, 要保存的图片范围,如果是tight, 将会去除掉图片周围空白部分
matplotlib设置,rc方法
plt.rc('figure', figsize=(10,10)) #设置全局数字大小为10*10
第一个参数指定要修改的组件,比如figure, axes, xtick, ytick, grid, legend, font等等
利用字典方式设置
font_options = {'family' : 'monospace', 'weight': 'bold', 'size' : 'small'}
plt.rc('font', **font_options)
matplotlibrc通过该文件方式设置
Anaconda3\Lib\site-packages\matplotlib\mpl-data\matplotlibrc
将该文件放到HOME路径下的 .matpltlib时,每次使用matplotlib时候都会读取该文件
使用pandas和seaborn绘图
matplotlib是一个底层库,也可以使用pandas和seaborn库来绘图
seaborn网站:
https://seaborn.pydata.org/
折线图,plot()或者plot.line()
Series和DataFrame都一个plot属性,默认绘制折线图,即df.plot()等同于df.plot.line()
举例:
s = pd.Series(np.random.randn(10).cumsum(), index=np.arange(0,100,10))
s.plot()
df = pd.DataFrame(np.random.randn(10,4).cumsum(0), columns=['A', 'B', 'C', 'D'], index=np.arange(0,100,10))
df.plot() #每一列绘制一个折线图
Series.plot()参数:
label, 图例标签
ax, 绘图所用的matplotlib子图对象。如果缺省则使用当前活动的matplotlib子图
style, 传给matplotlib的样式字符串,比如'ko--'
alpha, 图片不透明度,从0到1
kind, 可以是'area', 'bar', 'barh', 'density', 'hist', 'kde', 'line', 'pie'
logy, 在y轴上使用对数缩放
use_index, 使用对象索引刻度标签
rot, 刻度标签旋转度数
xticks, 用于x轴刻度值
yticks, 用于y轴刻度值
xlim, x轴范围
ylim, y轴范围
grid, 展示轴网络,默认打开
这些参数默认是传给matplotlib
DataFrame.plot参数:
subplots, 将DataFrame的每一列绘制在独立的子图中
sharex, 如果subplots=True,则分享相同的x轴、刻度、范围
sharey, 如果subplots=True,则分享相同的y轴
figsize, 用于生成图片尺寸的元组
title, 标题字符串
legend, 添加子图图例,默认True
sort_columns, 按字母顺序绘制各列,默认情况使用已有的列顺序。
柱状图,plot.bar()和plot.barh()
plot.bar()
柱状图
plot.barh()
水平柱状图
举例:
Seires:
fig, axes = plt.subplots(2,1)
data = pd.Series(np.random.rand(16), index=list('abcdefghijklmnop'))
data.plot.bar(ax=axes[0], color='k', alpha=0.7)
data.plot.barh(ax=axes[1], color='k', alpha=0.7)
s.value_counts().plot.bar() #绘制分类聚集
DataFrame:
df = pd.DataFrame(np.random.rand(6,4), index=['one', 'two', 'three', 'four', 'five', 'six'],
columns=pd.Index(['A', 'B', 'C', 'D'], name='Genus'))
df.plot.bar() #name会被作为图例标题
df.plot.bar(stacked=True, alpha=0.5) #堆叠图
使用seaborn完成汇聚:
import seaborn as sns
sns.barplot(x='tip_pct', y='day', data=tips, orient='h') #水平直方图
sns.barplot(x='tip_pct', y='day', hue='time', data=tips, orient='h') #hue可以决定每组展示多少类数据
seaborn会自动改变图表美观性,如果需要自己改变可以使用下面方法
sns.set(style="whitegrid")
直方图和密度图, plot.hist, plot.kde
直方图是一种条形图,用于给出值频率的离散显示。
Seires:
s1.plot.hist(ax=axes, bins=50) #bins默认10,指定绘制多少个直方图,就是柱状图
密度图:也叫内核密度估计图(KDE)
s1.plot.density()
sns.distplot(values, bins=100, color='k') #distplot函数可以绘制直方图和连续密度估计
散点图和点图, seaborn.regplot
seaborn.regplot可以绘制散点图并拟合一个线性回归线
散点图:
sns.regplot('m1', 'unemp', data=trans_data) #绘制散点图并拟合线性回归线
成对图或散点图矩阵:
sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2}) #用于探索数据分析,能查看一组变量所有散点图
分面网格和分类数据, seaborn.factorplot
sns.factorplot(x='day', y='tip_pct', hue='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1])
按照col='smoker'的不同值进行分面网格显示
按照hue='time'用不同颜色显示柱组图
sns.factorplot(x='day', y='tip_pct', row='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1])
使用row参数添加行来扩展分面网格
sns.factorplot(x='day', y='tip_pct', kind='box', data=tips[tips.tip_pct < 1])
使用箱形图
seaborn.FacetGrid
可以使用该类创建自己的分面网格图
箱形图,boxplot
显示数据的基本统计量,中位数、平均数、四分位数等
其他Python可视化工具
web交互式图形,创建动态、交互式图像
Bokeh
http://bokeh.pydata.org
Plotly
https://github.com/plotly/plotly.py
静态图像:
matplotlib
pandas
seaborn
数据聚合和分组操作
GroupBy机制
拆分-应用-联合
拆分成组,每个组应用不同处理,将处理结果联合起来
举例:
df = pd.DataFrame({'key1':['a', 'a', 'b', 'b', 'a'],
'key2':['one', 'two', 'one', 'two', 'one'],
'data1': np.random.randn(5),
'data2':np.random.randn(5)})
grouped = df['data1'].groupby(df['key1']) #返回的grouped是一个SeriesGroupBy对象
grouped.mean() #均值, 返回data1列,按照key1列分组之后,每一组的均值
df['data1'].groupby([df['key1'], df['key2']]).mean() #两层分组
states=np.array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'])
years=np.array([2005,2005,2006,2005,2006])
df['data1'].groupby([states, years]).mean() #即使df中没有states和years列,也可以根据位置对应关系完成分组
df.groupby('key1').mean() #如果不指定列进行应用,就会自动应用所有适配的列中,这里就会直接应该到data1和data2列中,key2不是数值没有统计
df.groupby(['key1','key2']).mean() #2层索引
df.groupby(['key1','key2']).size() #size是组大小
迭代各分组
迭代Groupby
for name, group in df.groupby('key1'): #groupby对象支持迭代,返回(group_name, group_data)的元组
print(name)
print(group)
for (k1, k2), group in df.groupby(['key1', 'key2']): #多层分组迭代返回值((group_name1, group_name2), group_data)
print((k1,k2))
print(group)
list(df.groupby('key1')) #用列表形式返回分组名和数据
dict(list(df.groupby('key1')) #以字典形式返回{分组名:DataFrame类型group数据}
groupby默认是在axis=0轴上面分组,也可以在其他轴上面分组
grouped = df.groupby(df.dtypes, axis=1)
for dtype, group in grouped:
print(dtype)
print(group)
[]选择一列或所有列的子集
df.groupby('key1')['data1'].mean()
df.groupby('key1')[['data2']].mean()
是下面2个语句的语法糖:
df['data1'].groupby('key1').mean()
df['data2'].groupby('key1').mean() #可以直接用列名称选择一列的数据进行显示
多个键值也可以
df.groupby(['key1', 'key2'])['data1'].mean()
使用字典和Series分组:
people = pd.DataFrame(np.random.randn(5,5), columns=['a', 'b', 'c', 'd', 'e'], index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis'])
mapping = {'a':'red', 'b':'red', 'c':'blue', 'd':'blue', 'e':'red', 'f':'orange'}
by_column=people.groupby(mapping, axis=1)
by_column.sum() #按列进行分组,使用字典进行分组
map_series = pd.Series(mapping)
people.groupby(map_series, axis=1).count() #使用Series进行分组
使用函数分组:
people.groupby(len).sum() #通过len函数的返回值完成分组
key_list = ['one', 'one', 'one', 'two', 'two']
people.groupby([len, key_list]).min() #函数和列表混合分组。函数、数组、字典、Series都可以混合分组
根据索引层级分组
columns = pd.MultiIndex.from_arrays([['US', 'US', 'US','JP', 'JP'], [1,2,5,1,3]], names=['cty', 'tenor'])
hierf_df = pd.DataFrame(np.random.randn(4,5), columns=columns)
hierf_df.groupby(level='cty', axis=1).count() #可以直接传递层级名称或层级数值给level参数进行分组
数据聚合
常用的groupby聚合方法
count
sum
mean
median, 算术中位数
std, var,无偏的(n-1分母)标准差和方差
min, max
prod, 乘积
first, last, 第一个、最后一个值
其他聚合函数
df.groupby('key1')['data1'].quantile(0.9) #quantile分位数
df.groupby('key1')['data1'].describe() #描述函数
自定义聚合函数, agg或aggregate
举例:
def peak_to_peak(arr):
return arr.max() - arr.min()
df.groupby('key1')['data1'].agg(peak_to_peak)
逐列及多函数应用
df.groupby('key1').agg([peak_to_peak, 'mean', 'std']) #可以同时进行多个函数的聚合,注意自定义函数没有''符号,返回列名是聚合函数名称
df.groupby('key1').agg([('col1',peak_to_peak), ('col2','mean'),('col3', 'std')]) #通过(column_name, function)元组方式制定列名
func=[('col1',peak_to_peak), ('col2','mean'),('col3', 'std')]
df.groupby('key1').agg(func) #另一种多函数应用使用方式
func = {'data1':[('mea','mean')], 'data2':np.max}
df.groupby('key1').agg(func) #逐列应用不同的汇聚函数
返回不含行索引的聚合数据
去掉行索引,参数as_index=False
df.groupby('key1', as_index=False).mean() #因为默认行索引从0开始,这里就是不显示
应用:通过拆分-应用-联合, apply()
apply应用举例:
def top(df, n=2, column='data1'):
return df.sort_values(by=column)[-n:]
df.groupby('key1').apply(top) #top函数只要返回pandas对象或者标量值就行
df.groupby('key1').apply(top, 1, 'data1') #除了可以带函数,还可以带参数
实现原理
df.groupby('key1').describe()
实际内部实现方式如下:
f = lambda x : x.describe
df.groupby('key1').apply(f)
压缩分组键,group_keys=False
df.groupby('key1', group_keys=False).apply(top, 2, 'data1') #group_keys=False可以关闭分组,即不显示第一列的分组列,这里就是不显示key1分组
分位数和桶分析:cut,qcut
cut:每个桶的长度是一样的,但里面的数值个数不同
frame = pd.DataFrame({'data1':np.random.randn(1000), 'data2':np.random.randn(1000)})
quartiles=pd.cut(frame.data1, 4)
def get_stats(group):
return {'min':group.min(), 'max':group.max(), 'count':group.count(), 'mean':group.mean()}
frame.data2.groupby(quartiles).apply(get_stats).unstack()
quartiles是一个Series对象,可以用于groupby分组。
qcut:每个桶里面数值个数是相同的,但每个桶长度不同
qcut_quar = pd.qcut(frame.data1, 10, labels=False)
def get_stats(group):
return {'min':group.min(), 'max':group.max(), 'count':group.count(), 'mean':group.mean()}
frame.data2.groupby(qcut_quar).apply(get_stats).unstack()
示例:使用指定分组填充缺省值
states=['o','n','v','f','or','nv','ca','id']
data=pd.Series(np.random.randn(8), index=states)
group_key = ['East']*4 + ['West']*4
data['v','nv','id']=np.nan
data.groupby(group_key).mean()
fill_mean = lambda g: g.fillna(g.mean())
data.groupby(group_key).apply(fill_mean) #填充平均值
fill_values={'East':0.5, 'West':-1}
fill_func=lambda g:g.fillna(fill_values[g.name])
data.groupby(group_key).apply(fill_func) #按组填充不同的值
示例:随机采样与排列,sample
suits=['H', 'S', 'C', 'D']
card_val=(list(range(1,11)) + [10]*3)*4
base_names=['A'] + list(range(2,11)) + ['J', 'K', 'Q']
cards=[]
for suit in suits:
cards.extend(str(num) + suit for num in base_names)
deck = pd.Series(card_val, index=cards)
def draw(deck, n=5):
return deck.sample(n)
draw(deck) #使用Series.sample()抽取
get_suit = lambda card : card[-1]
deck.groupby(get_suit).apply(draw, n=2) #分组抽取
deck.groupby(get_suit, group_keys=False).apply(draw, n=2) #隐藏key分类
示例:分组加权平均和相关性
df = pd.DataFrame({'category':['a', 'b']*4, 'data':np.random.randn(8), 'weights':np.random.rand(8)})
grouped = df.groupby('category')
get_wavg=lambda g : np.average(g['data'], weights=g['weights']) #加权平均
grouped.apply(get_wavg)
spx_corr = lambda x : x.corrwith(x['SPX'])
rets = close_px.pct_change().dropna()
get_year = lambda x : x.year
by_year = rets.groupby(get_year)
by_year.apply(spx_corr)
by_year.apply(lambda g: g['AAPL'].corr(g['MSFT'])) #计算相关性,协方差
示例:逐组线性回归
import statsmodels.api as sm
def regress(data, yvar, xvars):
Y = data[yvar]
X = data[xvars]
X['intercept'] = 1
result = sm.OLS(Y, X).fit() #OLS最小二乘回归
return result.params
by_year.apply(regress, 'AAPL', ['SPX'])
数据透视表与交叉表
pivot_table
DataFrame有pivot_table方法可以完成数据透视功能,用groupby同样可以完成
举例:
df.pivot_table(index='category', margins=True, aggfunc=len, fill_value=0)
df.pivot_table(['data', 'weights'], index=['category'], columns='data')
pivot_table参数介绍:
data, 需要汇聚的表名称
values, 需要聚合的列名,默认聚合所有数值型的列
index, 透视表行上面的分组
columns, 透视表列上的分组键
aggfunc, 聚合函数,默认是mean平均值,可以是groupby的任意有效函数
fill_value, 替换NaN值
dropna, 如果为True,将不包含所有条目为NA的列
margins, 添加行、列的小计和总计
交叉表crosstab
crosstab也是形成数据透视表工具,尤其在频率统计方面比pivot_table要方便
pd.crosstab(data.Nationality, data.Handedness, margins=True) #第一个参数是行索引,第二个参数是列索引,列会分类显示统计
前2个参数可以是数组、Series、数组的列表
pd.crosstab([tips.time, tips.day], tips.smoker, margins=True) #行会分层显示
时间序列
日期和时间数据的类型及工具
常用的库有datetime, time, calendar模块
举例:
from datetime import datetime
now=datetime.now()
now.year
delta=datetime(2011,1,7) - datetime(2008,6,24,8,15)
delta.days
from datetime import timedelta
start = datetime(2011, 1,7)
start+timedelta(12) #时间可以加timedelta形成新的时间
datetime模块中类型
date
time
datetime
timedelta, 两个datetime之间的差
tzinfo, 时区信息
字符串与datetime信息互换
举例:
stamp=datetime(2011,1,3)
str(stamp)
stamp.strftime('%Y-%m-%d') #strftime把时间转换成格式化字符串
value='2011-01-03'
datetime.strptime(value, '%Y-%m-%d') #strptime将字符串转换成日期时间格式
datestrs=['7/6/2011', '8/6/2011']
[datetime.strptime(x, '%m/%d/%Y') for x in datestrs]
stamp.strftime('%c')
返回:'Mon Jan 3 00:00:00 2011'
datetime格式说明
%Y, 四位年份
%y, 两位年份
%m, 两位月份
%d,两位日期
%H, 24制小时
%I, 12制小时
%M, 两位分钟
%S, 秒
%w, 星期
%U, 一年中星期数[00,53],以星期日为每周第一天,一年中第一个星期日前的日期为第0周
%W, 同上,以星期一为每周第一天
%z, 格式为+HHMM或-HHMM的UTC时区偏移,如果没有时区则为空
%F, %Y-%m-%d简写
%D, %m/%d/%y简写
datetime特定地区日期格式化选项
%a, 缩写的工作日名称,星期几
%A, 全写的工作日名称,星期几
%b, 简写月份名称
%B, 全写月份名称
%c,完整的日期和时间
%p, AM或PM
%x, 适合地区的格式化日期
%X, 适合地区的格式化时间
第三方库dateutil
datetime解析时间需要输入固定的格式,而dateutil可以自动识别大部分字符串日期格式
举例:
from dateutil.parser import parse
parse("2011-01-03") #返回datetime对象
parse('Jan 31, 1997 10:45 PM')
parse('6/12/2011', dayfirst=True) #日期在前是可以指定dayfirst为True
pandas.to_datetime()日期转换
举例:
datestrs=['2011-07-06 12:00:00', '2011-08-06 00:00:00']
pd.to_datetime(datestrs)
返回:DatetimeIndex(['2011-07-06 12:00:00', '2011-08-06 00:00:00'], dtype='datetime64[ns]', freq=None)
pd.to_datetime(datestrs + [None]) #缺失值情况,返回的缺失值是NaT
返回:DatetimeIndex(['2011-07-06 12:00:00', '2011-08-06 00:00:00', 'NaT'], dtype='datetime64[ns]', freq=None)
时间序列基础
举例:
dates=[datetime(2011,1,2), datetime(2011,1,5), datetime(2011,1,7), datetime(2011,1,8), datetime(2011,1,10), datetime(2011, 1,12)]
ts = pd.Series(np.random.randn(6), index=dates)
ts.index
ts.index.dtype #dtype('
高阶pandas
分类数据, Categorical
将数据转换为分类数据可以产生大幅的性能提升。DataFrame中的一列的分类版本通常也会明显使用更少内存。
使用category进行groupby速度更快,因为底层算法使用了基于整数代码的数组而不是字符串数组
take, unique, value_counts
values = pd.Series([0,1,0,0]*2)
dim = pd.Series(['apple', 'orange'])
dim.take(values) #take会形成类似字典方式,把values和dim进行一一对应
pd.unique(values) #去重
pd.value_counts(values) #计算每类数量
pandas中Categorical类型
Categorical类型,用于承载基于整数的类别展示或编码的数据
分类数据可以是任意不可变类型
举例:
fruits = ['apple', 'orange', 'apple', 'apple']*2
N = len(fruits)
df = pd.DataFrame({'fruits':fruits, 'basket_id':np.arange(N), 'count':np.random.randint(3,15,size=N), 'weight':np.random.uniform(0,4,size=N)},
columns=['basket_id', 'fruits', 'count', 'weight'])
fruit_cat = df['fruits'].astype('category') #返回的是pandas.category
c = fruit_cat.values #Categorical类型
c.categories #分类
c.codes #分类编码
df['fruits'] = df['fruits'].astype('category') #将一列数据转换为Categorical对象
my_categories = pd.Categorical(['foo', 'bar', 'bar', 'foo', 'bar']) #直接构建category类型
categories = ['foo', 'bar', 'baz']
codes = [0, 1, 2, 0, 0, 1]
my_cats_2 = pd.Categorical.from_codes(codes, categories) #使用from_codes构建category,对应关系不固定
my_cats_2.as_ordered() #排序分类
my_cats_2 = pd.Categorical.from_codes(codes, categories, ordered=True) #指定分类排序
使用Categorical对象进行计算
qcut
np.random.seed(12345)
draws = np.random.randn(1000)
bins = pd.qcut(draws, 4, labels=['01', '02', '03', '04']) #同时指定箱子名称
bins.codes[:10]
bins = pd.Series(bins, name='quartile')
results = (pd.Series(draws).groupby(bins).agg(['count', 'min', 'max']).reset_index())
使用分类节俭内存
N=10000000
draws=pd.Series(np.random.randn(N))
lables = pd.Series(['foo', 'bar', 'baz', 'qux'] * (N//4))
categories = lables.astype('category')
lables.memory_usage() >> categories.memory_usage() #没有分类的比分类的内存占用多了8倍
分类方法:
分类数据有些自己的方法
举例:
s = pd.Series(['a', 'b', 'c', 'd']*2)
cat_s = s.astype('category')
cat_s.cat.codes #cat这个属性提供了对分类方法的访问
改变类别:
cat_s2 = cat_s.cat.set_categories(['a', 'b','c', 'd', 'e'])
虽然数据没有改变,但是类别多了一个‘e'
移除未观测到的类
cat_s2.cat.remove_unused_categories()
只会保留有数值的类,没有数值的类会被移除
Series的分类方法:
add_categories, 将新的类别(未使用过的)添加到已有类别的尾部
as_ordered, 对类别排序
as_unordered, 使类别无序
remove_categories, 去除类别,将被没有类别的值对应的类置为NaN
remove_unused_categories, 去除所有没有值的类别
rename_categories, 使用新的类别名称替代现有的类别,不会改变类别的数量
reorder_categories, 与rename_categories类似,结果是经过排序的类别
set_categories, 用指定一组新类别替换现有类别,可以添加和删除
创建用于建模的虚拟变量:
pd.get_dummies(cat_s) #可以创建一个类似one-hot编码的DataFrane数据
高阶GroupBy应用:
分组转换和’展开‘GroupBy, transform
举例:
df = pd.DataFrame({'key':['a', 'b', 'c']*4, 'value':np.arange(12.)})
g=df.groupby('key')
g.transform(lambda x : x.mean()) #返回的大小同df.value, 每个分组的值都会被该组的平均值替代
g.transform('mean') #对于內建函数,作用同上
g.transform(lambda x : x*2)
g.transform(lambda x: x.rank(ascending=False)) #分组排序,这里返回的是排名名次
transform 同 apply, 对可以使用的函数种类有更多限制:
1、transform可以产生一个标量值,并广播到各分组的尺寸数据中
2、transform可以产生一个与输入分组尺寸相同的对象
3、transform不可以改变它的输入
分组的时间重新采样
举例:
N=15
times=pd.date_range('2017-05-20 00:00', freq='1min', periods=N)
df=pd.DataFrame({'time':times, 'value':np.arange(N)})
df.set_index('time').resample('5min').count()
方法链技术
方法链的主要目的是减少临时变量的使用量
assign赋值方式
df['key'] = value #这种是在原对象上面修改
assign('key', value) #形成一个新对象,assign赋值可以完成方法链功能
Python建模库介绍
statsmodels, scikit-learn
patsy
pandas与建模代码的结合
特征工程:从原生数据集中提取可用于模型上下文的有效信息的数据转换过程或分析。
pandas与NumPy数组的转换:
pandas和其他分析库的结合通常是NumPy数组。
将DataFrame转换为NumPy:
df_data.values #一般在数据都是同构情况下使用,不然会返回的将是python object对象
df_data.loc[:,['x0', 'x1']].values #如果存在异构数据时,可以仅提取部分列进行转换
将NumPy转换为DataFrame:
df2=pd.DataFrame(data.values, columns=['one', 'two', 'three'])
虚拟变量处理:
解决非数据类型的变量,将之转化成数据类型变量
data['category']=pd.Categorical(['a', 'b', 'a', 'a', 'b'], categories=['a', 'b'])
dummies = pd.get_dummies(data.category, prefix='category')
data_with_dummies = data.drop('category', axis=1).join(dummies) #将新增加的非数值类型列,转化成2列数值型列
使用Patsy创建模型描述
y, x=patsy.dmatrices('y ~ x0 + x1', data) #返回2个数组,第一个是data.y, 第二个是data.x0和data.x1,并且还加了一列Intercept列
np.asarray(x) #转换成numpy数组
y, x=patsy.dmatrices('y ~ x0 + x1 +0', data) #+o, 添加名词列来加入截距, 返回的y不变,x将仅剩2列了
patsy对象可以直接传给一些算法,比如numpy.linalg.lstsq等,这些算法都会执行一个最小二乘回归
coef, resid, _, _ = np.linalg.lstsq(x,y)
design_info
模型元数据都保留在design_info中,可以通过x.design_info访问
x.design_info.column_names
Patsy公式中的数据转换
y,x = patsy.dmatrices('y ~ x0 + np.log(np.abs(x1)+1)', data) #可以将python代码混合到patsy公式中
y,x = patsy.dmatrices('y ~ standardize(x0) + center(x1)', data) #patsy内置函数:标准化(对均值0和方差1)和居中(减去平均值)
new_data = pd.DataFrame({'x0':[6,7,8,9], 'x1':[3.1,-0.5, 0,2.3], 'y':[1,2,3,4]})
nex_x = patsy.build_design_matrices([x.design_info], new_data) #build_design_matrices可以将已有模型套用到其他数据上面
加法运算:
patsy公式中的+不是真的加法,而是列的拼接。如果要执行加法运算,需要将列名封装到特殊的I函数中。
y, x=patsy.dmatrices('y~ I(x0+x1)', data)
patsy.buildins模块中有內建函数可用
分类数据与Patsy
举例:
data = pd.DataFrame({
'key1':['a', 'a', 'b', 'b', 'a', 'b', 'a', 'b'],
'key2':[0,1,0,1,0,1,0,0],
'v1':[1,2,3,4,5,6,7,8],
'v2':[-1,0,2.5,-0.5,4.0,-1.2, 0.2, -1.7]
})
y,x=patsy.dmatrices('v2 ~ key1', data) #对于字符列key1,会自动构建虚拟变量
y,x=patsy.dmatrices('v2 ~ key1 + 0', data) #不显示截距时,就会显示多列虚拟变量
y,x=patsy.dmatrices('v2 ~ C(key2) + 0', data) #对于数字类型,可用使用C函数解释为分类类型
data['key2']=data['key2'].map({0:'zero', 1:'one'}) #
y,x=patsy.dmatrices('v2 ~ key1 + key2', data)
y,x=patsy.dmatrices('v2 ~ key1 + key2 + key1:key2', data) #key1:key2理解为同时满足2个条件的布尔值类型
statsmodels
用于拟合多种统计模型,执行统计测试以及数据探索和可视化,包含更多经典频率学派统计方法。
贝叶斯方法和机器学习模型可以在其他库中找到
包含在statesmodels中的一些模型
线性模型,广义线性模型和鲁棒线性模型
线性混合效应模型
方差分析(ANOVA)方法
时间序列过程和状态空间模型
广义的矩量法
评估线性模型
statemodel中的线性模型有两个不同的主要接口:基于数组的和基于公式的。这些接口通过下面API模块导入访问:
import statsmodels.api as sm
import statsmodels.formula.api as smf
举例:
def dnorm(mean, variance, size=1):
if isinstance(size, int):
size = size
return mean + np.sqrt(variance)*np.random.randn(size)
np.random.seed(12345)
N=100
x=np.c_[dnorm(0,0.4,size=N),
dnorm(0,0.6,size=N),
dnorm(0,0.2,size=N)]
eps=dnorm(0,0.1,size=N)
beta=[0.1,0.3,0.5]
y=np.dot(x, beta)+eps
x_model = sm.add_constant(x) #add_constant 添加类似patsy的截距,添加一列截距到现有矩阵
model = sm.OLS(y,x) #OLS类可以拟合一个最小二乘线性回归
results= model.fit() #fit方法返回一个回归结果
results.params #返回拟合的结果
results.summary() #summary可以打印出一个模型的诊断细节
data = pd.DataFrame(x, columns=['col0', 'col1', 'col2'])
data['y'] = y
results=smf.ols('y ~ col0 + col1 + col2', data=data).fit() #用patsy公式
results.params
results.tvalues
results.predict(data[:5]) #给定新的样本数据后,可以根据估计的模型参数计算预测值
评估时间序列处理
时间序列分析:自回归过程,卡尔曼滤波, 其他状态空间模型, 多变量自回归模型
举例:
init_x = 4
import random
values = [init_x, init_x]
N=1000
b0=0.8
b1=-0.4
noise=dnorm(0,0.1,N)
for i in range(N):
new_x=values[-1]*b0 + values[-2]*b1+noise[i]
values.append(new_x)
MAXLAGS=5
model=sm.tsa.AR(values)
results=model.fit(MAXLAGS)
results.params
scikit-learn
通用机器学习库,包含广泛的标准监督和无监督,包括用于模型选择和评估、数据转换、数据加载、模型持久化的工具。
这些模型可以用于分类、聚类、预测和其他常见任务
举例:
train =pd.read_csv('datasets/titanic/train.csv')
test=pd.read_csv('datasets/titanic/test.csv')
train.isnull().sum()
test.isnull().sum()
impute_value = train['Age'].median()
train['Age'] = train['Age'].fillna(impute_value)
test['Age'] = test['Age'].fillna(impute_value)
train['IsFemale'] = (train['Sex'] == 'female').astype(int)
test['IsFemale'] = (test['Sex'] == 'femalte').astype(int)
predictors = ['Pclass', 'IsFemale', 'Age']
x_train = train[predictors].values
x_test = test[predictors].values
y_train = train['Survived'].values
from sklearn.linear_model import LogisticRegress
model = LogisticRegression()
model.fit(x_train, y_train)
y_predict = model.predict(x_test)
(y_true == y_predict).mean()
from sklearn.linear_model import LogisticRegressionCV
moel_cv = LogisticRegressionCV(10)
model_cv.fit(x_train, y_train)
from sklean.model_selection import creoss_val_score
model = LogisticRegression(C=10)
scores = cross_val_score(model, x_train, y_train,cv=4)
你可能感兴趣的:(数据分析,python,numpy)