Pandas acceleration
Last updated
Last updated
我们来看有关pandas加速的小技巧:
使用datetime类型来处理和时间序列有关的数据
批量计算的技巧
通过HDFStore存储数据节省时间
源码,相关数据及GitHub地址
现在就让我们开始吧
首先这里我们使用的数据源是一个电力消耗情况的数据(energy_cost.csv),非常贴近生活而且也是和时间息息相关的,用来做测试在合适不过了,这个csv文件大家可以在第四部分找到下载的地方哈
现在我们看到初始数据的样子了,主要有date_time和energy_kwh这两列,来表示时间和消耗的电力,比较好理解,下面让我们来看一下数据类型
这里有个小问题,Pandas和NumPy有dtypes(数据类型)的概念。如果未指定参数,则date_time这一列的数据类型默认object,所以为了之后运算方便,我们可以把str类型的这一列转化为timestamp类型:
可以发现我们通过用pd.to_datetime这个方法已经成功的把date_time这一列转化为了datetime64类型
现在再来看数据, 发现已经和刚才不同了,我们还可以通过指定format参数实现一样的效果,速度上也会快一些
有关具体的日期自定义相关方法,大家点击这里查看
首先,我们假设根据用电的时间段不同,电费价目表如下:
假设我们想要计算出电费,我们可以先写出一个根据时间动态计算电费的方法“apply_tariff“
好啦,现在我们想要在数据中新增一列 ‘cost_cents’ 来表示总价钱,我们有很多选择,首先能想到的方法便是iterrows(),它可以让我们循环遍历Dataframe的每一行,根据条件计算并赋值给新增的‘cost_cents’列
首先我们能做的是循环遍历流程,让我们先用.iterrows()替代上面的方法来试试:
我们为了测试方便,所有的方法都会循环10次来比较耗时,这里很明显我们有很大的改进空间,下面我们用apply方法来优化
这回速度得到了很大的提升,但是显然我们还没有get到pandas加速的精髓:矢量化操作。下面让我们开始提速
假设我们现在的电价是定值,不根据用电时间段来改变,那么pandas中最快的方法那就是采用(df[‘cost_cents’] = df[‘energy_kwh’] * price),这就是一个简单的矢量化操作示范。它基本是在Pandas中运行最快的方式。
目前的问题是我们的价格是动态的,那么如何将条件判断添加到Pandas中的矢量化运算中呢?答案就是我们根据条件选择和分组DataFrame,然后对每个选定的组应用矢量化操作:
这回我们发现速度是真正起飞了,首先我们根据用电的三个时段把df进行分三组,再依次进行三次矢量化操作,大家可以发现最后减少了很多时间,原理很简单:
在运行的时候,.isin()方法返回一个布尔值数组,如下所示:
[False, False, False, …, True, True, True]
接下来布尔数组传递给DataFrame的.loc索引器时,我们获得一个仅包含与3个用电时段匹配DataFrame切片。然后简单的进行乘法操作就行了,这样做的好处是我们已经不需要刚才提过的apply方法了,因为不在存在遍历所有行的问题
通过观察可以发现,在apply_tariff_isin()中,我们仍然在通过调用df.loc和df.index.hour.isin()来进行一些“手动工作”。如果想要进一步提速,我们可以使用cut方法
效果依然锋利,速度上有了成倍的提升
众所周知,Pandas是在Numpy上建立起来的,所以在Numpy中当然有类似cut的方法可以实现分组,从速度上来讲差不太多
正常情况下,以上的加速方法是能满足日常需要的,如果有特殊的需求,大家可以上网看看有没有相关的第三方加速包
这里主要想强调的是节省预处理的时间,假设我们辛辛苦苦搭建了一些模型,但是每次运行之前都要进行一些预处理,比如类型转换,用时间序列做索引等,如果不用HDFStore的话每次都会花去不少时间,这里Python提供了一种解决方案,可以把经过预处理的数据存储为HDF5格式,方便我们下次运行时直接调用。
下面就让我们把本篇文章的df通过HDF5来存储一下:
现在我们可以关机下班了,当明天接着上班后,通过key(“preprocessed_df”)就可以直接使用经过预处理的数据了
如上图所示,现在我们可以发现date_time已经是处理为index了
Github仓库地址: https://github.com/yaozeliang/pandas_share
date_time
energy_kwh
0
2001/1/13 0:00
0.586
1
2001/1/13 1:00
0.580
2
2001/1/13 2:00
0.572
3
2001/1/13 3:00
0.596
4
2001/1/13 4:00
0.592
date_time
energy_kwh
0
2001-01-13 00:00:00
0.586
1
2001-01-13 01:00:00
0.580
2
2001-01-13 02:00:00
0.572
3
2001-01-13 03:00:00
0.596
4
2001-01-13 04:00:00
0.592
Type
cents/kwh
periode
Peak
28
17:00 to 24:00
Shoulder
20
7:00 to 17:00
Off-Peak
12
0:00 to 7:00
energy_kwh
cost_cents
date_time
2001-01-13 00:00:00
0.586
7.032
2001-01-13 01:00:00
0.580
6.960
2001-01-13 02:00:00
0.572
6.864
2001-01-13 03:00:00
0.596
7.152
2001-01-13 04:00:00
0.592
7.104