Как сделать кросс-таблицу pandas с процентами?
Учитывая данные с различными категориальными переменными, как мне вернуть перекрестную таблицу с процентами вместо частот?
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
Использование параметра полей в кросс-таблице для вычисления итогов строк и столбцов приближает нас настолько, чтобы думать, что это должно быть возможно с помощью aggfunc или groupby, но мой скудный мозг не может это продумать.
B A B C
A
one .33 .33 .33
three .33 .33 .33
two .33 .33 .33
Ответы
Ответ 1
pd.crosstab(df.A, df.B).apply(lambda r: r/r.sum(), axis=1)
В основном у вас есть функция, которая выполняет row/row.sum()
, и вы используете apply
с axis=1
чтобы применить ее по строке.
(Если вы делаете это в Python 2, вы должны использовать from __future__ import division
чтобы деление всегда возвращало float.)
Ответ 2
Начиная с 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
Где вы можете нормализовать all
или all
, index
(строки) или columns
.
Более подробная информация содержится в документации.
Ответ 3
Мы можем показать его в процентах путем умножения на 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
Где я округлен для удобства.
Ответ 4
Если вы ищете процент от общего количества, вы можете разделить на len df вместо суммы строки:
pd.crosstab(df.A, df.B).apply(lambda r: r/len(df), axis=1)
Ответ 5
Другой вариант - использовать div, а не применять:
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')):
In [13]: res.astype('float').div(res.sum(axis=1), axis=0)
Out[13]:
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
Ответ 6
Нормализация индекса просто сработает. Используйте параметр normalize = "index"
в pd.crosstab()
.