在Pandas中,在Categorical系列上调用value_counts将确保每个可能的值都得到一个计数,即使该计数为零,所有这些都是微妙的,轻度记录的,可能很少关心,但要紧紧抓住。我们要掉进兔子洞了。
假设我定义了一个DataFrame,其中有两个Categorical列,如下所示:
import pandas as pd
abc_categorical = pd.CategoricalDtype(['a', 'b', 'c'], ordered=True)
size_categorical = pd.CategoricalDtype(['s', 'm', 'l'], ordered=True)
df = pd.DataFrame({
'a': pd.Categorical(list('aaabababababa'), dtype=abc_categorical),
'tsize': pd.Categorical(list('smmssmlmlslsl'), dtype=size_categorical),
}
)
a tsize
0 a s
1 a m
2 a m
3 b s
4 a s
5 b m
6 a l
7 b m
8 a l
9 b s
10 a l
11 b s
12 a l
Series.value_counts
我没有'a'列的值为'c'的行,所以Series.value_counts给我们一个零计数。
df.a.value_counts(sort=False)
a 8
b 5
c 0
Name: a, dtype: int64
因为我们费心定义了一个Categorical,Pandas知道列'a'可以取值'c',但这在数据中从未发生过,所以我们得到了0。到目前为止,一切顺利。
DataFrame.value_counts
然而,如果我调用DataFrame.value_counts来计算两列的组合值,那么对于'b'和'l'组合,我也不会得到零,其中有零,而'c'则没有。
df.value_counts(sort=False)
a tsize
a s 2
m 2
l 4
b s 3
m 2
dtype: int64
真扫兴!
交叉表?
pandas.crosstab函数做得稍微好一点,对'b'和'l'的计数为零,但仍然忽略了'c'值。
pd.crosstab(df.a, df.tsize)
tsize s m l
a
a 2 2 4
b 3 2 0
预期结果
我认为DataFrame.value_counts应该返回如下内容:
count
a tsize
a s 2
m 2
l 4
b s 3
m 2
l 0
c s 0
m 0
l 0
value_counts应该和Series.value_counts做同样的事情,或者至少提供一个选项来这样做,也许是“value_counts(include_zeros=True)"。对于这一点,交叉表也应该这样做。
我的实际问题
我的问题是:有没有一种简洁的惯用方法让Pandas来计算类别的计数值 *,包括那些计数为零的类别 *?
注:在Pandas 2.0.1的上下文中询问
1条答案
按热度按时间6psbrbz91#
是的,DataFrame.groupby尊重Categorical!
Groupby
DataFrameGroupBy.size以Series的形式返回每个组中的行数,该Series的索引是两个分类类型的乘积。
太棒了!所有的数和零。此外,请注意,T恤的大小是在适当的小,中,大的顺序,而不是字母顺序。这要归功于另一个聪明的Pandas工具包。
分类索引
索引打印本身的方式使它看起来像一个字符串元组数组,但这不是它的本质。
Pandas提供了一个CategoricalIndex,如果我们深入到MultiIndex的级别,我们可以看到它们在工作。
数据透视表
为了完整性,pivot_table也尊重Categoricals,并给出与groupby相同的结果。
观察选项
如果你 * 不想要 * 零呢?groupby和pivot_table都接受默认为False的“observed”参数。如果observed设置为True,我们只获得分类分组的观察值,复制value_counts的行为。
好极了!