我正面临一个巨大的瓶颈,我对Pandas DataFrame中的每一行都应用了method()。执行时间大概在15-20分钟之间。在
现在,我使用的代码如下:
def FillTarget(self, df):
backup = df.copy()
target = list(set(df['ACTL_CNTRS_BY_DAY']))
df = df[~df['ACTL_CNTRS_BY_DAY'].isnull()]
tmp = df[df['ACTL_CNTRS_BY_DAY'].isin(target)]
tmp = tmp[['APPT_SCHD_ARVL_D', 'ACTL_CNTRS_BY_DAY']]
tmp.drop_duplicates(subset='APPT_SCHD_ARVL_D', inplace=True)
t1 = dt.datetime.now()
backup['ACTL_CNTRS_BY_DAY'] = backup.apply(self.ImputeTargetAcrossSameDate,args=(tmp, ), axis=1)
# backup['ACTL_CNTRS_BY_DAY'] = self.compute_(tmp, backup)
t2 = dt.datetime.now()
print("Time for the bottleneck is ", (t2-t1).microseconds)
print("step f")
return backup
其中,imputeTargetCrossSameDate()方法如下:
^{pr2}$有什么方法可以优化这个apply()调用来减少总的时间吗。 注意,我必须在DataFrame上运行这个过程,它存储了2年的数据。我运行了15天,花了15-20分钟,而运行了1个月的数据,执行了超过45分钟,之后我不得不强制停止进程,这样在运行全数据集的情况下,这将是一个巨大的问题。在
还请注意,我遇到了一些引入numba来优化代码的示例http://pandas.pydata.org/pandas-docs/stable/enhancingperf.html,下面是我的numba实现:
调用numba方法的语句:
backup['ACTL_CNTRS_BY_DAY'] = self.compute_(tmp, backup)
numba的计算方法:
@numba.jit
def compute_(self, df1, df2):
n = len(df2)
result = np.empty(n, dtype='float64')
for i in range(n):
d = df2.iloc[i]
result[i] = self.apply_ImputeTargetAcrossSameDate_method(df1['APPT_SCHD_ARVL_D'].values, df1['ACTL_CNTRS_BY_DAY'].values,
d['APPT_SCHD_ARVL_D'], d['ACTL_CNTRS_BY_DAY'])
return result
这是一个包装器方法,它取代了Pandas的apply,对每一行调用Impute方法。使用numba的插补方法如下:
@numba.jit
def apply_ImputeTargetAcrossSameDate_method(self, df1col1, df1col2, df2col1, df2col2):
dd = np.datetime64(df2col1)
idx1 = np.where(df1col1 == dd)[0]
if idx1.size == 0:
idx1 = idx1
else:
idx1 = idx1[0]
val = df1col2[idx1]
if val.size == 0:
r = 0
else:
r = val
return r
对于时间周期为5天的数据,我运行了normal apply()方法和numba()方法,结果如下:
With Numba:
749805 microseconds
With DF.apply()
484603 microseconds.
如你所见,numba比较慢,这是不应该发生的,所以万一我遗漏了什么,请告诉我,这样我就可以优化这段代码。在
提前谢谢
编辑1 根据要求,将截取的数据(前20行的头)添加如下: 在此之前:
APPT_SCHD_ARVL_D ACTL_CNTRS_BY_DAY
919 2020-11-17 NaN
917 2020-11-17 NaN
916 2020-11-17 NaN
915 2020-11-17 NaN
918 2020-11-17 NaN
905 2014-06-01 NaN
911 2014-06-01 NaN
913 2014-06-01 NaN
912 2014-06-01 NaN
910 2014-06-01 NaN
914 2014-06-01 NaN
908 2014-06-01 NaN
906 2014-06-01 NaN
909 2014-06-01 NaN
907 2014-06-01 NaN
898 2014-05-29 NaN
892 2014-05-29 NaN
893 2014-05-29 NaN
894 2014-05-29 NaN
895 2014-05-29 NaN
之后:
APPT_SCHD_ARVL_D ACTL_CNTRS_BY_DAY
919 2020-11-17 0.0
917 2020-11-17 0.0
916 2020-11-17 0.0
915 2020-11-17 0.0
918 2020-11-17 0.0
905 2014-06-01 0.0
911 2014-06-01 0.0
913 2014-06-01 0.0
912 2014-06-01 0.0
910 2014-06-01 0.0
914 2014-06-01 0.0
908 2014-06-01 0.0
906 2014-06-01 0.0
909 2014-06-01 0.0
907 2014-06-01 0.0
898 2014-05-29 0.0
892 2014-05-29 0.0
893 2014-05-29 0.0
894 2014-05-29 0.0
895 2014-05-29 0.0
这个方法有什么作用? 在上面的数据示例中,您可以看到一些日期是重复的,并且它们对应的值是NaN。如果具有相同日期的所有行都具有值NaN,则将它们替换为0。 但也有一些情况,比如说:2014-05-29其中有10行具有相同的日期,只有1行与该日期相对应,其中会有一些值。(假设是10)。然后,方法()将用10而不是nan填充该特定日期的所有值。在
示例:
898 2014-05-29 NaN
892 2014-05-29 NaN
893 2014-05-29 NaN
894 2014-05-29 10
895 2014-05-29 NaN
上述内容应为:
898 2014-05-29 10
892 2014-05-29 10
893 2014-05-29 10
894 2014-05-29 10
895 2014-05-29 10
这是一个有点仓促的解决方案,因为我现在就要离开到周末了,但它奏效了。在
输入数据帧:
代码:
^{pr2}$基本上不需要
apply
一个函数。我在这里做的是:tt
vv
tt
中。在vv
获取值,其中df
中的日期相同,并将其分配给df
。在0.0
填充所有其他空值。在迭代行不是一件很快的事情,但我希望它比旧代码更快。如果我有更多的时间,我会想出一个没有迭代的解决方案,也许在周一。在
编辑: 使用
pd.merge()
而不进行迭代的解决方案:您的数据意味着
ACTL_CNTRS_BY_DAY
中最多只有一个值不是空的,所以我使用groupby
中的first()
来选取唯一存在的值。在相关问题 更多 >
编程相关推荐