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))