我必须在我拥有的数据集中的移动窗口中计算变异系数(std /均值)。代码很简单:
start_time = time.time()
channel_data = data[data['channel_id'] == ch].sort_values('datetime')
channel_data['datetime'] = pd.to_datetime(channel_data['datetime'],format='%Y-%m-%d %H:%M:%S').dt.floor('d')
channel_data = channel_data.set_index('datetime')
rolling_data = channel_data.rolling('{}D'.format(window)).agg({ 'val': coeff_of_var })
rolling_data = rolling_data.groupby(rolling_data.index.floor('d')).last()[window:]
print('Time needed: {} seconds'.format(time.time() - start_time))
我的问题是它非常慢。
coeff_of_var
可以是scipy.stats.variation
的自定义函数,也可以是lambda函数-我尝试了全部。我使用的自定义功能是
def coeff_of_var(series):
return series.std() / series.mean()
data
是一个尺寸为[3070584行x 5列]的DataFrame。 channel_data
包含〜457710行。
这段代码在一个周期内,花了很长时间,我不得不在第一次执行时间的print
之前将其停止...
我没有计算变异系数,而是尝试分别计算std和mean,即用[[std','mean']代替第5行大括号中的函数。新行是:
std_rolling_data = channel_data.rolling('{}D'.format(window)).agg({ 'val': ['std', 'mean'] })
执行时间降至:
Time needed: 0.9421329498291016 seconds
Time needed: 0.9423763751983643 seconds
Time needed: 0.9420042037963867 seconds
Time needed: 0.9560058116912842 seconds
Time needed: 0.9728689193725586 seconds
我还尝试将自定义函数简化为:
def coeff_of_var(series):
return 1
在这种情况下,执行时间为:
Time needed: 32.465901136398315 seconds
Time needed: 34.14194059371948 seconds
Time needed: 38.883220195770264 seconds
Time needed: 44.430686950683594 seconds
Time needed: 42.99840021133423 seconds
您是否知道自定义功能缓慢的原因是什么?
您可以使用以下代码来复制问题:
import numpy as np
import pandas as pd
import time
def coeff_of_var(series):
return 1 #series.std() / series.mean()
nrows = 3070584
ntrue = 450000
window = 5
rng = pd.date_range('2015-01-01 00:00:00', periods=nrows, freq='min')
data = pd.DataFrame({ 'A': rng, 'B' : np.random.randn(len(rng)), 'C' : np.random.randn(len(rng)), 'D' : np.random.randn(len(rng)), 'E' : np.zeros(len(rng), dtype=bool)})
data.loc[np.random.choice(np.arange(nrows), ntrue, replace=False), 'E'] = True
start_time = time.time()
channel_data = data[data['E'] == True].sort_values('A')
channel_data['A'] = pd.to_datetime(channel_data['A'],format='%Y-%m-%d %H:%M:%S').dt.floor('d')
channel_data = channel_data.set_index('A')
rolling_data = channel_data.rolling('{}D'.format(window)).agg({ 'B': coeff_of_var })
rolling_data = rolling_data.groupby(rolling_data.index.floor('d')).last()[window:]
print('Time needed: {} seconds'.format(time.time() - start_time))
答案 0 :(得分:2)
我以相似的结果运行了您的代码,所以我在Google上搜索了一下。不幸的是,我发现的内容非常模糊,但我认为分享它可能仍会给您一些想法:
Optimize Custom Grouping Function
TL; DR:
熊猫无法优化自定义功能。它具有数量有限的内置分组方法。所有这些都经过优化,应该会产生更好的性能。
虽然我知道这不是一个令人满意的答案,但我希望它仍然会有所帮助。
答案 1 :(得分:1)
函数速度过慢的原因是您使用的是.agg而不是.apply。对于自定义函数,您想使用.apply。只需将代码更改为:
rolling_data = channel_data.rolling('{}D'.format(window))['B'].apply(coeff_of_var)
如果您只使coeff_of_var返回1,那么您的时间将是:
Time needed: 0.80185866355896 seconds
如果您使用自定义函数或lambda x更改代码以计算变异系数,那么对我而言所花费的时间为10秒。
最快的方法就是您所说的:
rolling_data = channel_data.rolling('{}D'.format(window)).agg({'B':['mean','std']})
rolling_data = rolling_data['B']['std']/rolling_data['B']['mean']
我选了哪个
Time needed: 0.7320513725280762 seconds