在相同索引多次出现的不规则数据集上使用pandas计算滚动中值的有效方法



我有一个不规则的数据集,其中一些索引显示多次,现在想要计算一个浮动中位数,一次基于epoch之前的时间跨度,一次基于epoch之后的时间跨度。

Pandas的rolling选项会很好,但是,如果某些索引出现多次,它就不能很好地工作了…

我写了一个函数来计算我想要的结果。然而,我认为这可能不是最有效的实现,可能有一个更优雅的解决方案,直接使用pandas。

代码如下:fun是我在前两天的基础上实现的,接下来2天的fun2相同。rolling尝试做同样的事情,但给出了不同的结果,以防某些索引出现的次数多于一次。

import numpy as np
import pandas as pd
def dummy_data():
idx = np.array([pd.Timestamp(year=2021, month=1, day=1, hour=1),
pd.Timestamp(year=2021, month=1, day=2, hour=2),
pd.Timestamp(year=2021, month=1, day=3, hour=5),
pd.Timestamp(year=2021, month=1, day=3, hour=5),
pd.Timestamp(year=2021, month=1, day=3, hour=5),
pd.Timestamp(year=2021, month=1, day=8, hour=15),
pd.Timestamp(year=2021, month=1, day=9, hour=18),
pd.Timestamp(year=2021, month=1, day=10, hour=14),
])
data = np.array([1, 2, 3, 4, 5, 6, 7, 8])
return pd.DataFrame(data, index=idx, columns=["l"])
def rolling_median_irregular(ds, left, right):
res = pd.Series(index=ds.index, dtype=np.float64)
for t in ds.index:
val = ds.loc[(ds.index >= t - left) & (ds.index <= t + right)].median()
res.loc[t] = val
return res
if __name__ == "__main__":
df = dummy_data()
df["fun"] = rolling_median_irregular(df["l"], left=pd.Timedelta(days=2), right=pd.Timedelta(days=0))
df["rolling"] = df["l"].rolling("2D").median()
df["fun2"] = rolling_median_irregular(df["l"], left=pd.Timedelta(days=0), right=pd.Timedelta(days=2))
df["rolling2"] = df.loc[::-1, 'l'].rolling("2D").median().loc[::-1]
print(df.head(10))

rolling的问题是,对于2021-01-03索引,它将不能正常工作,因为它不理解这个索引显示多次。比较第三行。正确的中位数应该是3.5,因为时间跨度涵盖了[2 3 4 5]rolling函数列出2.5,因为它认为时间范围只包含值[2 3]。在第5行,rolling是正确的,因为现在它考虑了所有2021-01-03的数据。

l  fun  rolling  fun2  rolling2
2021-01-01 01:00:00  1  1.0      1.0   1.5       1.5
2021-01-02 02:00:00  2  1.5      1.5   3.5       3.5
2021-01-03 05:00:00  3  3.5      2.5   4.0       4.0
2021-01-03 05:00:00  4  3.5      3.0   4.0       4.5
2021-01-03 05:00:00  5  3.5      3.5   4.0       5.0
2021-01-08 15:00:00  6  6.0      6.0   7.0       7.0
2021-01-09 18:00:00  7  6.5      6.5   7.5       7.5
2021-01-10 14:00:00  8  7.0      7.0   8.0       8.0

我会寻找一个更好的(更快/更容易/更灵活)实现我的rolling_median_irregular实现。

如果外缘(不是参考epoch)包含在计算中或不包含在计算中并不重要,因为我的数据是不规则的,精确到毫秒,因此几乎永远不会出现一个epoch直接位于边缘的情况。

您可以使用rolling函数,但是您需要删除" error "通过在索引上使用duplicated行,一旦使用keep='最后'和一次'第一',这取决于你滚动的方向。然后,由于索引对齐,即使对于重复项,它也会填充所需的值。

df['roll_test'] = df['l'].rolling("2D").median()[~df.index.duplicated(keep='last')]
df['roll_test2'] = (df.loc[::-1, 'l'].rolling("2D").median()
.loc[::-1][~df.index.duplicated(keep='first')])
print(df)
l  fun  rolling  fun2  rolling2  roll_test  roll_test2
2021-01-01 01:00:00  1  1.0      1.0   1.5       1.5        1.0         1.5
2021-01-02 02:00:00  2  1.5      1.5   3.5       3.5        1.5         3.5
2021-01-03 05:00:00  3  3.5      2.5   4.0       4.0        3.5         4.0
2021-01-03 05:00:00  4  3.5      3.0   4.0       4.5        3.5         4.0
2021-01-03 05:00:00  5  3.5      3.5   4.0       5.0        3.5         4.0
2021-01-08 15:00:00  6  6.0      6.0   7.0       7.0        6.0         7.0
2021-01-09 18:00:00  7  6.5      6.5   7.5       7.5        6.5         7.5
2021-01-10 14:00:00  8  7.0      7.0   8.0       8.0        7.0         8.0

最新更新