跨时间轴的滑动窗口平均值

5
我有一个大型的时间序列数据集,每隔30分钟进行一次采样,并尝试在这个数据集上进行滑动窗口,但是要针对每天的每个时间点分别进行操作,使用pandas库实现。
我不是统计学家,也不擅长思考或编写此类工作的代码,但这是我想要做的笨拙尝试。我真的希望得到帮助改进它,因为我知道有更好的方法来完成这个任务,可能需要使用MultiIndexes和一些适当的迭代?但我在“时间轴”上遇到了困难。
def sliding_window(run,data,type='mean'):
    data = data.asfreq('30T')
    for x in date_range(run.START, run.END, freq='1d'):
        if int(datetime.strftime(x, "%w")) == 0 or int(datetime.strftime(x, "%w")) == 6:
            points = data.select(weekends).truncate(x - relativedelta(days=run.WINDOW),x + relativedelta(days=run.WINDOW)).groupby(lambda date: minutes(date, x)).mean()
        else:
            points = data.select(weekdays).truncate(x - relativedelta(days=run.WINDOW),x + relativedelta(days=run.WINDOW)).groupby(lambda date: minutes(date, x)).mean()
        for point in points.index:
            data[datetime(x.year,x.month,x.day,point.hour,point.minute)] = points[point]
    return data

run.START、run.END 和 run.WINDOW 是数据中的两个点,时间跨度为 45 天。我已经反复查看了这段代码,不确定其中哪些部分对其他人来说有意义,请尽管问我以便我能澄清任何问题。

解决方案:(解决方案由 crewbum 提供)

修改后的函数在预期内运行得非常快速:

def sliding_window(run,data,am='mean',days='weekdays'):
    data = data.asfreq('30T')
    data = DataFrame({'Day': [d.date() for d in data.index], 'Time': [d.time() for d in data.index], 'Weekend': [weekday_string(d) for d in data.index], 'data': data})
    pivot = data.pivot_table(values='data', rows='Day', cols=['Weekend', 'Time'])
    pivot = pivot[days]
    if am == 'median':
        mean = rolling_median(pivot, run.WINDOW*2, min_periods=1)
    mean = rolling_mean(pivot, run.WINDOW*2, min_periods=1)
    return DataFrame({'mean': unpivot(mean), 'amax': np.tile(pivot.max().values, pivot.shape[0]), 'amin': np.tile(pivot.min().values, pivot.shape[0])}, index=data.index)

非逆波函数:

def unpivot(frame):
    N, K = frame.shape
    return Series(frame.values.ravel('C'), index=[datetime.combine(d[0], d[1]) for d in zip(np.asarray(frame.index).repeat(K), np.tile(np.asarray(frame.ix[0].index), N))])

目前,sliding_mean 中的 center=True 功能好像有些问题,如果我有机会的话,我将在 Github 上提交此问题。


你有看过/尝试过内置的滚动均值函数吗?http://pandas.pydata.org/pandas-docs/stable/generated/pandas.stats.moments.rolling_mean.html?highlight=rolling#pandas.stats.moments.rolling_mean - Garrett
试图弄清楚你想做什么:你想在-45到+45天的范围内平均所有值,但按每个24小时时间点分组。例如,平均所有13:00的数据(91个),并单独平均所有13:30等的数据。因为“执行滑动窗口”相当模糊:滑动窗口是什么? - user707650
另外,为什么要将工作日和周末分开呢?我猜这只是考虑到所处理的数据而做出的逻辑划分吧? - user707650
2
最后(将不同的事情分开评论):是否实际上有一些东西不按照您想要的方式工作?您没有说它不起作用,只是想改进它。以哪种方式?更少的代码,应该运行得更快,更灵活?也许http://codereview.stackexchange.com/更适合您的目的。 - user707650
Evert - “然后在13:30等分别对所有数据取平均值” 正是我的想法。我正在处理大量的电力需求数据,工作日和周末差异巨大。这个过程相当缓慢,我有一种预感,使用多索引将使许多操作更加简便,只是希望能够有时间学习并增强pandas技能! - Ben Hussey
1个回答

4
如果你对MultiIndexes感兴趣,可以查看df.pivot_table()。当传递多个键到行和/或列参数时,它将自动创建MultiIndex。
例如,假设您想为每个周末和非周末的每个30分钟时间块创建单独的列来枢轴数据;您可以通过向DataFrame添加Day,Weekend和TOD(时间)列,然后将这些列名传递给pivot_table来实现。
pivot = df.pivot_table(values='Usage', rows='Day', cols=['TOD', 'Weekend'])

在这种格式下,pd.rolling_mean()(或者您自己创建的函数)可以轻松地应用于pivot的列。像pandas中所有的滚动/移动函数一样,pd.rolling_mean()甚至接受一个center参数来进行中心滑动窗口。
pd.rolling_mean(pivot, 90, center=True, min_periods=1)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接