Pandas Groupby:具有多个类别的“已观察”参数

时间:2019-08-06 22:59:18

标签: python python-3.x pandas

考虑以下带有两个类别列的DataFrame:

df = pd.DataFrame({
    "state": pd.Categorical(["AK", "AL", "AK", "AL"]),
    "gender": pd.Categorical(["M", "M", "M", "F"]),
    "name": list("abcd"),
})

df.groupby()中,默认值为observed=Falseobserved(Pandas 0.25.0)的description为:

  

在使用分类石斑鱼(作为单个石斑鱼,或作为多个石斑鱼的一部分)时,observed关键字控制是否返回所有可能的石斑鱼值的笛卡尔积(observed = False)还是仅那些被观察到的石斑鱼(observed = True)。

因此,这是我期望的结果:

>>> # Expected result
>>> df.groupby(["state", "gender"])["name"].count()
state  gender
AK     M         2
       F         0
AL     F         1
       M         1
Name: name, dtype: int64

这是实际结果:

>>> df.groupby(["state", "gender"])["name"].count()
state  gender
AK     M         2
AL     F         1
       M         1
Name: name, dtype: int64

我在这里误解了描述吗?

此解决方法似乎是一个巨大的痛苦,而observed=False正是应该创建的。我是否缺少其他选择?

>>> idx = pd.MultiIndex.from_product(
...     (
...         df["state"].cat.categories,
...         df["gender"].cat.categories,
...     ),
...     names=["state", "gender"]
... )
>>> df.groupby(["state", "gender"])["name"].count().reindex(idx).fillna(0.).astype(int)
state  gender
AK     F         0
       M         2
AL     F         1
       M         1
Name: name, dtype: int64

3 个答案:

答案 0 :(得分:3)

似乎您放置["name"]的位置正在扔掉它。我认为这可行:

df.groupby(["state", "gender"]).count().fillna(0)["name"]
state  gender
AK     F         0.0
       M         2.0
AL     F         1.0
       M         1.0
Name: name, dtype: float64

以下是一些有用的变体:

In [16]: df.groupby(["state", "gender"], observed=False).count().fillna(0)["name"].astype(int)
Out[16]:
state  gender
AK     F         0
       M         2
AL     F         1
       M         1
Name: name, dtype: int64

In [17]: df.groupby(["state", "gender"], observed=True).count()["name"]
Out[17]:
state  gender
AK     M         2
AL     M         1
       F         1
Name: name, dtype: int64

答案 1 :(得分:1)

我同样不确定observed。但是,您想要的结果并不难得到。跟踪.unstack(fill_value=0).stack()

>>> import pandas as pd
>>> df = pd.DataFrame({
...     "state": pd.Categorical(["AK", "AL", "AK", "AL"]),
...     "gender": pd.Categorical(["M", "M", "M", "F"]),
...     "name": list("abcd"),
... }) 
>>> df.groupby(['state', 'gender'])['name'].count().unstack(fill_value=0).stack()
state  gender
AK     M         2
       F         0
AL     M         1
       F         1
dtype: int64

答案 2 :(得分:1)

使用crosstab

pd.crosstab(df.state,df.gender).stack()
state  gender
AK     F         0
       M         2
AL     F         1
       M         1
dtype: int64