在Pandas中,有一种非常简洁的方法可以按操作计算组内列中的不同值。例如
ex = pd.DataFrame([[1, 2, 3], [6, 7, 8], [1, 7, 9]],
columns=["A", "B", "C"]).set_index(["A", "B"])
ex.groupby(level="A").C.nunique()
将返回
A
1 2
6 1
Name: C, dtype: int64
我还希望在按B
分组时计算索引级A
中的不同值。我找不到从B
对象访问groupby
级别的简洁方法。我能想到的最好的是:
ex.reset_index("B", drop=False).groupby(level="A").B.nunique()
正确返回:
A
1 2
6 1
Name: B, dtype: int64
我有没有办法在groupby上执行此操作而不重置索引或使用apply
函数?
答案 0 :(得分:4)
IIUC您可以为所有级别reset_index
执行,然后将groupby设为'A'并应用nunique
方法:
res = ex.reset_index().groupby('A').agg(lambda x: x.nunique())
In [339]: res
Out[339]:
B C
A
1 2 2
6 1 1
与pivot_table
相同的解决方案:
In [341]: ex.reset_index().pivot_table(index='A', aggfunc=lambda x: x.nunique())
Out[341]:
B C
A
1 2 2
6 1 1
答案 1 :(得分:1)
不确定这是否更好,但它不使用应用或重置索引:)
In [20]: ex.groupby(level="A").agg(lambda x: x.index.get_level_values(1).nunique())
Out[20]:
C
A
1 2
6 1
FWIW,我发现在开发一个复杂的群体时打破这些是有用的。您可以通过
查看您将使用的各个对象In [24]: ex.groupby(level="A").get_group(1)
Out[24]:
C
A B
1 2 3
7 9
合:
In [33]: (ex.groupby(level='A')
....: .C.agg({'a': lambda x: x.index.get_level_values(1).nunique(),
....: 'b': 'nunique'}))
Out[33]:
b a
A
1 2 2
6 1 1
答案 2 :(得分:0)
为了您的娱乐,使用reset_index
,apply
或agg
或匿名功能的不那么容易读出的解决方案。但是,它确实使用了标准库中的zip
和Counter
。
import pandas as pd
from collections import Counter
ex = pd.DataFrame([[1, 2, 3], [6, 7, 8], [1, 7, 9]],
columns=["A", "B", "C"]).set_index(["A", "B"])
A_val, nunique_B = zip(*[(k, len(Counter(v.index.labels[v.index.names.index('B')])))
for k, v in ex.groupby(level='A')])
pd.Series(nunique_B, index=pd.Int64Index(A_val, name='A'))
返回
A
1 2
6 1
dtype: int32
另外,为了一般性,我不认为B
处于索引的第1级。