为什么groupby不能在索引级别之间正确求和

时间:2017-04-18 23:56:52

标签: python pandas

考虑数据框d1d2

d1 = pd.DataFrame(dict(
        A=list('111222'),
        B=list('xyzxyz'),
        C=range(6)
    ))

d2 = pd.DataFrame(dict(
        A=list('111222'),
        B=list('xyzxyz'),
        C=range(6)
    ))

我想连接这些并执行groupby

df = pd.concat([d.set_index('A') for d in [d1, d2]], keys=['d1', 'd2'])
print(df)

      B  C
   A      
d1 1  x  0
   1  y  1
   1  z  2
   2  x  3
   2  y  4
   2  z  5
d2 1  x  0
   1  y  1
   1  z  2
   2  x  3
   2  y  4
   2  z  5

但是,当我执行groupbysum

df.groupby(level='A').C.sum()

A
1     0
1     2
1     4
2     6
2     8
2    10
Name: C, dtype: int64

这完全不是我所期待的。

我可以将df拆开并再次将其重新组合,然后执行groupby ...
我期待这个

pd.DataFrame(
    df.values,
    pd.MultiIndex.from_tuples(df.index.values, names=df.index.names),
    df.columns.values
).groupby(level='A').C.sum()

A
1     6
2    24
Name: C, dtype: int64

任何人都可以解释出现了什么问题吗?

2 个答案:

答案 0 :(得分:1)

我相信这是一个错误。使索引成为MultiIndex是一个可行的小黑客

df = pd.concat([d.set_index(['A', [np.nan]*len(d))]) for d in [d1, d2]], keys=['d1', 'd2'])

另一种解决方案是反转其中一个DataFrames

df = pd.concat([d.set_index(['A']) for d in [d1, d2.sort_index(ascending=False)]], 
               keys=['d1', 'd2'])

具体而言,在具有相同索引的数据帧(具有键的规范的非multiIndex)的串联中,创建的新MultiIndex获得与原始标签无关的标签0,...,len(d)。 (如果查看索引,您会看到每个标签具有不同ID的多个副本)。

具体来说,这是由pandas.core.reshape.concat

中的以下代码片段引起的
def _make_concat_multiindex(indexes, keys, levels=None, names=None):
    ...   
    ...  # Somewhere here we treat the non identical axis
    ...
    if isinstance(new_index, MultiIndex):
        new_levels.extend(new_index.levels)
        new_labels.extend([np.tile(lab, kpieces) for lab in new_index.labels])
    else:
        new_levels.append(new_index)
        new_labels.append(np.tile(np.arange(n), kpieces))

因此,如果索引已经不是多索引,则分配的标签为np.arange(n)

答案 1 :(得分:1)

keys移除concat()参数将允许您所需的groupby()成功:

df = pd.concat([d.set_index('A') for d in [d1, d2]])
df.groupby(level='A').C.sum()

或者,如果keys需要保留,您可以使用reset_index()和重复groupby()到达那里:

df = pd.concat([d.set_index('A') for d in [d1, d2]], keys=['d1', 'd2'])
(df.groupby(level='A').sum()
   .reset_index()
   .groupby('A').sum()
)