Pandas 在时间滚动窗口中查找最大值。

5

我有一张名为df的表格,其中包含"timestamp""Y"两列。我想要添加另外一列"MaxY",这一列包含未来24小时内最大的Y值。也就是说

df.MaxY.iloc[i] = df[(df.timestamp > df.timestamp.iloc[i]) &
                     (df.timestamp < df.timestamp.iloc[i] + timedelta(hours=24))].Y.max()

很显然,像这样计算非常缓慢。有更好的方法吗?

在计算“SumY”时,我可以使用cumsum()技巧来完成。但是在这里,类似的技巧似乎不起作用。

根据要求,这里提供一个示例表格(MaxY是输出结果。输入仅为前两列)。

-------------------------------
| timestamp        | Y | MaxY |
-------------------------------
| 2016-03-29 12:00 | 1 |   3  |  rows 2 and 3 fall within 24 hours, so MaxY = max(2,3)
| 2016-03-29 13:00 | 2 |   4  |  rows 3 and 4 fall in the time interval, so MaxY = max(3, 4)
| 2016-03-30 11:00 | 3 |   4  |  rows 4, 5, 6 all fall in the interval so MaxY = max(4, 3, 2)
| 2016-03-30 12:30 | 4 |   3  |  max (3, 2)
| 2016-03-30 13:30 | 3 |   2  |  row 6 is the only row in the interval
| 2016-03-30 14:00 | 2 | nan? |  there are no rows in the time interval. Any value will do.
-------------------------------

帮助我们帮助您!请提供一个包含5-7行数据的样本数据集,并基于提供的样本提供期望的输出/结果集。 - MaxU - stand with Ukraine
@JohnE,据我所知,rolling()仅适用于固定行数的窗口。我的是针对固定时间间隔的。 - Karolis Juodelė
@MaxU,我希望一个天真的代码片段足够好。现在我也添加了一个表格。更清晰了吗? - Karolis Juodelė
@JohnE,我也尝试使用“rolling”和“resample”,但是我做不好。你能否给我们指条明路?谢谢! - MaxU - stand with Ukraine
@MaxU 好的,就为你试了一下。;-) 比我想象的要棘手,但我认为它现在正常工作。 - JohnE
3个回答

2
这里介绍一种使用resample/rolling的方法。在使用pandas 0.18.0和python 3.5时,我遇到了一个奇怪的警告。我认为这不是个问题,但不确定为何会产生这种警告。
如果索引不是'timestamp',则需要先使用df = df.set_index('timestamp')命令。
>>> df2 = df.resample('30min').sort_index(ascending=False).fillna(np.nan)
>>> df2 = df2.rolling(48,min_periods=1).max()
>>> df.join(df2,rsuffix='2')

                     Y   Y2
timestamp                  
2016-03-29 12:00:00  1  3.0
2016-03-29 13:00:00  2  4.0
2016-03-30 11:00:00  3  4.0
2016-03-30 12:30:00  4  4.0
2016-03-30 13:30:00  3  3.0
2016-03-30 14:00:00  2  2.0

在这个小数据框中,看起来速度大约快了两倍,但你需要在一个更大的数据框上进行测试,以获得相对速度的合理想法。希望这些内容有点自解释性。升序排序是必要的,因为根据我的观察,滚动只允许向后或居中窗口。

谢谢你加加!我之前一直在使用“1H”的频率操作,但是结果总是不佳。为什么现在改用“30min”的频率就成功了呢? - MaxU - stand with Ukraine
@MaxU,数据中有一些时间如12:30和13:30,所以可能不会完全相同,会有1小时的差异吗? - JohnE
我现在明白了,谢谢你的解决方案和解释! - MaxU - stand with Ukraine
那在真实数据上并不是很好。resample()的参数要么很小,从而会使表格膨胀(特别是如果其中有任何时间间隔),要么就会很大,从而产生错误的数字(也许我可以容忍这种情况)。 - Karolis Juodelė
@KarolisJuodelė 你真的试过吗?如果在实际数据上它不比你的方法更快,我会感到惊讶,因为你的方法基本上是做了2*n^2个不等式测试,随着数据变得越来越大,速度会越来越慢。你提出的关于重新采样和数据精细程度的观点是公正的,但我不确定是否有什么可以做的——尽管如果重新采样足够快,你可以使其非常精细。 - JohnE
我会先尝试提议的方法,但如果那不是一个足够好的解决方案,你可以看看这里:http://pandas.pydata.org/pandas-docs/stable/timeseries.html#sparse-resampling - JohnE

0

出了什么问题

df['MaxY'] = df[::-1].Y.shift(-1).rolling('24H').max()

df[::-1] 反转了 df(你想要它“倒过来”),shift(-1) 处理了“未来”的情况。


0
考虑使用 apply() 函数来提高运行速度的解决方案。该函数返回每行时间条件序列的最大值。
import pandas as pd
from datetime import timedelta

def daymax(row):         
    ser = df.Y[(df.timestamp > row) &
               (df.timestamp <= row + timedelta(hours=24))]
    return ser.max()

df['MaxY'] = df.timestamp.apply(daymax)

print(df)

#            timestamp  Y  MaxY
#0 2016-03-29 12:00:00  1   3.0
#1 2016-03-29 13:00:00  2   4.0
#2 2016-03-30 11:00:00  3   4.0
#3 2016-03-30 12:30:00  4   3.0
#4 2016-03-30 13:30:00  3   2.0
#5 2016-03-30 14:00:00  2   NaN

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