Pandas - 在特定时间间隔内累积值

0 投票
1 回答
2366 浏览
提问于 2025-05-01 08:27

假设我有

df

                          ts  v
0 2014-11-03 03:39:42.200914  1
1 2014-11-03 03:39:42.500914  2
2 2014-11-03 03:39:43.600914  3
3 2014-11-03 03:39:43.620914  4

我想添加一列,使得每一行都包含在1秒的时间范围内,v的总和,比如说

desired_df
   s                         ts  v
0  1 2014-11-03 03:39:42.200914  1
1  3 2014-11-03 03:39:42.500914  2
2  3 2014-11-03 03:39:43.600914  3
3  7 2014-11-03 03:39:43.620914  4

那么,我该如何生成这列s呢?

注意,这些时间段应该是重叠的,但它们必须在数据框的每一行(数据点)上有一个右端点,也就是说,我的数据框中的每一行(数据点)都必须是那个大小的时间段的右端点。

编辑:下面的答案不对?不完整

编辑:我希望这个解决方案能适用于通用的时间间隔,比如14毫秒,而不仅仅是1秒。

那这样怎么样

df['s'] = df.groupby(pd.TimeGrouper(freq='400mS')).transform(numpy.cumsum)

我得到了

                          ts  v  s
0 2014-11-03 03:39:42.200914  1  1
1 2014-11-03 03:39:42.500914  2  2
2 2014-11-03 03:39:43.600914  3  3
3 2014-11-03 03:39:43.620914  4  7

行索引1不是错了吗?在03:39:42.500914时刻的应该是2+1=3,而不是2,因为前两行在400毫秒内,所以应该把它们加在一起。为什么没有这样做呢?

编辑:当我尝试

df['s'] = df.groupby(pd.TimeGrouper(freq='340mS')).transform(numpy.cumsum)

它实际上进行了分组,尽管时间间隔更小:

                            v  s
ts                              
2014-11-03 03:39:42.200914  1  1
2014-11-03 03:39:42.500914  2  3
2014-11-03 03:39:43.600914  3  3
2014-11-03 03:39:43.620914  4  7

那么,TimeGrouper放置的分隔符在哪里?我希望时间段的右端点与我正在查看的行(与对应的行)重合。

暂无标签

1 个回答

3

首先,把 ts 设置为索引,然后用 groupby 按照第二列分组,再用 cumsum() 计算累加和,生成一个新的列 s。最后,使用 reset_index 来重置索引,像这样:

df
                          ts  v
0 2014-11-03 03:39:42.200914  1
1 2014-11-03 03:39:42.500914  2
2 2014-11-03 03:39:43.600914  3
3 2014-11-03 03:39:43.620914  4

df = df.set_index('ts')

df['s'] = df.groupby(lambda x: x.second).transform(cumsum)
df = df.reset_index()
df

                          ts  v  s
0 2014-11-03 03:39:42.200914  1  1
1 2014-11-03 03:39:42.500914  2  3
2 2014-11-03 03:39:43.600914  3  3
3 2014-11-03 03:39:43.620914  4  7

你可能还想重新排列一下列的顺序:

df = df[['s','ts','v']]
df
   s                         ts  v
0  1 2014-11-03 03:39:42.200914  1
1  3 2014-11-03 03:39:42.500914  2
2  3 2014-11-03 03:39:43.600914  3
3  7 2014-11-03 03:39:43.620914  4

更新

根据提问者的更新,如果需要一个通用的方法,可以使用 pd.TimeGrouper

另一个更新(提供了完整步骤)

df = pd.DataFrame([['2014-11-03 03:39:42.200914',1],['2014-11-03 03:39:42.500914', 2],['2014-11-03 03:39:43.600914',3],['2014-11-03 03:39:43.620914', 4]], columns=['ts','v'], dtype=object)

# you will get type error if you haven't converted your string to datetime 
df['ts'] = [pd.to_datetime(d) for d in df['ts']]

df = df.set_index('ts')

看看这一行

# from the doc we need to add closed='left' to include the first nbin count
df['s'] = df.groupby(pd.TimeGrouper(freq='340mS', closed='left')).transform(cumsum)

# reset the index
df = df.reset_index()

# reorder the columns
df = df[['s', 'ts', 'v']]

df
   s                         ts  v
0  1 2014-11-03 03:39:42.200914  1
1  3 2014-11-03 03:39:42.500914  2
2  3 2014-11-03 03:39:43.600914  3
3  7 2014-11-03 03:39:43.620914  4

不过对于 '400mS' 的情况,我同意我们还是没有得到想要的结果。

撰写回答