我有一个带有MultiIndex的pandas DataFrame,如下所示:
>>> import pandas as pd
>>> category = ['bar', 'bar', 'bar', 'bar', 'bar', 'baz', 'baz', 'baz', 'baz',
'baz', 'baz', 'foo', 'foo', 'foo']
>>> timestamp = ['2017-01-01 09:00:00', '2017-01-01 09:01:00', '2017-01-01 09:02:00',
'2017-01-01 09:03:00', '2017-01-01 09:04:00', '2016-11-18 03:18:00',
'2016-11-18 03:19:00', '2016-11-18 03:20:00', '2016-11-18 03:21:00',
'2016-11-18 03:22:00', '2016-11-18 03:23:00', '2017-02-03 20:39:00',
'2017-02-03 20:40:00', '2017-02-03 20:41:00']
>>> values = [1,1,2,2,2,35,3,3,4,4,4,28,28,28]
>>> tuples = list(zip(*[category,timestamp]))
>>> index = pd.MultiIndex.from_tuples(tuples, names=['category', 'timestamp'])
>>> df = pd.DataFrame(values,index=index,columns=['values'])
>>> df
values
category timestamp
bar 2017-01-01 09:00:00 1
2017-01-01 09:01:00 1
2017-01-01 09:02:00 2
2017-01-01 09:03:00 2
2017-01-01 09:04:00 2
baz 2016-11-18 03:18:00 35
2016-11-18 03:19:00 3
2016-11-18 03:20:00 3
2016-11-18 03:21:00 4
2016-11-18 03:22:00 4
2016-11-18 03:23:00 4
foo 2017-02-03 20:39:00 28
2017-02-03 20:40:00 28
2017-02-03 20:41:00 28
对于每个类别,我想找到值列更改次数的累积总和,如下所示:
values changed cum_changes
category timestamp
bar 2017-01-01 09:00:00 1 False 0
2017-01-01 09:01:00 1 False 0
2017-01-01 09:02:00 2 True 1
2017-01-01 09:03:00 2 False 1
2017-01-01 09:04:00 2 False 1
baz 2016-11-18 03:18:00 35 False 0
2016-11-18 03:19:00 3 True 1
2016-11-18 03:20:00 3 False 1
2016-11-18 03:21:00 4 True 2
2016-11-18 03:22:00 4 False 2
2016-11-18 03:23:00 4 False 2
foo 2017-02-03 20:39:00 28 False 0
2017-02-03 20:40:00 28 False 0
2017-02-03 20:41:00 28 False 0
我试过这样做:
df["changes"] = False
df.iloc[idx[:,1:],1] = df.iloc[idx[:,1:],0] == df.iloc[idx[:,:-1],0] #This doesn't work
df["cum_changes"] = df["changed"].groupby(level=[0]).cumsum().astype(int)
但不幸的是,第二行并不奏效。它类似于使用loc多值索引的方式,但显然iloc不会以相同的方式处理MultiIndex。我无法按标签进行索引,因为每个组中的时间戳不同,我不能使用head(),因为每个组的长度不同。是否可以在MultiIndex的第二级进行位置索引?
我真正需要的是" cum_changes"专栏,"改变"专栏只是一个中间步骤。如果有不同的方法来计算" cum_changes"第I栏我很想听。我知道可以通过迭代类别列来完成,但似乎应该可以保持这个矢量化,所以我正在寻找一个不涉及循环的解决方案。
我发现了这个相关问题,但我不相信它适用,因为解决方案实际上并非按位置编制索引,而是找到与给定位置对应的标签并按标签编制索引: Slice MultiIndex pandas DataFrame by position
答案 0 :(得分:1)
您可以将diff()
用作@Psidom has already said in the comment:
In [25]: df['x'] = df.groupby(level=0)['values'] \
.apply(lambda x: x.diff().fillna(0).ne(0).cumsum())
In [26]: df
Out[26]:
values x
category timestamp
bar 2017-01-01 09:00:00 1 0
2017-01-01 09:01:00 1 0
2017-01-01 09:02:00 2 1
2017-01-01 09:03:00 2 1
2017-01-01 09:04:00 2 1
baz 2016-11-18 03:18:00 35 0
2016-11-18 03:19:00 3 1
2016-11-18 03:20:00 3 1
2016-11-18 03:21:00 4 2
2016-11-18 03:22:00 4 2
2016-11-18 03:23:00 4 2
foo 2017-02-03 20:39:00 28 0
2017-02-03 20:40:00 28 0
2017-02-03 20:41:00 28 0