Pandas groupby - 应用循环平均值将每 10 分钟的数据聚合为每小时的数据 - 更快?
Pandas groupby - Apply circular mean to aggregate 10-minutely data into hourly data - Faster?
我需要你的帮助来制定一种更快地分组 10 分钟 angular/circular 数据的方法。由于循环数据的取值范围是0到360,普通的均值并不能捕捉到0到360之间的关系。因此,我想用scipy.statscircmean来完成循环均值。我已经发现 pd.groupby 中实现的 apply() 方法非常慢(标准联想笔记本电脑为 120 秒),类似于将每 10 分钟的数据转换为每小时的组,然后对这些组应用循环平均值。
此外,我使用的数据集可能包含非连续的时间戳。不过,有没有办法加快以下代码的速度(例如通过矢量化)?
非常感谢您的帮助。如果您需要这方面的更多信息,请告诉我。
import time
import pandas as pd
from datetime import datetime
import numpy as np
from scipy.stats import circmean
data = pd.DataFrame()
start = datetime(2015, 1, 1)
end = datetime(2020, 1, 1)
data['time'] = pd.date_range(start, end, freq='10T')
data['angles'] = np.random.uniform(low=0.0, high=360.0, size=(len(data.time),))
data.drop(data.index[1500:2000], inplace=True)
def mean2(df):
'''
:param df: 10min Values inside a dataframe for the according hour - DataFrame
:return: df_out: The aggregated dataframe - DataFrame
'''
df_out = pd.DataFrame(columns=df.columns)
try:
df_out.at[0,'angles'] = round(np.rad2deg(circmean(np.deg2rad(df['angles']))),2)
df_out.at[0, 'time'] = df.time.iloc[0]
df_out.time = pd.to_datetime(df_out.time)
return df_out
except:
return df_out
start_time = time.time()
data_hourly = data.groupby([pd.Grouper(key='time',freq='1H')], as_index=False).apply(mean2)
print("--- %s seconds ---" % (time.time() - start_time))
您的 mean2
函数中发生了很多无用的事情。
当函数应用于 groupby
时,pandas 将自动重新创建一个新的数据框,无需在您的函数中执行一些奇怪的列/索引访问。此外,pandas访问特定列/索引对的数据(at
方法)确实很昂贵。
下面是一种效率更高的简单方法:
import time
import pandas as pd
from datetime import datetime
import numpy as np
from scipy.stats import circmean
data = pd.DataFrame()
start = datetime(2015, 1, 1)
end = datetime(2020, 1, 1)
data['time'] = pd.date_range(start, end, freq='10T')
data['angles'] = np.random.uniform(low=0.0, high=360.0, size=(len(data.time),))
data.drop(data.index[1500:2000], inplace=True)
def circular_mean(x):
return round(np.rad2deg(circmean(np.deg2rad(x['angles'].values))),2)
start_time = time.time()
data.index = data['time']
data_hourly = data.resample(rule='1H').apply(circular_mean)
print("--- %s seconds ---" % (time.time() - start_time))
我需要你的帮助来制定一种更快地分组 10 分钟 angular/circular 数据的方法。由于循环数据的取值范围是0到360,普通的均值并不能捕捉到0到360之间的关系。因此,我想用scipy.statscircmean来完成循环均值。我已经发现 pd.groupby 中实现的 apply() 方法非常慢(标准联想笔记本电脑为 120 秒),类似于将每 10 分钟的数据转换为每小时的组,然后对这些组应用循环平均值。
此外,我使用的数据集可能包含非连续的时间戳。不过,有没有办法加快以下代码的速度(例如通过矢量化)?
非常感谢您的帮助。如果您需要这方面的更多信息,请告诉我。
import time
import pandas as pd
from datetime import datetime
import numpy as np
from scipy.stats import circmean
data = pd.DataFrame()
start = datetime(2015, 1, 1)
end = datetime(2020, 1, 1)
data['time'] = pd.date_range(start, end, freq='10T')
data['angles'] = np.random.uniform(low=0.0, high=360.0, size=(len(data.time),))
data.drop(data.index[1500:2000], inplace=True)
def mean2(df):
'''
:param df: 10min Values inside a dataframe for the according hour - DataFrame
:return: df_out: The aggregated dataframe - DataFrame
'''
df_out = pd.DataFrame(columns=df.columns)
try:
df_out.at[0,'angles'] = round(np.rad2deg(circmean(np.deg2rad(df['angles']))),2)
df_out.at[0, 'time'] = df.time.iloc[0]
df_out.time = pd.to_datetime(df_out.time)
return df_out
except:
return df_out
start_time = time.time()
data_hourly = data.groupby([pd.Grouper(key='time',freq='1H')], as_index=False).apply(mean2)
print("--- %s seconds ---" % (time.time() - start_time))
您的 mean2
函数中发生了很多无用的事情。
当函数应用于 groupby
时,pandas 将自动重新创建一个新的数据框,无需在您的函数中执行一些奇怪的列/索引访问。此外,pandas访问特定列/索引对的数据(at
方法)确实很昂贵。
下面是一种效率更高的简单方法:
import time
import pandas as pd
from datetime import datetime
import numpy as np
from scipy.stats import circmean
data = pd.DataFrame()
start = datetime(2015, 1, 1)
end = datetime(2020, 1, 1)
data['time'] = pd.date_range(start, end, freq='10T')
data['angles'] = np.random.uniform(low=0.0, high=360.0, size=(len(data.time),))
data.drop(data.index[1500:2000], inplace=True)
def circular_mean(x):
return round(np.rad2deg(circmean(np.deg2rad(x['angles'].values))),2)
start_time = time.time()
data.index = data['time']
data_hourly = data.resample(rule='1H').apply(circular_mean)
print("--- %s seconds ---" % (time.time() - start_time))