如何使用滚动汇总函数控制Pandas groupby返回的索引

6

我有一些带有多级索引的数据,就像这样:

import itertools
idx1 = list('XYZ')
idx2 = range(3)
idx = pd.MultiIndex.from_tuples(list(itertools.product(idx1,idx2)))
df = pd.DataFrame(np.random.rand(9,4), columns=list('ABCD'), index=idx)

                     A         B         C         D
first second                                        
X     0       0.808432  0.708881  0.411515  0.704168
      1       0.322688  0.093869  0.651238  0.146480
      2       0.800746  0.156890  0.131700  0.220423
Y     0       0.102290  0.129895  0.939147  0.510555
      1       0.462014  0.749873  0.585867  0.357788
      2       0.794327  0.141203  0.414841  0.923480
Z     0       0.557513  0.768428  0.487475  0.824503
      1       0.258303  0.115791  0.102588  0.062753
      2       0.934960  0.700371  0.319663  0.642070

以下是按第一个索引级别分组求和的结果:

In[]: df.groupby(level=0).sum()
Out[]: 
              A         B         C         D
first                                        
X      1.931866  0.959640  1.194453  1.071071
Y      1.358631  1.020971  1.939855  1.791824
Z      1.750776  1.584590  0.909725  1.529326

看起来很合理-我对索引的第一层进行了求和,因此第二层消失了。但是,如果我使用rolling方法:

df.groupby(level=0).rolling(2).sum()

我明白了

                           A         B         C         D
first first second                                        
X     X     0            NaN       NaN       NaN       NaN
            1       1.131120  0.802750  1.062753  0.850648
            2       1.123434  0.250759  0.782938  0.366903
Y     Y     0            NaN       NaN       NaN       NaN
            1       0.564303  0.879768  1.525014  0.868343
            2       1.256341  0.891075  1.000708  1.281269
Z     Z     0            NaN       NaN       NaN       NaN
            1       0.815816  0.884219  0.590062  0.887256
            2       1.193263  0.816162  0.422251  0.704823

为某种原因,pandas决定返回一个3级索引,重复第一级。 为什么会这样?有没有更好的方法来编写我的代码,使其不会这样做?

而且,由于第一个标签被重复,对结果调用reset_index()会导致ValueError: cannot insert first, already exists,因此我不知道如何删除重复的索引。有什么技巧吗?

1个回答

4
使用group_keys=False
In [43]: df.groupby(level=0, group_keys=False).rolling(2).sum()
Out[43]: 
            A         B         C         D
X 0       NaN       NaN       NaN       NaN
  1  1.244257  1.430957  0.798310  0.779261
  2  0.632238  1.512251  1.473498  0.395945
Y 0       NaN       NaN       NaN       NaN
  1  1.241747  0.865178  0.550665  1.070216
  2  1.629892  1.328947  1.046749  1.167371
Z 0       NaN       NaN       NaN       NaN
  1  0.406606  0.945525  0.936090  1.301093
  2  0.701282  0.975851  0.586523  0.698980

与此相反:
In [44]: df.groupby(level=0, group_keys=True).rolling(2).sum()
Out[44]: 
              A         B         C         D
X X 0       NaN       NaN       NaN       NaN
    1  1.244257  1.430957  0.798310  0.779261
    2  0.632238  1.512251  1.473498  0.395945
Y Y 0       NaN       NaN       NaN       NaN
    1  1.241747  0.865178  0.550665  1.070216
    2  1.629892  1.328947  1.046749  1.167371
Z Z 0       NaN       NaN       NaN       NaN
    1  0.406606  0.945525  0.936090  1.301093
    2  0.701282  0.975851  0.586523  0.698980

顺便提一下,如果你发现自己卡在了一个想要删除的多重索引级别上,可以使用 MultiIndex.droplevel 方法
result = df.groupby(level=0, group_keys=True).rolling(2).sum()
result.index = result.index.droplevel(level=0)

谢谢。由于某些原因,这在我的真实数据上无法正常工作。我会尝试在一秒钟内发布一些真实数据的链接。您是否有预期它无法正常工作的情况? - itzy
我不知道有什么需要注意的地方,所以我很想看到一个能够重现问题的例子。无论如何,我还添加了一种替代方法——使用“droplevel”。 - unutbu
1
非常感谢您提供如此详细的信息,这对我很有帮助。看起来即使在 group_keys=False 的情况下,如果我使用 df.groupby()['A']... 而不是 df['A'].groupby()...,我仍会得到额外的键。我不确定这是否是设计上的问题还是一个 bug -- 我认为这两个应该具有相同的输出结果。 - itzy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接