1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 《利用python进行数据分析》读书笔记

《利用python进行数据分析》读书笔记

时间:2023-09-26 15:21:57

相关推荐

《利用python进行数据分析》读书笔记

《利用python进行数据分析》是一本利用python的Numpy、Pandas、Matplotlib库进行数据分析的基础介绍,非常适合初学者。

重要的python库

NumPy

Pandas

matplotlib

IPython 和 Jupyter

Scipy

scikit-learn

http://scikit-

statsmodels

nbviewer

/

软件安装和环境配置:

安装Anaconda:/

下载安装包或者pip install jupyter notebook

Jupyter notebook用法:

内省

?, 对象前后加?号可以显示对象概要信息,针对魔术字也是生效的,即可以查看魔术字的参数

??, 使用??可以显示函数源码

?,可以作为通配符使用,与*结合可以查询符合规范的名称

Ipython magichttps://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, 在新的调试器中调用语句statementl statement, 显示当前堆栈的当前位置和上下文w, where意思,在当前位置打印带有上下文的完整堆栈回溯h, help显示命令列表help command, 显示command命令的文档q,quit退出调试器%run -d test.py, 可以直接进入调试器%run -d b2 test.py, 加断点pdb.set_tracefrom IPython.core.debugger import Pdbdef set_trace():Pdb(color_scheme="Linux").set_trace(sys.__getgrame().f_back)可以在程序任何地方调用set_trace(),比如在抛出异常前调用,可以进入调试模式pdb.runcallfrom IPython.core.debugger import Pdbdef debug(f, *args, **kwargs):pdb = Pdb(color_scheme="Linux")return pdb.runcall(f, *args, **kwargs)可以单独调试一个函数def f(x, y, z=1):return (x+y)/zdebug(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_libimport importlibimportlib.reload(som_lib)Ipython有个dreload(some_lib)可以用代码设计技巧扁平优于嵌套适当的大文件比零散的多个小文件好管理配置文件:ipython profile create #可以形成ipython配置文件文件路径C:\\Users\\guangxinwang\\.ipython\\profile_default\\ipython_config.py也可以创建一个新的配置文件,并自己使用:ipython profile create secret_projectipython --profile=secret_projectjupyter notebook的配置文件:jupyter notebook --generate-config默认路径.jupyter/jupyter_notebook_config.pyjupyter notebook --config=~/.jupyter/my_custom_config.py配置内容摘要有:主题启动扩展模块等自定义魔术函数等

NumPy基础:数组和向量化计算

NumPy的重要性:

1、NumPy的设计对于含有大量数组的数据非常有效;

2、NumPy在内部将数据存储在连续的内存块上,NumPy的算法库是C语言写的,不需要任何类型检查。而且占用的内存量也小

3、NumPy可以针对全部数组进行复杂计算而不需要写python循环

导入:推荐import numpy as npNumPy的核心——N维数组对象ndarray一个ndarray是一个通用的多维同类数据容器,即它包含的每一个元素都是相同类型属性:shape表示ndarray的维度dtype表示ndarray的数据类型,ndarray的默认数据类型是float64ndim表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同所给数组,值全1zeros, 全零数组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类型转换方法astypemy_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,-1cell,最高整数,遇到小数往上取整floor,往下取整rint,保留整数位,且保留dtypemodf, 分别返回小数和整数部分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就为Trueall(),所有为True才为True排序sort(),可以沿着axis排序如sort(0)就是沿着x轴对y轴进行排序,就是只对y轴排序唯一值np.unique()针对一维数组,返回的是去重后的数组,并且还完成排序np.in1d(arr1, arr2)判断数组1中值是否在数组2中,返回bool类型的数组,长度同arr1intersect1d(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',)默认都是二进制形式存取的文件后缀默认是npynp.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 pltnsteps = 1000draws = np.random.randint(0, 2, size=nsteps) #从0,1中随机抽取1000次steps = np.where(draws > 0 , 1, -1) #把0,1格式化成-1和1walk = steps.cumsum() #对数组做累计求和plt.plot(walk) #打印折线图walk.min() #求连续走最小或最大步数(np.abs(walk) >= 10).argmax() #求第一次连续一个方向走10步的位置举例2:nwalks = 5000nsteps = 1000draws = 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和Falsecrossing_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, 按行堆叠,沿轴0hstack, 按列堆叠colum_stack, 类似hstack,但会先把一维数组转换为2维列向量dstack, 按深度堆叠数组,沿着轴2split, 沿指定轴分隔数组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)数组,类似vstacknp.c_[np.r_[arr1,arr2], arr] #返回一个(6,3)数组,类似hstack 数据重复repeatarr.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区别是前者是将整个数组作为一个整体进行复制,而后者是对每个元素进行复制。所以后者重复的行或列会连续出现,而前者是间隔出现神奇索引等价操作taketake可以根据索引取对应轴的数据比如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.newaxisreshape可以加一个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所有元素将全部赋值为5col = np.array([1,2,3,4])arr[:] = col[:, np.newaxis] #col[:, np.newaxis]可以转为(4,1)数组, arr[:]索引全部列,最终arr所有3列的值相同都是1、2、3、4arr[: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 + yadd_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'速度最快不稳定OO(n^2)'mergesort'速度中等稳定n/2O(n log n)'heapsort'速度低不稳定 OO(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库建议好好研究下,该库使用LLVM将python代码编译成机器码,大大加快python执行速度举例1:from numba import vectorize@vectorizedef 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()高阶数组的输入和输出内存映射文件mmapmmap = 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 * 2np.exp(obj)字典类操作:另外,因为Series很像字典的key:value结构,所以字典的一些操作也适用于Series'b' in objobj = pd.Series({'a':'ohio', 'b':'texas', 'c':'utah'}生成的Series是按照字典key排序后的序列,如果想指定索引顺序,可以在Series构造时传入index=参数 NaNpanda表示缺失值Not a Numberpandas使用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, , , ],'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,行会使用嵌套字典的keyframe = 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.Seriesframe.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, 如果索引序列递增返回Trueis_unique, 如果索引序列唯一则返回Trueunique, 计算索引的唯一值序列筛选df[df['D'] > 0] #筛选D列大于0df[(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], 可以选择单列、多列、通过布尔数组过滤行、对行切片、布尔值DataFramedf.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, rsubdiv, rdivfloordiv, rfloordiv, #整除//mul, rmulpow, rpowDataFrame和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' %xframe.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.02 6.53 4.54 3.05 2.06 4.5obj.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值了。归约方法的常用参数:axisskipnalevel, 如果轴是多层索引的,该参数可以缩减分组层级描述性统计与汇总统计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元素替换成NaNread_csv/read_table函数参数path sep/delimiter, 分隔符或正则表达式header, 列名,默认第一行index_col, 用列名对行做分层显示names, 和header=None一起使用,指定表头skiprows, 跳过指定行na_values, 需要用NA替换的值序列comment, 在行结尾处分隔注释的字符,比如#符号parse_dates, 将数据解析成日期时间格式,默认是False。如果是True,可以解析所有列,或指定列号或列名的列表。会把多个列一起解析,比如Date+timekeep_date_col, 如果连接列到解析日期上,保留被连接的列,默认Falseconverters, 将列名称映射到函数。比如{'foo':fuc}就是把func函数映射到foo列dayfirst, 按June 7, 解析日期date_parser, 用于解析日期的函数nrows, 从文件开头处读入的行数iterator, 返回一个TextParser对象,用于零散的读入文件chunksize, 用于迭代的块大小skip_footer, 忽略文件尾部的行数verbose, 打印详细输出encoding, 编码方式squeeze, 如果解析数据只包含一列,返回Seriesthousands, 千位分隔符分块读入文本文件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 csvwith 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_MINIMALreader = 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和HTMLpandas.read_html依赖下面库:1xml, beautifulsoup4, html5lib默认行为pandas.read_html默认读取html中的<table>表中数据,转为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 objectifyparsed = 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.pyvaldata.append(el_data)perf = pd.DataFrame(data)二进制格式pickleframe1.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']=framestore['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 ParquetHDF5不是数据库,适合一次写入多次读取,多个写入者同时写入可能会破坏文件excel文件依赖库:xlrd, openpyxl举例:ex=pd.ExcelFile('test.xlsx') pd.read_excel(ex, 'Sheet1') #读取数据或者 pd.read_excel('test.xlsx', 'Sheet1') #可以直接输入文件名读取写入数据:writer = pd.ExcelWriter('test.xlsx') #需要创建一个writerframe.to_excel(writer, 'Sheet1')writer.save()或者frame.to_excel('test.xlsx')与WEB API交互推荐库requests举例:import requestsurl = '/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个补全缺失值,fillnafillna参数value, 用标量或字典类型对象填充缺失值method, 插值方法,默认ffillaxis,默认0inplace, 直接修改对象,而不形成新对象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() #返回是否有重复值,从第二次观察到重复值开始算Truedata2.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替换成NaNdata4.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,那么就返回Truedata8[(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,其他全0dummies = 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结合使用方法字符串操作字符串内建处理方法countendswithstartswithjoinindexfindrfindreplacestrip, rstrip, lstripsplitlowerupppercasefoldljust, rjust #左对齐、右对齐contains,包含正则表达式方法:findall, 返回列表finditer,返回迭代器match, 从起始位置开始匹配search, 可以匹配任意位置,只返回一个匹配对象split, 分拆sub, 替换subn, 替换第n次出现位置过程:python内建的re模块,会先根据patern编译,然后再执行匹配,替代,拆分等操作。如果没有显式的执行pile动作,re也会自动先执行编译通常流程都是regex = pile(patern) #可以一次编译,多次使用,节约时间regex.split(text) 举例:re.split('\s+', text) #按照空格、制表符分隔文本regex = pile('\s+')regex.findall(text) #返回所有匹配值regex = pile(r'c:\') #r意思是raw, 表示后面的字符串是原始字符串,里面没有转义字符,也就是里面的特殊字符不用转义同regex = pile('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 = pile(pattern, flags=re.IGNORECASE) #flags可以忽略大小写m = regex.match('www@')m.groups() #返回匹配到的三个分组regex.findall() #会以元组形式返回所有匹配的对象用\1 \2引用分组pattern = r'([A-Z]+)@([A-Z]+)\.([A-Z]{2,4})regex=pile(pattern, flags=re.IGNORECASE)regex.sub(r'Username: \1, Domain: \2, suffix: \3', text) #会匹配字符串,然后替换,替换时会引用匹配到的分组,比如分组1会替换成Username: \1pandas中的向量化字符串函数 pd.Series.strdata = pd.Series({'Dave': 'dave@', 'steve':'steve@', 'Rob':'rob@', '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中分组抽取一个或多个字符串,返回的结果是每个分组形成的一列DataFrameendswitch, 等于每个元素执行x.endwith模式startswitch, 等价于每个元素执行x.startwith模式findall, 列表返回get, 对每个元素进行索引,获取第i个元素isalnum, isalphaisdecimalisdigitislowerisnumericisupperjoinlenlower, upper,大小写转换matchpad,将空白加到字符串左右或两边center, 等价于pd(side='both')repeat, 等价于x*3slice, 进行切片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_indexswaplevel,可以将两个层级交换,接受两个层级名称或者索引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, joinpd.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, 左边DataFrameright, 右边DataFramehow, 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, 需要连接的对象axisjoin, 'inner'或'outer', 默认时outerjoin_axis, 指定连接轴keys, 指定分层索引名levels, 指定多层索引的层级names, 用于给keys和levels层级命名verify_integrity, 检查连接对象中的新轴是否重复,如果是,则引发异常,默认时允许重复ignore_index, 不沿着连接轴保存索引,而是产生新的索引联合重叠数据:combine_first将没有的数据合入进来,相当于用另一个数据集填充当前数据集的缺省值举例:bine_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.meltpandas.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]) #也可以不指定任何分组

绘图和可视化

参考网址:

/

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, 还有图片figplt.subplots()参数解释nrowsncolssharex, 所有子图使用相同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的轴引用的显示labelplt.legend(loc='best', ncol=4, mode="expand", shadow=True)leg.get_frame().set_alpha(alpha) #获得legend对象可以进一步操作刻度、标签、图例图表装饰工作的两种方式:1、使用程序性的pyplot接口,即matplotlib.pyplot 2、使用面向对象的原生matplotlib APIplt.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') #直接通过labelax.plot(np.random.randn(1000).cumsum(), 'k--', label='two')ax.plot(np.random.randn(1000).cumsum(), 'k.', label='three')ax.legend(loc='best') 注释、子图加工注释方法:textax.text(50,20,'hello world', family='monospace', fontsize=10) #在(x,y)位置文件注释arrowannoteax.annotate('test anno', xy=(500, 0), xytext=(500,10), arrowprops=dict(facecolor='black', headwidth=4, width=2, headlength=4), horizontalalignment='left', verticalalignment='top') #箭头可以理解成从xytest 到 xymatplotlib.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、pdfdpi, 每英寸点数分辨率,默认100facecolor, edgecolor, 子图之外的图形背景颜色,默认白色'w'format, 文件格式,png, pdf, svg, ps, epsbbox_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网站:/折线图,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到1kind, 可以是'area', 'bar', 'barh', 'density', 'hist', 'kde', 'line', 'pie'logy, 在y轴上使用对数缩放use_index, 使用对象索引刻度标签rot, 刻度标签旋转度数xticks, 用于x轴刻度值yticks, 用于y轴刻度值xlim, x轴范围ylim, y轴范围grid, 展示轴网络,默认打开这些参数默认是传给matplotlibDataFrame.plot参数:subplots, 将DataFrame的每一列绘制在独立的子图中sharex, 如果subplots=True,则分享相同的x轴、刻度、范围sharey, 如果subplots=True,则分享相同的y轴figsize, 用于生成图片尺寸的元组title, 标题字符串legend, 添加子图图例,默认Truesort_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 snssns.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.regplotseaborn.regplot可以绘制散点图并拟合一个线性回归线散点图:sns.regplot('m1', 'unemp', data=trans_data) #绘制散点图并拟合线性回归线成对图或散点图矩阵:sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2}) #用于探索数据分析,能查看一组变量所有散点图分面网格和分类数据, seaborn.factorplotsns.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交互式图形,创建动态、交互式图像BokehPlotly/plotly/plotly.py静态图像:matplotlibpandasseaborn

数据聚合和分组操作

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([,,,,])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是组大小迭代各分组迭代Groupbyfor 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聚合方法countsummeanmedian, 算术中位数std, var,无偏的(n-1分母)标准差和方差min, maxprod, 乘积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=Falsedf.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.describedf.groupby('key1').apply(f)压缩分组键,group_keys=Falsedf.groupby('key1', group_keys=False).apply(top, 2, 'data1') #group_keys=False可以关闭分组,即不显示第一列的分组列,这里就是不显示key1分组分位数和桶分析:cut,qcutcut:每个桶的长度是一样的,但里面的数值个数不同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']*4data['v','nv','id']=np.nandata.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) #按组填充不同的值示例:随机采样与排列,samplesuits=['H', 'S', 'C', 'D']card_val=(list(range(1,11)) + [10]*3)*4base_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.yearby_year = rets.groupby(get_year)by_year.apply(spx_corr)by_year.apply(lambda g: g['AAPL'].corr(g['MSFT'])) #计算相关性,协方差示例:逐组线性回归import statsmodels.api as smdef regress(data, yvar, xvars):Y = data[yvar]X = data[xvars]X['intercept'] = 1result = sm.OLS(Y, X).fit() #OLS最小二乘回归return result.paramsby_year.apply(regress, 'AAPL', ['SPX'])数据透视表与交叉表pivot_tableDataFrame有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, 添加行、列的小计和总计交叉表crosstabcrosstab也是形成数据透视表工具,尤其在频率统计方面比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(,1,7) - datetime(,6,24,8,15)delta.daysfrom datetime import timedeltastart = datetime(, 1,7)start+timedelta(12) #时间可以加timedelta形成新的时间datetime模块中类型date time datetimetimedelta, 两个datetime之间的差tzinfo, 时区信息字符串与datetime信息互换举例:stamp=datetime(,1,3)str(stamp)stamp.strftime('%Y-%m-%d') #strftime把时间转换成格式化字符串value='-01-03'datetime.strptime(value, '%Y-%m-%d') #strptime将字符串转换成日期时间格式datestrs=['7/6/', '8/6/'][datetime.strptime(x, '%m/%d/%Y') for x in datestrs]stamp.strftime('%c')返回:'Mon Jan 3 00:00:00 '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, 适合地区的格式化时间第三方库dateutildatetime解析时间需要输入固定的格式,而dateutil可以自动识别大部分字符串日期格式举例:from dateutil.parser import parseparse("-01-03") #返回datetime对象parse('Jan 31, 1997 10:45 PM')parse('6/12/', dayfirst=True) #日期在前是可以指定dayfirst为Truepandas.to_datetime()日期转换举例:datestrs=['-07-06 12:00:00', '-08-06 00:00:00']pd.to_datetime(datestrs)返回:DatetimeIndex(['-07-06 12:00:00', '-08-06 00:00:00'], dtype='datetime64[ns]', freq=None)pd.to_datetime(datestrs + [None]) #缺失值情况,返回的缺失值是NaT返回:DatetimeIndex(['-07-06 12:00:00', '-08-06 00:00:00', 'NaT'], dtype='datetime64[ns]', freq=None)时间序列基础举例:dates=[datetime(,1,2), datetime(,1,5), datetime(,1,7), datetime(,1,8), datetime(,1,10), datetime(, 1,12)]ts = pd.Series(np.random.randn(6), index=dates)ts.indexts.index.dtype #dtype('<M8[ns]') 纳秒级别精度ts + ts[::2] #会按照时间序列自动对齐索引、选择、子集stamp = ts.index[2]ts[stamp] #用原始时间戳索引ts['1/10/'] #用其他字符串格式索引ts['0110'] #用其他字符串格式索引longer_ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/', periods=1000)) #pd.date_range形成周期性数据longer_ts[''] #用年完成切片,返回所有索引的数据longer_ts['-05'] #用年月切片longer_ts[datetime(,5,5):] #用datetime对象完成切片longer_ts['1/6/':'1/11/'] #可以用不在序列中的时间完成切片。可以传递字符串日期、datetime对象或时间戳进行切片注意:这些切片是不会产生新数据,而是在原有数据上面的视图truncate:ts.truncate(after='1/9/') #用truncate完成切片DataFrame的一个示例:dates=pd.date_range('1/1/2000',periods=100, freq='W-WED')long_df = pd.DataFrame(np.random.randn(100,4), index=dates, columns=['Colorado', 'Texas', 'New York', 'Ohio'])long_df.loc['5-2001'] #loc也可以完成切片含有重复索引的时间序列举例:dates = pd.DatetimeIndex(['1/1/2000', '1/2/2000', '1/2/2000', '1/2/2000', '1/3/2000'])dup_ts=pd.Series(np.arange(5), index=dates)dup_ts.index.is_unique #判断唯一性dup_ts['1/2/2000'] #返回所有重复索引的切片数据dup_ts.groupby(level=0).count() #通过level=0层级索引完成分组日期范围、频率、位移生成日期范围, pandas.date_rangepandas.date_range可以根据特定频率生成指定长度的DatetimeIndex举例:index=pd.date_range('-04-01', '-06-01') #默认按天为频率,指定起始和结束日期pd.date_range(start='-04-01', periods=200) #指定起始日期,长度 pd.date_range(end='-06-01',periods=20) #指定结束日期pd.date_range('2000-01-01', '2000-12-01', freq='BM') #指定频率BM就是business end of monthpd.date_range('-05-02 12:5:31', periods=5) #会保留时间pd.date_range('-05-02 12:5:31', periods=5, normalize=True) #normalize会把时间标准化,去掉时间部分pd.date_range('-01-01', '-09-01', freq='WOM-3FRI') #每月第3周五时间频率:D, dayB, BusinessDay,工作日H, HourT或min, minuteS, SecondeL或ms, Milli,毫秒U, Micro, 微秒M, MonthEnd,月底BM, BusinessMonthEnd 月底工作日MS, 月初BMS, BusinessMonthBegin, 月初工作日W-MON, W-TUE,W-WED, W-THU, W-FRI, W-SAT, W-SUN, weekWOM-1MON, WOM-2MON... Week of Month, 本月第几周Q-JAN, Q-FEB, .... 每月最后一个日历日的季度日期BQ-JAN, BQ-FEB, ...每月最后一个工作日的季度日期QS-JAn, QS-FEB.....每月第一个日历日的季度日期BQS-JAN, BQS-FEB,...每月第一个工作日的季度日期A-JAN, A-FEB, ...给定月份所在的月的最后一个日历所对应的年度日期BA-JAN, BA-FEB, ..., YearBegin, 给定月份所在的月的最后一个工作日所对应的年度日期AS-JAN, AS-FEB, ..., BusinessYearBegin, BAS-JAN, BAS-FEB,..., 频率和日期偏置有2种方法:方法1:使用pandas自带的类对象from pandas.tseries.offsets import Hour, Minutehour = Hour()hour = Hour(4) #构建4小时对象pd.date_range('-05-02 12:5:31', periods=5, freq=hour)ped= Hour(2) + Minute(30) #偏置可以通过联合完成举例:pd.date_range('-05-02 12:5:31', periods=5, freq='4H') #通常可以直接在频率别字前面加数量表示频率pd.date_range('-05-02 12:5:31', periods=5, freq='1h30min') #1小时30分向前向后移动日期,shift举例:ts=pd.Series(np.random.randn(4), index=pd.date_range('1/1/2000', periods=4, freq='M'))ts.shift(2) #索引不变,数值往后移动2行ts.shift(-2) #向前移动,会引入缺失值ts.shift(2, freq='M') #偏移索引2mon,值不变ts/ts.shift(1) - 1 #常用于时间序列或DateFrame多列时间序列的百分比变化使用Datetime和Timestamp进行偏置from pandas.tseries.offsets import Day, MonthEndnow=datetime(,11,17)now+3*Day()now + MonthEnd(2) #往后偏移2个月,输出月底最后一天roolforward, rollback显示将日期向前和向后移动offset.rollforward(now) #本月月底offset.rollback(now) #上月月底与groupby结合使用:ts.groupby(offset.rollforward).count() #相当于统计每个月的数量ts.resample('M').count() #作用同上,但更方便时区处理介绍:很多时间序列用户选择世界协调时间或者UTC,这是格林尼治时间的后继者,也是目前的国际标准时区通常被表示为UTC的偏置python中的时区信息来源于第三方库pytzimport mon_timezones[-5:]tz = pytz.timezone('Asia/Shanghai')时区的本地化和转换默认情况python中的时间序列是时区简单型,即没有时区信息显示举例:rng = pd.date_range('3/9/ 9:30', periods=6, freq='D')ts = pd.Series(np.random.randn(len(rng)), index=rng)type(ts.index.tz) #返回None类型,没有时区信息使用tz_localize方法可以将简单时区转换到本地化时区tz = pytz.timezone('Asia/Shanghai')pd.date_range('3/9/ 9:30', periods=10, freq='D', tz=tz) #返回时间类似:-03-09 09:30:00+08:00'。 如果tz是UTC,返回+00:00ts_utc=ts.tz_localize('UTC') #完成时间本地化tz_convert可以转换为另一个时区一旦有了时区信息,就可以在时区之间转换了,如果没有时区信息就无法转换的ts_utc.tz_convert('Asia/Shanghai') #完成时区转换DatetimeIndex对象也有tz_localize和tz_convert方法ts.index.tz_localize('UTC')rng.tz_localize('UTC')时区感知时间戳对象的操作stamp = pd.Timestamp('-03-12 04:00')stamp_utc = stamp.tz_localize('utc')stamp_utc.tz_convert('Asia/Shanghai')stamp_shanghai = pd.Timestamp('-03-12 04:00', tz='asia/shanghai') #创建时设置时区时区感知的Timestamp对象内部存储了一个UNIX纪元(1970年1月1日)至今的纳秒数量UTC时间戳数值,该数值在时区转换中是不变的。stamp_utc.valuestamp_utc.tz_convert('asia/shanghai').value #这2个value值是相同的使用Dataoffset进行算术运算from pandas.tseries.offsets import Hourstamp = pd.Timestamp('-03-12 01:30', tz='asia/shanghai')不同时区间操作两个不同的时区时间序列如果需要联合,结果将是UTC时间的,由于时间戳是UTC格式的,所以这个操作比较简单,不需要转换ts1 = ts[:3].tz_localize('Europe/London')ts2 = ts[3:].tz_localize('Europe/Moscow')result = ts1 + ts2 #返回的result将是UTC时间+00:00时间区间和区间算术时间区间表示的是一个时间范围举例:p = pd.Period(, freq='A-DEC')pd.Period(, freq='A-DEC')-p #周期可以直接运算values=['2001Q3', '2002Q2', 'Q1']index=pd.PeriodIndex(values, freq='Q-DEC') #使用字符串构建时间区间对象区间频率转换 asfreq可以将频率进行转换举例:p = pd.Period(, freq='A-DEC')p.asfreq('M', how='start') #返回的就是Period('-01', 'M')p.asfreq('M', how='end') #返回的就是12月p = pd.Period(, freq='A-JUN') #取一年中6月p.asfreq('M', how='start') #取7月p.asfreq('M', how='end') #取6月p=pd.Period('Aug-', 'M')p.asfreq('A-JUN') #返回的是rng=pd.period_range('', '', freq='A-DEC')ts=pd.Series(np.random.randn(len(rng)), index=rng)ts.asfreq('M', how='start') #将年索引,转换成月索引ts.asfreq('B', how='end') #转换为每年最后一个工作日季度区间的频率p=pd.Period('Q4', freq='Q-JAN') #以1月为一个季度结束月份p.asfreq('D', 'start') #返回的是-11-01p.asfreq('D', 'end') #返回的是-01-31p4pm = (p.asfreq('B', 'e')-1).asfreq('T', 's') + 16*60 #返回季度倒数第二个工作日下午4点的时间戳p4pm.to_timestamp()#返回值Period('-01-30 16:00', 'T')将时间戳转换为区间(以及逆转换), to_period, to_timestamprng = pd.date_range('2000-01-01', periods=3, freq='M')ts = pd.Series(np.random.randn(3), index=rng)pts=ts.to_period() #默认转换成了月区间pts.to_timestamp(how='end') #转换成时间戳从数组生成PeriodIndexindex = pd.PeriodIndex(year=data.year, quarter=data.quarter, freq='Q-DEC') #可以把两个数组年和季度组合成一个PeriodIndex对象重新采样与频率转换介绍:重新采样是指将时间序列从一个频率转换为另一个频率的过程。向下采样:将跟高频率的数据聚合到低频向上采样:将低频数据转换到高频数据平行采样:比如每周一转换成每周四采样需要注意:1、在向下采样中,目标频率必须是原频率的子区间2、在向上采样中,目标频率必须是原频率的父区间resample具有和groupby类似的API,可以完成分组和聚合操作举例:rng = pd.date_range('2000-01-01', periods=100, freq='D')ts=pd.Series(np.random.randn(len(rng)), index=rng)ts.resample('M').count() #按照月进行分组ts.resample('M', kind='period').count() #作用同上 resample参数介绍:freq, 频率字符串或者DateOffset对象,'M', '5min', Second(1)axis, 需要采用的轴向,默认axis=0fill_method, 采样插值,ffill或bfill,默认是不差值closed, 向下采样中,那段是封闭的, right或leftlabel, 向下采样中,比如可以标记为9:30,9:35等loffset, 对箱标签进行时间调校,例如'-1s' second(-1)limit, 向前或向后填充时,填充区间的最大值kind, 对区间'period', 时间戳'timestamp'的聚合,默认为时间序列索引的类型convention, 在对区间重新采样时,用于将低频周期转换为高频的约定,'start' 'end'默认是‘end’向下采样需要考虑:1、每段间隔的那一边是闭合的2、如何在间隔的起始或结束位置标记每个已聚合的箱体举例:rng = pd.date_range('2000-01-01', periods=12, freq='T')ts=pd.Series(np.random.randn(len(rng)), index=rng)ts.resample('5min', closed='right').sum() #5分钟采样一次ts.resample('5min', closed='right', label='left').count() #label是对箱子的标记,right和left的标记结果是不同的#最终返回的序列名称也是不同的,label=‘left'会取箱体的左边界进行命名,'right'会取箱体右边界命名ts.resample('5min', closed='right', label='right',loffset='-1s').count() #loffset可以让索引名称更容易理解开端-峰值-谷值-结束(OHLC)重新采样, ohlcts.resample('5min').ohlc() #获取开始、最大、最小、结束的数据,类似K线图向上采样与插值举例:frame = pd.DataFrame(np.random.randn(2,4), index=pd.date_range('1/1/2000', periods=2, freq='W-WED'), columns=['Colorado', 'Texas', 'New York', 'Ohio'])df_daily=frame.resample('D').asfreq() #按天采样frame.resample('D').ffill() #向前填充frame.resample('D').ffill(limit=2) #仅填充2组frame.resample('W-THU').ffill() #时间平移使用区间进行重新采样frame=pd.DataFrame(np.random.randn(24,4), index=pd.period_range('1-2000', '12-2001', freq='M'), columns=['Colorado', 'Texas', 'New York', 'Ohio'])annual_frame=frame.resample('A-DEC').count() #使用年采样annual_frame.resample('Q-DEC').ffill() #按季度采样annual_frame.resample('Q-DEC', convention='start').ffill() #convention默认是startannual_frame.resample('Q-DEC', convention='end').ffill() #convention是end时,会从end开始采样,这样开头区间会只采样一个数据移动窗口函数, rolling, expanding, ewmSeries和DataFrame都有rolling. expanding函数,作为滚动窗口rolling, expanding类似groupby和resample,也产生分组,只是rolling是根据滑动窗口产生分组的,然后应用聚类函数rolling, 有窗口大小限制expanding, 没有DataFrame调用移动窗口函数会应用到所有的列上面。举例:s1 = pd.Series(np.random.randn(1000), index=np.arange(1000))s1.rolling(250).mean().plot()s1.rolling(250, min_periods=100).mean().plot() #min_period可以设置最小窗口s1.expanding().mean().plot() #从窗口开始,并增加窗口大小,直到覆盖整个序列s2=pd.Series(np.random.randn(1000), pd.period_range('2000-1-1', periods=1000, freq='D'))s2.rolling('20D').mean().plot() #rolling函数也接收固定大小时间偏置字符串,比如'20D'指数加权函数ewm,s1.ewm(span=30).mean().plot() #ewm, exponential weighted moving, 指数加权移动, span是窗口大小二元移动窗口函数spc_px = close_px_all['spx']spx_rets = spx_px.pct_change() #pct_change()计算当前元素与上一个元素的变化百分比returns = close_px.pct_change() corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets) #corr计算协方差corr = returns.rolling(125, min_periods=100).corr(spx_rets) #计算一个Seires与DataFrame各列之间的协方差用户自动以移动窗口函数, applyfrom scipy.stats import percentileofscorescore_at_2percent = lambda x : percentileofscore(x, 0.02) #计算0.02在x中的分位数s1.rolling(250).apply(score_at_2percent).plot()

高阶pandas

分类数据, Categorical

将数据转换为分类数据可以产生大幅的性能提升。DataFrame中的一列的分类版本通常也会明显使用更少内存。

使用category进行groupby速度更快,因为底层算法使用了基于整数代码的数组而不是字符串数组

take, unique, value_countsvalues = 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']*2N = 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.categoryc = 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对象进行计算qcutnp.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=10000000draws=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, 去除类别,将被没有类别的值对应的类置为NaNremove_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=15times=pd.date_range('-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_namesPatsy公式中的数据转换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 = sizereturn mean + np.sqrt(variance)*np.random.randn(size)np.random.seed(12345)N=100x=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)+epsx_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'] = yresults=smf.ols('y ~ col0 + col1 + col2', data=data).fit() #用patsy公式results.paramsresults.tvaluesresults.predict(data[:5]) #给定新的样本数据后,可以根据估计的模型参数计算预测值评估时间序列处理时间序列分析:自回归过程,卡尔曼滤波, 其他状态空间模型, 多变量自回归模型举例:init_x = 4import randomvalues = [init_x, init_x]N=1000b0=0.8b1=-0.4noise=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=5model=sm.tsa.AR(values)results=model.fit(MAXLAGS)results.paramsscikit-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].valuesx_test = test[predictors].valuesy_train = train['Survived'].valuesfrom sklearn.linear_model import LogisticRegressmodel = LogisticRegression()model.fit(x_train, y_train)y_predict = model.predict(x_test)(y_true == y_predict).mean()from sklearn.linear_model import LogisticRegressionCVmoel_cv = LogisticRegressionCV(10)model_cv.fit(x_train, y_train)from sklean.model_selection import creoss_val_scoremodel = LogisticRegression(C=10)scores = cross_val_score(model, x_train, y_train,cv=4)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。