本文翻译自https://nbviewer.jupyter.org/github/justmarkham/pandas-videos/blob/master/top_25_pandas_tricks.ipynb ,翻译若有不当之处,还请批评指正。
首先咱们须要先提早下载好示例数据集
:git
利用如下代码导入上述数据集:github
输入下面的命令查询pandas版本:
若是你还想知道pandas所依赖的模块的版本,你可使用show_versions()
函数:
你能够查看到Python,pandas, Numpy, matplotlib等的版本信息。segmentfault
假设你须要建立一个示例DataFrame。有不少种实现的途径,我最喜欢的方式是传一个字典给DataFrame constructor,其中字典中的keys为列名,values为列的取值。
如今若是你须要建立一个更大的DataFrame,上述方法则须要太多的输入。在这种状况下,你可使用Numpy的random.rand()
函数,告诉它行数和列数,将它传递给DataFrame constructor:
这种方式很好,但若是你还想把列名变为非数值型的,你能够强制地将一串字符赋值给columns
参数:
你能够想到,你传递的字符串的长度必须与列数相同。app
让咱们来看一下刚才咱们建立的示例DataFrame:
我更喜欢在选取pandas列的时候使用点(.),可是这对那么列名中含有空格的列不会生效。让咱们来修复这个问题。
更改列名最灵活的方式是使用rename()
函数。你能够传递一个字典,其中keys为原列名,values为新列名,还能够指定axis:
使用这个函数最好的方式是你须要更改任意数量的列名,不论是一列或者所有的列。
若是你须要一次性从新命令全部的列名,更简单的方式就是重写DataFrame的columns
属性:
若是你须要作的仅仅是将空格换成下划线,那么更好的办法是使用str.replace()
方法,这是由于你都不须要输入全部的列名:
上述三个函数的结果都同样,能够更改列名使得列名中不含有空格:
最后,若是你须要在列名中添加前缀或者后缀,你可使用add_prefix()
函数:
或者使用add_suffix()
函数:dom
让咱们来看一下drinks这个DataFame:
该数据集描述了每一个国家的平均酒消费量。若是你想要将行序反转呢?
最直接的办法是使用loc
函数并传递::-1
,跟Python中列表反转时使用的切片符号一致:
若是你还想重置索引使得它从0开始呢?
你可使用reset_index()
函数,告诉他去掉彻底抛弃以前的索引:
你能够看到,行序已经反转,索引也被重置为默认的整数序号。机器学习
跟以前的技巧同样,你也可使用loc
函数将列从左至右反转:
逗号以前的冒号表示选择全部行,逗号以后的::-1
表示反转全部的列,这就是为何country这一列如今在最右边。ide
这里有drinks这个DataFrame的数据类型:
假设你仅仅须要选取数值型的列,那么你可使用select_dtypes()
函数:
这包含了int和float型的列。
你也可使用这个函数来选取数据类型为object的列:
你还能够选取多种数据类型,只须要传递一个列表便可:
你还能够用来排除特定的数据类型:svg
让咱们来建立另外一个示例DataFrame:
这些数字实际上储存为字符型,致使其数据类型为object:
为了对这些列进行数学运算,咱们须要将数据类型转换成数值型。你能够对前两列使用astype()
函数:
可是,若是你对第三列也使用这个函数,将会引发错误,这是由于这一列包含了破折号(用来表示0)可是pandas并不知道如何处理它。
你能够对第三列使用to_numeric()
函数,告诉其将任何无效数据转换为NaN
:
若是你知道NaN
值表明0,那么你能够fillna()
函数将他们替换成0:
最后,你能够经过apply()
函数一次性对整个DataFrame使用这个函数:
仅需一行代码就完成了咱们的目标,由于如今全部的数据类型都转换成float:函数
pandas DataFrame被设计成能够适应内存,因此有些时候你能够减少DataFrame的空间大小,让它在你的系统上更好地运行起来。
这是drinks这个DataFrame所占用的空间大小:
能够看到它使用了304.KB。
若是你对你的DataFrame有操做方面的问题,或者你不能将它读进内存,那么在读取文件的过程当中有两个步骤可使用来减少DataFrame的空间大小。
第一个步骤是只读取那些你实际上须要用到的列,能够调用usecols
参数:
经过仅读取用到的两列,咱们将DataFrame的空间大小缩小至13.6KB。
第二步是将全部实际上为类别变量的object列转换成类别变量,能够调用dtypes
参数:
经过将continent列读取为category数据类型,咱们进一步地把DataFrame的空间大小缩小至2.3KB。
值得注意的是,若是跟行数相比,category数据类型的列数相对较小,那么catefory数据类型能够减少内存占用。学习
假设你的数据集分化为多个文件,可是你须要将这些数据集读到一个DataFrame中。
举例来讲,我有一些关于股票的小数汇集,每一个数据集为单天的CSV文件。这是第一天的:
这是次日的:
这是第三天的:
你能够将每一个CSV文件读取成DataFrame,将它们结合起来,而后再删除原来的DataFrame,可是这样会多占用内存且须要许多代码。
更好的方式为使用内置的glob
模块。你能够给glob()
函数传递某种模式,包括未知字符,这样它会返回符合该某事的文件列表。在这种方式下,glob会查找全部以stocks开头的CSV文件:
glob会返回任意排序的文件名,这就是咱们为何要用Python内置的sorted()
函数来对列表进行排序。
咱们以生成器表达式用read_csv()
函数来读取每一个文件,并将结果传递给concat()
函数,这会将单个的DataFrame按行来组合:
不幸的是,索引值存在重复。为了不这种状况,咱们须要告诉concat()
函数来忽略索引,使用默认的整数索引:
上一个技巧对于数据集中每一个文件包含行记录颇有用。可是若是数据集中的每一个文件包含的列信息呢?
这里有一个例子,dinks数据集被划分红两个CSV文件,每一个文件包含三列:
同上一个技巧同样,咱们以使用glob()
函数开始。这一次,咱们须要告诉concat()
函数按列来组合:
如今咱们的DataFrame已经有六列了。
假设你将一些数据储存在Excel或者Google Sheet中,你又想要尽快地将他们读取至DataFrame中。
你须要选择这些数据并复制至剪贴板。而后,你可使用read_clipboard()
函数将他们读取至DataFrame中:
和read_csv()
相似,read_clipboard()
会自动检测每一列的正确的数据类型:
让咱们再复制另一个数据至剪贴板:
神奇的是,pandas已经将第一列做为索引了:
须要注意的是,若是你想要你的工做在将来可复制,那么read_clipboard()
并不值得推荐。
假设你想要将一个DataFrame划分为两部分,随机地将75%的行给一个DataFrame,剩下的25%的行给另外一个DataFrame。
举例来讲,咱们的movie ratings这个DataFrame有979行:
咱们可使用sample()
函数来随机选取75%的行,并将它们赋值给"movies_1"DataFrame:
接着咱们使用drop()
函数来舍弃“moive_1”中出现过的行,将剩下的行赋值给"movies_2"DataFrame:
你能够发现总的行数是正确的:
你还能够检查每部电影的索引,或者"moives_1":
或者"moives_2":
须要注意的是,这个方法在索引值不惟一的状况下不起做用。读者注
:该方法在机器学习或者深度学习中颇有用,由于在模型训练前,咱们每每须要将所有数据集按某个比例划分红训练集和测试集。该方法既简单又高效,值得学习和尝试。
让咱们先看一眼movies这个DataFrame:
其中有一列是genre(类型):
好比咱们想要对该DataFrame进行过滤,咱们只想显示genre为Action或者Drama或者Western的电影,咱们可使用多个条件,以"or"符号分隔:
可是,你实际上可使用isin()
函数将代码写得更加清晰,将genres列表传递给该函数:
若是你想要进行相反的过滤,也就是你将吧刚才的三种类型的电影排除掉,那么你能够在过滤条件前加上破浪号:
这种方法可以起做用是由于在Python中,波浪号表示“not”操做。
假设你想要对movies这个DataFrame经过genre进行过滤,可是只须要前3个数量最多的genre。
咱们对genre使用value_counts()
函数,并将它保存成counts(type为Series):
&emp; 该Series的nlargest()
函数可以轻松地计算出Series中前3个最大值:
事实上咱们在该Series中须要的是索引:
最后,咱们将该索引传递给isin()
函数,该函数会把它当成genre列表:
这样,在DataFrame中只剩下Drame, Comdey, Action这三种类型的电影了。
让咱们来看一看UFO sightings这个DataFrame:
你将会注意到有些值是缺失的。
为了找出每一列中有多少值是缺失的,你可使用isna()
函数,而后再使用sum()
:isna()
会产生一个由True和False组成的DataFrame,sum()
会将全部的True值转换为1,False转换为0并把它们加起来。
相似地,你能够经过mean()
和isna()
函数找出每一列中缺失值的百分比。
若是你想要舍弃那些包含了缺失值的列,你可使用dropna()
函数:
或者你想要舍弃那么缺失值占比超过10%的列,你能够给dropna()
设置一个阈值:len(ufo)
返回总行数,咱们将它乘以0.9,以告诉pandas保留那些至少90%的值不是缺失值的列。
咱们先建立另外一个新的示例DataFrame:
若是咱们须要将“name”这一列划分为三个独立的列,用来表示first, middle, last name呢?咱们将会使用str.split()
函数,告诉它以空格进行分隔,并将结果扩展成一个DataFrame:
这三列实际上能够经过一行代码保存至原来的DataFrame:
若是咱们想要划分一个字符串,可是仅保留其中一个结果列呢?好比说,让咱们以", "来划分location这一列:
若是咱们只想保留第0列做为city name,咱们仅须要选择那一列并保存至DataFrame:
让咱们建立一个新的示例DataFrame:
这里有两列,第二列包含了Python中的由整数元素组成的列表。
若是咱们想要将第二列扩展成DataFrame,咱们能够对那一列使用apply()
函数并传递给Series constructor:
经过使用concat()
函数,咱们能够将原来的DataFrame和新的DataFrame组合起来:
让咱们来看一眼从Chipotle restaurant chain获得的orders这个DataFrame:
每一个订单(order)都有订单号(order_id),包含一行或者多行。为了找出每一个订单的总价格,你能够将那个订单号的价格(item_price)加起来。好比,这里是订单号为1的总价格:
若是你想要计算每一个订单的总价格,你能够对order_id使用groupby()
,再对每一个group的item_price进行求和。
可是,事实上你不可能在聚合时仅使用一个函数,好比sum()
。为了对多个函数进行聚合,你可使用agg()
函数,传给它一个函数列表,好比sum()
和count()
:
这将告诉咱们没定订单的总价格和数量。
让咱们再看一眼orders这个DataFrame:
若是咱们想要增长新的一列,用于展现每一个订单的总价格呢?回忆一下,咱们经过使用sum()
函数获得了总价格:sum()
是一个聚合函数,这代表它返回输入数据的精简版本(reduced version )。
换句话说,sum()
函数的输出:
比这个函数的输入要小:
解决的办法是使用transform()
函数,它会执行相同的操做可是返回与输入数据相同的形状:
咱们将这个结果存储至DataFrame中新的一列:
你能够看到,每一个订单的总价格在每一行中显示出来了。
这样咱们就能方便地甲酸每一个订单的价格占该订单的总价格的百分比:
让咱们看一眼另外一个数据集:
这就是著名的Titanic数据集,它保存了Titanic上乘客的信息以及他们是否存活。
若是你想要对这个数据集作一个数值方面的总结,你可使用describe()
函数:
可是,这个DataFrame结果可能比你想要的信息显示得更多。
若是你想对这个结果进行过滤,只想显示“五数归纳法”(five-number summary)的信息,你可使用loc
函数并传递"min"到"max"的切片:
若是你不是对全部列都感兴趣,你也能够传递列名的切片:
Titanic数据集的Survived列由1和0组成,所以你能够对这一列计算总的存活率:
若是你想对某个类别,好比“Sex”,计算存活率,你可使用groupby()
:
若是你想一次性对两个类别变量计算存活率,你能够对这些类别变量使用groupby()
:
该结果展现了由Sex和Passenger Class联合起来的存活率。它存储为一个MultiIndexed Series,也就是说它对实际数据有多个索引层级。
这使得该数据难以读取和交互,所以更为方便的是经过unstack()
函数将MultiIndexed Series重塑成一个DataFrame:
该DataFrame包含了与MultiIndexed Series同样的数据,不一样的是,如今你能够用熟悉的DataFrame的函数对它进行操做。
若是你常用上述的方法建立DataFrames,你也许会发现用pivot_table()
函数更为便捷:
想要使用数据透视表,你须要指定索引(index), 列名(columns), 值(values)和聚合函数(aggregation function)。
数据透视表的另外一个好处是,你能够经过设置margins=True
轻松地将行和列都加起来:
这个结果既显示了总的存活率,也显示了Sex和Passenger Class的存活率。
最后,你能够建立交叉表(cross-tabulation),只须要将聚合函数由"mean"改成"count":
这个结果展现了每一对类别变量组合后的记录总数。
让咱们来看一下Titanic数据集中的Age那一列:
它如今是连续性数据,可是若是咱们想要将它转变成类别数据呢?
一个解决办法是对年龄范围打标签,好比"adult", "young adult", "child"。实现该功能的最好方式是使用cut()
函数:
这会对每一个值打上标签。0到18岁的打上标签"child",18-25岁的打上标签"young adult",25到99岁的打上标签“adult”。
注意到,该数据类型为类别变量,该类别变量自动排好序了(有序的类别变量)。
让咱们再来看一眼Titanic 数据集:
注意到,Age列保留到小数点后1位,Fare列保留到小数点后4位。若是你想要标准化,将显示结果保留到小数点后2位呢?
你可使用set_option()
函数:set_option()
函数中第一个参数为选项的名称,第二个参数为Python格式化字符。能够看到,Age列和Fare列如今已经保留小数点后两位。注意,这并无修改基础的数据类型,而只是修改了数据的显示结果。
你也能够重置任何一个选项为其默认值:
对于其它的选项也是相似的使用方法。
上一个技巧在你想要修改整个jupyter notebook中的显示会颇有用。可是,一个更灵活和有用的方法是定义特定DataFrame中的格式化(style)。
让咱们回到stocks这个DataFrame:
咱们能够建立一个格式化字符串的字典,用于对每一列进行格式化。而后将其传递给DataFrame的style.format()
函数:
注意到,Date列是month-day-year的格式,Close列包含一个$符号,Volume列包含逗号。
咱们能够经过链式调用函数来应用更多的格式化:
咱们如今隐藏了索引,将Close列中的最小值高亮成红色,将Close列中的最大值高亮成浅绿色。
这里有另外一个DataFrame格式化的例子:
Volume列如今有一个渐变的背景色,你能够轻松地识别出大的和小的数值。
最后一个例子:
如今,Volumn列上有一个条形图,DataFrame上有一个标题。
请注意,还有许多其余的选项你能够用来格式化DataFrame。
假设你拿到一个新的数据集,你不想要花费太多力气,只是想快速地探索下。那么你可使用pandas-profiling
这个模块。
在你的系统上安装好该模块,而后使用ProfileReport()
函数,传递的参数为任何一个DataFrame。它会返回一个互动的HTML报告:
使用示例以下(只显示第一部分的报告):
这部分的代码已经放在Github上,网址为:https://github.com/percent4/panas_usage_25_tricks 。 感谢你们的阅读~