Python 如何使用百分比制作熊猫交叉表?

Python 如何使用百分比制作熊猫交叉表?,python,pandas,crosstab,Python,Pandas,Crosstab,给定一个具有不同分类变量的数据帧,如何返回带有百分比而不是频率的交叉列表 df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 6, 'B' : ['A', 'B', 'C'] * 8, 'C' : ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 4, 'D' : np.rando

给定一个具有不同分类变量的数据帧,如何返回带有百分比而不是频率的交叉列表

df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 6,
                   'B' : ['A', 'B', 'C'] * 8,
                   'C' : ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 4,
                   'D' : np.random.randn(24),
                   'E' : np.random.randn(24)})


pd.crosstab(df.A,df.B)


B       A    B    C
A               
one     4    4    4
three   2    2    2
two     2    2    2
使用crosstab中的边距选项来计算行和列的总数使我们足够接近于认为使用aggfunc或groupby应该是可行的,但我贫乏的大脑无法思考到底

B       A     B    C
A               
one     .33  .33  .33
three   .33  .33  .33
two     .33  .33  .33
基本上,您只需使用执行
row/row.sum()
的函数,然后使用
apply
axis=1
按行应用它

(如果在Python 2中执行此操作,则应使用来自uuu future uuuu import division的
,以确保division始终返回浮点。)

另一个选项是使用而不是应用:

In [11]: res = pd.crosstab(df.A, df.B)
除以索引的总和:

In [12]: res.sum(axis=1)
Out[12]: 
A
one      12
three     6
two       6
dtype: int64
与上面类似,您需要对整数除法进行一些操作(我使用astype('float'):


如果要查找占总数的百分比,可以除以df的len,而不是行和:

pd.crosstab(df.A, df.B).apply(lambda r: r/len(df), axis=1)

从Pandas 0.18.1开始,有一个
normalize
选项:

In [1]: pd.crosstab(df.A,df.B, normalize='index')
Out[1]:

B              A           B           C
A           
one     0.333333    0.333333    0.333333
three   0.333333    0.333333    0.333333
two     0.333333    0.333333    0.333333
您可以在
所有
索引
(行)或
之间进行标准化


更多详细信息可用。

我们可以用百分比乘以
100

pd.crosstab(df.A,df.B, normalize='index')\
    .round(4)*100

B          A      B      C
A                         
one    33.33  33.33  33.33
three  33.33  33.33  33.33
two    33.33  33.33  33.33

我为了方便而绕道而行

对索引进行规范化很简单。在
pd.crosstab()

中使用参数
normalize=“index”
,您需要一个来自未来导入除法的
来强制对整数进行浮点除法。没错。我在回答中加了这个。(我的shell设置为自动执行此操作,因此我总是忘记需要执行此操作。)@BrenBarn这里axis=1的重要性是什么。。!?真的不懂@罗希思:不知道你不明白什么。正如我在回答中所说,axis=1按行应用函数。否则,百分比将相对于列总计而不是行总计进行计算。您不希望该表是
0.167 0.167 0.167\n 0.083 0.083\n 0.083 0.083 0.083
?我想您特别想要“行内百分比”(例如)。在0.18.1中,看起来您可以传递normalize=“index”此选项的一个好处是,如果包含边际小计,它仍然有效。
In [1]: pd.crosstab(df.A,df.B, normalize='index')
Out[1]:

B              A           B           C
A           
one     0.333333    0.333333    0.333333
three   0.333333    0.333333    0.333333
two     0.333333    0.333333    0.333333
pd.crosstab(df.A,df.B, normalize='index')\
    .round(4)*100

B          A      B      C
A                         
one    33.33  33.33  33.33
three  33.33  33.33  33.33
two    33.33  33.33  33.33