pandasのcrosstabでクロス集計(カテゴリ毎の出現回数・頻度を算出)

pandas.crosstab()関数を使うとクロス集計分析ができます。 カテゴリデータ(カテゴリカルデータ、質的データ)のカテゴリごとのサンプル数(出現回数・頻度)の算出などが可能。

pandas.crosstab — pandas 0.22.0 documentation

出現回数ではなく、カテゴリごとの平均値などを算出したい場合はピボットテーブルpandas.pivot_table()を使います。以下の記事を参照。

ここでは、

pandas.crosstab()関数の基本的な使い方 カテゴリごとの小計・総計を算出: 引数margins 全体・行ごと・列ごとに規格化(正規化): 引数normalize

について説明します。 例としてタイタニックの生存情報のデータを使用します。Kaggleの問題からダウンロードできます。

import pandas as pd

df = pd.read_csv('data/src/titanic_train.csv', index_col=0).drop(['Name', 'Ticket', 'SibSp', 'Parch'], axis=1)

print(df.head())
#              Survived  Pclass     Sex   Age     Fare Cabin Embarked
# PassengerId                                                        
# 1                   0       3    male  22.0   7.2500   NaN        S
# 2                   1       1  female  38.0  71.2833   C85        C
# 3                   1       3  female  26.0   7.9250   NaN        S
# 4                   1       1  female  35.0  53.1000  C123        S
# 5                   0       3    male  35.0   8.0500   NaN        S

適当に列を除外しています。

pandas.crosstab()関数の基本的な使い方

第一引数indexに結果の行見出しとなるpandas.DataFrameの列(= pandas.Series)、第二引数columnsに結果の列見出しとなるpandas.DataFrameの列(= pandas.Series)を指定します。 pandas.pivot_table()と異なり、pandas.DataFrameオブジェクトとその列名で指定するのではない。注意。

print(pd.crosstab(df['Sex'], df['Pclass']))
# Pclass    1    2    3
# Sex                  
# female   94   76  144
# male    122  108  347

pandas.crosstab()関数が返すのはpandas.DataFrame。

print(type(pd.crosstab(df['Sex'], df['Pclass'])))
# <class 'pandas.core.frame.DataFrame'>

引数index, columnsにはpandas.Seriesのリストを指定することもできます。結果はマルチインデックス(階層型インデックス)のpandas.DataFrameとして返される。

print(pd.crosstab([df['Sex'], df['Survived']], [df['Pclass'], df['Embarked']]))
# Pclass            1         2          3         
# Embarked          C  Q   S  C  Q   S   C   Q    S
# Sex    Survived                                  
# female 0          1  0   2  0  0   6   8   9   55
#        1         42  1  46  7  2  61  15  24   33
# male   0         25  1  51  8  1  82  33  36  231
#        1         17  0  28  2  0  15  10   3   34

カテゴリごとの小計・総計を算出: 引数margins

引数marginsをTrueとすると、各カテゴリごとの小計および全体の総計が算出できます。

print(pd.crosstab([df['Sex'], df['Survived']], [df['Pclass'], df['Embarked']],
                  margins=True))
# Pclass            1           2           3           All
# Embarked          C  Q    S   C  Q    S   C   Q    S     
# Sex    Survived                                          
# female 0          1  0    2   0  0    6   8   9   55   81
#        1         42  1   46   7  2   61  15  24   33  231
# male   0         25  1   51   8  1   82  33  36  231  468
#        1         17  0   28   2  0   15  10   3   34  109
# All              85  2  127  17  3  164  66  72  353  889

小計・総計の行ラベル・列ラベルは引数margins_nameで指定できます。デフォルトは'All'。

print(pd.crosstab([df['Sex'], df['Survived']], [df['Pclass'], df['Embarked']],
                  margins=True, margins_name='Total'))
# Pclass            1           2           3          Total
# Embarked          C  Q    S   C  Q    S   C   Q    S      
# Sex    Survived                                           
# female 0          1  0    2   0  0    6   8   9   55    81
#        1         42  1   46   7  2   61  15  24   33   231
# male   0         25  1   51   8  1   82  33  36  231   468
#        1         17  0   28   2  0   15  10   3   34   109
# Total            85  2  127  17  3  164  66  72  353   889

全体・行ごと・列ごとに規格化(正規化): 引数normalize

引数normalizeを指定すると、結果を全体・行ごと・列ごとに1で規格化(正規化)できます。 normalize=Trueまたはnormalize='all'とすると、全体を合計すると1になるように規格化。

print(pd.crosstab(df['Sex'], df['Pclass'], margins=True, normalize=True))
# Pclass         1         2         3       All
# Sex                                           
# female  0.105499  0.085297  0.161616  0.352413
# male    0.136925  0.121212  0.389450  0.647587
# All     0.242424  0.206510  0.551066  1.000000

normalize='index'とすると、行ごとに合計すると1になるように規格化。

print(pd.crosstab(df['Sex'], df['Pclass'], margins=True, normalize='index'))
# Pclass         1         2         3
# Sex                                 
# female  0.299363  0.242038  0.458599
# male    0.211438  0.187175  0.601386
# All     0.242424  0.206510  0.551066

normalize='columns'とすると、列ごとに合計すると1になるように規格化。

print(pd.crosstab(df['Sex'], df['Pclass'], margins=True, normalize='columns'))
# Pclass         1         2         3       All
# Sex                                           
# female  0.435185  0.413043  0.293279  0.352413
# male    0.564815  0.586957  0.706721  0.647587

引数margins=Trueかつ引数index, columnsにリストで複数列を指定した場合、マルチインデックスを指定した方向に規格化するとエラーになるので注意。

# print(pd.crosstab(df['Sex'], [df['Pclass'], df['Embarked']],
#                   margins=True, normalize=True))
# TypeError: Expected tuple, got str

print(pd.crosstab(df['Sex'], [df['Pclass'], df['Embarked']],
                  margins=True, normalize='index'))
# Pclass           1                             2                      \
# Embarked         C         Q         S         C         Q         S   
# Sex                                                                    
# female    0.137821  0.003205  0.153846  0.022436  0.006410  0.214744   
# male      0.072790  0.001733  0.136915  0.017331  0.001733  0.168111   
# All       0.095613  0.002250  0.142857  0.019123  0.003375  0.184477   
# Pclass           3                      
# Embarked         C         Q         S  
# Sex                                     
# female    0.073718  0.105769  0.282051  
# male      0.074523  0.067591  0.459272  
# All       0.074241  0.080990  0.397075  

# print(pd.crosstab(df['Sex'], [df['Pclass'], df['Embarked']],
#                   margins=True, normalize='columns'))
# ValueError: Length of new names must be 1, got 2

バグとして報告されているがバージョン0.22.0の時点でまだFixされていない模様。

BUG: crosstab cannot normalize multiple columns for the index · Issue #15150 · pandas-dev/pandas

margins=False(デフォルト)であれば問題ない。

print(pd.crosstab(df['Sex'], [df['Pclass'], df['Embarked']], normalize=True))
# Pclass           1                             2                      \
# Embarked         C         Q         S         C         Q         S   
# Sex                                                                    
# female    0.048369  0.001125  0.053993  0.007874  0.002250  0.075366   
# male      0.047244  0.001125  0.088864  0.011249  0.001125  0.109111   
# Pclass           3                     
# Embarked         C        Q         S  
# Sex                                    
# female    0.025872  0.03712  0.098988  
# male      0.048369  0.04387  0.298088  

print(pd.crosstab(df['Sex'], [df['Pclass'], df['Embarked']], normalize='index'))
# Pclass           1                             2                      \
# Embarked         C         Q         S         C         Q         S   
# Sex                                                                    
# female    0.137821  0.003205  0.153846  0.022436  0.006410  0.214744   
# male      0.072790  0.001733  0.136915  0.017331  0.001733  0.168111   
# Pclass           3                      
# Embarked         C         Q         S  
# Sex                                     
# female    0.073718  0.105769  0.282051  
# male      0.074523  0.067591  0.459272  

print(pd.crosstab(df['Sex'], [df['Pclass'], df['Embarked']], normalize='columns'))
# Pclass           1                        2                             3  \
# Embarked         C    Q         S         C         Q         S         C   
# Sex                                                                         
# female    0.505882  0.5  0.377953  0.411765  0.666667  0.408537  0.348485   
# male      0.494118  0.5  0.622047  0.588235  0.333333  0.591463  0.651515   
# Pclass                        
# Embarked         Q         S  
# Sex                           
# female    0.458333  0.249292  
# male      0.541667  0.750708  

シェア

関連カテゴリー

Python pandas

pandasでユニークな要素の個数、頻度(出現回数)をカウント pandasでデータを行・列(縦・横)方向にずらすshift pandasで欠損値NaNが含まれているか判定、個数をカウント Python, pandasでwebページの表(htmlのtable)をスクレイピング pandasでExcelファイル(xlsx, xls)の書き込み(to_excel) pandas.DataFrame, Seriesを辞書に変換(to_dict) 『Pythonデータサイエンスハンドブック』は良書(NumPy, pandasほか) pandas, Matplotlib(mpl_finance)でローソク足チャートを作成 pandasのjson_normalizeで辞書のリストをDataFrameに変換 pandas.DataFrame, SeriesとNumPy配列ndarrayを相互に変換 pandas-datareaderで株価や人口のデータを取得 pandasの要素としてリストを格納し処理 pandasで文字列と数値を相互変換、書式変更 pandas.DataFrame, Seriesを時系列データとして処理 pandas.DataFrameをクリップボードにコピーするto_clipboard

Last Updated: 6/26/2019, 10:34:03 PM