Pandas - 在特定时间间隔内累积值
假设我有
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' 的情况,我同意我们还是没有得到想要的结果。