Python 如何加速多级数据帧和?
我正在尝试加快几个大型多级数据帧的求和速度 以下是一个示例:Python 如何加速多级数据帧和?,python,performance,pandas,cython,Python,Performance,Pandas,Cython,我正在尝试加快几个大型多级数据帧的求和速度 以下是一个示例: df1 = mul_df(5000,30,400) # mul_df to create a big multilevel dataframe #let df2, df3, df4 = df1, df1, df1 to minimize the memory usage, #they can also be mul_df(5000,30,400) df2, df3, df4 = df1, df1, df1 In [12]: ti
df1 = mul_df(5000,30,400) # mul_df to create a big multilevel dataframe
#let df2, df3, df4 = df1, df1, df1 to minimize the memory usage,
#they can also be mul_df(5000,30,400)
df2, df3, df4 = df1, df1, df1
In [12]: timeit df1+df2+df3+df4
1 loops, best of 3: 993 ms per loop
我对993ms不满意,有没有办法加快速度?cython能提高性能吗?如果是,如何编写cython代码?谢谢
注意:
mul_df()
是创建演示多级数据帧的函数
import itertools
import numpy as np
import pandas as pd
def mul_df(level1_rownum, level2_rownum, col_num, data_ty='float32'):
''' create multilevel dataframe, for example: mul_df(4,2,6)'''
index_name = ['STK_ID','RPT_Date']
col_name = ['COL'+str(x).zfill(3) for x in range(col_num)]
first_level_dt = [['A'+str(x).zfill(4)]*level2_rownum for x in range(level1_rownum)]
first_level_dt = list(itertools.chain(*first_level_dt)) #flatten the list
second_level_dt = ['B'+str(x).zfill(3) for x in range(level2_rownum)]*level1_rownum
dt = pd.DataFrame(np.random.randn(level1_rownum*level2_rownum, col_num), columns=col_name, dtype = data_ty)
dt[index_name[0]] = first_level_dt
dt[index_name[1]] = second_level_dt
rst = dt.set_index(index_name, drop=True, inplace=False)
return rst
更新:
我的奔腾双核上的数据T4200@2.00GHZ,3.00GB内存,WindowXP,Python 2.7.4,Numpy 1.7.1,Pandas 0.11.0,numexpr 2.0.1(Anaconda 1.5.0(32位))
方法1:在我的机器上(禁用
numexpr
方法2:使用numexpr
(如果安装了numexpr
,则默认启用该方法)
方法3:直接使用numexpr
In [34]: import numexpr as ne
In [46]: %timeit DataFrame(ne.evaluate('df1+df2+df3+df4'),columns=df1.columns,index=df1.index,dtype='float32')
10 loops, best of 3: 47.7 ms per loop
这些加速是使用numexpr
实现的,因为:
- 避免使用中间临时数组(在本例中可能是
numpy的效率相当低,我怀疑这是像
((df1+df2)+df3)+df4
- 使用可用的多核
numexpr
,例如df1+df2
将以这种方式进行评估,但是您在这里给出的示例将导致多次调用numexpr
(这是方法2,比方法1快)。使用直接(方法3)ne进行评估(…)
实现了更多的加速
请注意,在pandas 0.13(本周将发布0.12)中,我们实现了一个函数pd.eval
,该函数实际上与我上面的示例完全相同。请继续关注(如果您有冒险精神,这将很快出现在master中:)
最后回答您的问题,cython
在这里根本没有帮助;numexpr
在这类问题上非常有效(也就是说,在某些情况下cython是有帮助的)
一个警告:为了使用直接Numexpr方法,帧应该已经对齐(Numexpr在numpy数组上运行,并且对索引一无所知)。此外,它们应该是单个数据类型。方法1:在我的机器上没有那么糟糕(禁用了
Numexpr
)
方法2:使用numexpr
(如果安装了numexpr
,则默认启用该方法)
方法3:直接使用numexpr
In [34]: import numexpr as ne
In [46]: %timeit DataFrame(ne.evaluate('df1+df2+df3+df4'),columns=df1.columns,index=df1.index,dtype='float32')
10 loops, best of 3: 47.7 ms per loop
这些加速是使用numexpr
实现的,因为:
- 避免使用中间临时数组(在本例中可能是
numpy的效率相当低,我怀疑这是像
((df1+df2)+df3)+df4
- 使用可用的多核
numexpr
,例如df1+df2
将以这种方式进行评估,但是您在这里给出的示例将导致多次调用numexpr
(这是方法2,比方法1快)。使用直接(方法3)ne进行评估(…)
实现了更多的加速
请注意,在pandas 0.13(本周将发布0.12)中,我们实现了一个函数pd.eval
,该函数实际上与我上面的示例完全相同。请继续关注(如果您有冒险精神,这将很快出现在master中:)
最后回答您的问题,cython
在这里根本没有帮助;numexpr
在这类问题上非常有效(也就是说,在某些情况下cython是有帮助的)
一个警告:为了使用直接Numexpr方法,帧应该已经对齐(Numexpr在numpy数组上运行,并且不知道任何索引)。此外,它们应该是单个数据类型其他观察值
- 如果你的机器上只有两个内核,你就不能期望有更多的加速。最终,numexpression依赖于并行化和cpu缓存的性能使用
- 您所做的在某种程度上是错误的。数据帧上的Numexpressions是快速的,但却是错误的。如果数据帧的索引不相等,则它们不会返回正确的结果。不同的排序已经给您带来了麻烦,我将在下面介绍
- 如果您添加了具有不同索引的数据帧,那么整个性能就不再那么好了。好吧,Pandas通过查找相应的索引项为您添加适当的行做了相当好的工作。这带来了自然成本
导入itertools
将numpy作为np导入
作为pd进口熊猫
def mul_df(level1_rownum,level2_rownum,col_num,data_ty='float32'):
''创建多级数据帧,例如:mul_df(4,2,6)''
索引名称=['STK\U ID','RPT\U日期']
col_name=['col'+str(x).zfill(3)表示范围内的x(col_num)]
第一级\u dt=[[A'+str(x).zfill(4)]*范围内x的2级\u行数(1级\u行数)]
first_level_dt=list(itertools.chain(*first_level_dt))#展平列表
第二级\u dt=['B'+str(x).zfill(3)表示范围内的x(level2\u rownum)]*level1\u rownum
dt=pd.DataFrame(np.random.randn(level1_rownum*level2_rownum,col_num),columns=col_name,dtype=data_ty)
dt[索引名称[0]]=一级dt
dt[索引名称[1]]=第二级\u dt
rst=dt.set\U inde
In [44]: expr.set_use_numexpr(True)
In [45]: %timeit df1+df2+df3+df4
10 loops, best of 3: 173 ms per loop
In [34]: import numexpr as ne
In [46]: %timeit DataFrame(ne.evaluate('df1+df2+df3+df4'),columns=df1.columns,index=df1.index,dtype='float32')
10 loops, best of 3: 47.7 ms per loop
In [5]: %timeit pd.eval('df1+df2+df3+df4')
10 loops, best of 3: 50.9 ms per loop
564 ms ± 10.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
152 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
66.4 ms ± 1.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
True
1.36 s ± 67.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
928 ms ± 39.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
68 ms ± 2.2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
False