pandas 创建具有移动求和的列

z0qdvdin  于 2023-02-11  发布在  其他
关注(0)|答案(1)|浏览(107)

我有一个时间序列数据和一个带有时间戳的非连续数据日志。我想将后者与时间序列数据合并,并创建一个带有列值的新列。
设时间序列数据为:

import pandas as pd
import numpy as np
df = pd.DataFrame(index=pd.date_range(freq=f'{5}T',start='2020-10-10',periods=(12)*24*5))
df['col'] = np.random.random_integers(1, 100, size= df.shape[0])
df['uid'] = 1
df2 = pd.DataFrame(index=pd.date_range(freq=f'{5}T',start='2020-10-10',periods=(12)*24*5))
df2['col'] = np.random.random_integers(1, 50, size= df2.shape[0])
df2['uid'] = 2
df3=pd.concat([df, df2]).reset_index()
df3= df3.rename(columns={'index': 'timestamp'})

    timestamp             col   uid
0   2020-10-10 00:00:00   96     1
1   2020-10-10 00:05:00   47     1
2   2020-10-10 00:10:00   78     1
3   2020-10-10 00:15:00   27     1    
...

设日志数据为:

import datetime as dt
 df_log=pd.DataFrame(np.array([[100, 1, 3], [40, 2, 6], [50, 1, 5], [60, 2, 9], [20, 1, 2], [30, 2, 5]]),
                   columns=['duration', 'uid', 'factor'])

df_log['timestamp'] = pd.Series([dt.datetime(2020,10,10, 15,21), dt.datetime(2020,10,10, 16,27),
                dt.datetime(2020,10,11, 21,25), dt.datetime(2020,10,11, 10,12),
                dt.datetime(2020,10,13, 20,56), dt.datetime(2020,10,13, 13,15)])

    duration   uid  factor  timestamp
0    100        1     3     2020-10-10 15:21:00
1    40         2     6     2020-10-10 16:27:00
...

我想合并这两个列(df_merged),并在时间序列数据中创建新列(相对于uid):

df_merged['new'] = df_merged['duration] * df_merged['factor']

用这个值填充df_merged['new'],直到每个uid的下一个日志,然后对下一个日志和总和执行相同的操作,并使其成为移动的2天平均值。
谁能给我指出解决这个问题的方向?
预期输出:

timestamp             col   uid  duration  factor  new
0   2020-10-10 15:20:00   96     1     100      3      300
1   2020-10-10 15:25:00   47     1     100      3      300
2   2020-10-10 15:30:00   78     1     100      3      300
...
    2020-10-11 21:25:00   ..     1     60       9     540+300 
    2020-10-11 21:30:00   ..     1     60       9     540+300
... 
    2020-10-13 20:55:00   ..     1     20       2     40+540
    2020-10-13 21:00:00   ..     1     20       2     40+540
    ..
    2020-10-13 21:25:00   ..     1     20       2      40
vohkndzv

vohkndzv1#

据我所知,在合并之前计算df_log上的new列更简单,只需使用rolling计算每个uid组的窗口:

df_log["new"] = df_log["duration"] * df_log["factor"]
# 2 day rolling window summing `new`
df_log = df_log.groupby("uid").rolling("2d", on="timestamp")["new"].sum().to_frame()

合并很简单:

# prepare for merge
df_log = df_log.sort_values(by="timestamp")
df3 = df3.sort_values(by="timestamp")

df_merged = (
    pd.merge_asof(df3, df_log, on="timestamp", by=["uid"])
    .dropna()
    .reset_index(drop=True)
)

此解决方案与预期输出略有偏差。连续序列(df3)中包含的第一行将位于时间戳2020-10-10 15:25:00而不是2020-10-10 15:20:00处,因为merge方法将查找df_log中早于df3中的时间戳的最后一个时间戳。
或者,如果您要求输出中的第一行具有时间戳2020-10-10 15:20:00,则可以在pd.merge_asof中使用direction="forward",这将使每一行都与df_log中的第一行匹配,并且时间戳晚于df3中的时间戳,因此您需要删除每个uid开头的额外行。

相关问题