Data Whale第20期チーム学習Pandas学習-変形


Data Whale第20期チーム学習Pandas学習-変形
  • 一、長幅表の変形
  • 1.1 pivot
  • 1.2 pivot_table
  • 1.3 melt
  • 1.4 wide_to_long

  • 二、インデックスの変形
  • 2.1 stackとunstack
  • 2.2重合と変形の関係
  • 三、その他の変形関数
  • 3.1 crosstab
  • 3.2 explode
  • 3.3 get_dummies

  • 参考文献
  • 一、縦横表の変形
    長いテーブルと広いテーブルは、ある特徴にとって、例えば、あるテーブルが性別をある列に格納すると、それは性別に関する長いテーブルである.性別をカラム名とし、カラム内の要素が他の関連特徴数値である場合、このテーブルは性別に関する広いテーブルです.
    import pandas as pd
    import numpy as np
    df=pd.DataFrame({
         'Gender':['F','F','M','M','F','F'],
                     'Height':[163, 160, 175, 180,165,175]})
    print("df=",df)
    # df=   Gender  Height
    # 0      F     163
    # 1      F     160
    # 2      M     175
    # 3      M     180
    # 4      F     165
    # 5      F     175
    df1=pd.DataFrame({
         'Height: F':[163, 160,180],
                      'Height: M':[175, 180,169]})
    print("df1=",df1)
    # df1=    Height: F  Height: M
    # 0        163        175
    # 1        160        180
    # 2        180        169
    

    上記のコードから分かるように、テーブルdfとテーブルdf 1は情報的に完全に等価であり、いずれも同じ身長統計値を含むが、これらの値の提示方式は異なるが、その提示方式は主に性別の1列で選択されたレイアウトモード、すなわちlongの状態で格納されるかwideの状態で格納されるかに関係している.従ってpandasは,このようなアスペクトテーブルの変形動作に関連するいくつかの変形関数を設計した.
    1.1 pivot
    pivotは典型的な長表幅表の関数である.
    df2=pd.DataFrame({
         'Class':[1,3,2,4,1,3],
                      'Name':['San Zhang','Xiao Zhang','Si Wang','Si Li','Er Wang','Wu Liu'],
                      'Subject':['Chinese','Math','Chinese','Math','Chinese','Math'],
                      'Grade':[80,75,90,85,70,95]})
    print("df2=",df2)
    # df2=    Class        Name  Subject  Grade
    # 0      1   San Zhang  Chinese     80
    # 1      3  Xiao Zhang     Math     75
    # 2      2     Si Wang  Chinese     90
    # 3      4       Si Li     Math     85
    # 4      1     Er Wang  Chinese     70
    # 5      3      Wu Liu     Math     95
    

    基本的な長さが広くなる操作に対して、最も重要なのは、変形後のローインデックス、カラムインデックスに移動する必要があるカラム、およびpivotメソッドのindex、columns、valuesパラメータにそれぞれ対応するカラムとローインデックスに対応する数値を知ることです.テーブルに新生されたカラムインデックスはcolumns対応カラムのunique値であり、新しいテーブルのローインデックスはindex対応カラムのunique値であり、valuesは表示したい数値カラムに対応する.
    print("df2.pivot(index='Name', columns='Subject', values='Grade')=",
          df2.pivot(index='Name', columns='Subject', values='Grade'))
    # df2.pivot(index='Name', columns='Subject', values='Grade')= Subject     Chinese  Math
    # Name                     
    # Er Wang        70.0   NaN
    # San Zhang      80.0   NaN
    # Si Li           NaN  85.0
    # Si Wang        90.0   NaN
    # Wu Liu          NaN  95.0
    # Xiao Zhang      NaN  75.0
    
    

    pandasは1.1.0からpivotに関連する3つのパラメータをリストに設定できます.つまり、マルチレベルインデックスが返されることを意味します.次の表の6つの列は、クラス、名前、テストタイプ(中間試験と期末試験)、科目、成績、ランキングです.コードは次のとおりです.
    df3 = pd.DataFrame({
         'Class':[1, 1, 2, 2, 1, 1, 2, 2],'Name':['San Zhang', 'San Zhang', 'Si Li', 'Si Li','San Zhang', 'San Zhang', 'Si Li', 'Si Li'],
                        'Examination': ['Mid', 'Final', 'Mid', 'Final','Mid', 'Final', 'Mid', 'Final'],
                        'Subject':['Chinese', 'Chinese', 'Chinese', 'Chinese','Math', 'Math', 'Math', 'Math'],
                        'Grade':[80, 75, 85, 65, 90, 85, 92, 88],'rank':[10, 15, 21, 15, 20, 7, 6, 2]})
    print("df3=",df3)
    # df3=    Class       Name Examination  Subject  Grade  rank
    # 0      1  San Zhang         Mid  Chinese     80    10
    # 1      1  San Zhang       Final  Chinese     75    15
    # 2      2      Si Li         Mid  Chinese     85    21
    # 3      2      Si Li       Final  Chinese     65    15
    # 4      1  San Zhang         Mid     Math     90    20
    # 5      1  San Zhang       Final     Math     85     7
    # 6      2      Si Li         Mid     Math     92     6
    # 7      2      Si Li       Final     Math     88     2
    """
                     
    (    、    、    、    )     ,           
    """
    pivot_multi = df3.pivot(index = ['Class', 'Name'],
                           columns = ['Subject','Examination'],values = ['Grade','rank'])
    print("pivot_multi=",pivot_multi)
    # pivot_multi=                   Grade                     rank                 
    # Subject         Chinese       Math       Chinese       Math      
    # Examination         Mid Final  Mid Final     Mid Final  Mid Final
    # Class Name                                                       
    # 1     San Zhang      80    75   90    85      10    15   20     7
    # 2     Si Li          85    65   92    88      21    15    6     2
    
    

    一意性の原則に基づいて、新しいテーブルのローインデックスはindexの複数のカラムにdrop_を使用することに等しい.duplicatesで、カラムインデックスの長さはvaluesの要素個数にcolumnsの一意の組合せ数(indexと同様)を乗じます.
    1.2 pivot_table
    pivotの使用は一意性条件に依存し、一意性条件が満たされない場合は、同じ行列の組合せに対応する複数の値を集約操作によって1つの値に変更する必要がある.
    
    """
                        ,      ,
                    ,        pivot      
    """
    df4 = pd.DataFrame({
         'Name':['San Zhang', 'San Zhang','Si Li', 'Si Li','San Zhang', 'San Zhang','Si Li', 'Si Li'],
                        'Subject':['Chinese', 'Chinese', 'Math', 'Math','Chinese', 'Chinese', 'Math', 'Math'],
                        'Grade':[80, 90, 100, 90, 70, 80, 85, 95]})
    print("df4=",df4)
    # df4=         Name  Subject  Grade
    # 0  San Zhang  Chinese     80
    # 1  San Zhang  Chinese     90
    # 2      Si Li     Math    100
    # 3      Si Li     Math     90
    # 4  San Zhang  Chinese     70
    # 5  San Zhang  Chinese     80
    # 6      Si Li     Math     85
    # 7      Si Li     Math     95
    

    pandasではpivot_が提供されていますaggfuncパラメータが使用される集約関数であるtableで実現
    print("df4.pivot_table(index = 'Name',columns = 'Subject',values='Grade',aggfunc = 'mean'",
          df4.pivot_table(index = 'Name',columns = 'Subject',values='Grade',aggfunc = 'mean'))
    # df4.pivot_table(index = 'Name',columns = 'Subject',values='Grade',aggfunc = 'mean' Subject    Chinese  Math
    # Name                    
    # San Zhang     80.0   NaN
    # Si Li          NaN  92.5
    

    転送aggfuncには、前章で説明したすべての合法的な集約文字列が含まれており、シーケンスを入力スカラーとして出力する集約関数を転送してカスタム操作を実現することもできます.
    print("df4.pivot_table(index = 'Name',columns = 'Subject',values = 'Grade',aggfunc = lambda x:x.mean())=",
          df4.pivot_table(index = 'Name',columns = 'Subject',values = 'Grade',aggfunc = lambda x:x.mean()))
    # df4.pivot_table(index = 'Name',columns = 'Subject',values = 'Grade',aggfunc = lambda x:x.mean())= Subject    Chinese  Math
    # Name                    
    # San Zhang     80.0   NaN
    # Si Li          NaN  92.5
    
    

    さらに、pivot_tableは、margins=Trueを設定することによって実現できる境界要約機能を有し、境界の集約方式はaggfuncで与えられた集約方法と一致する.
    """
                  、         ,           :
    """
    print("df4.pivot_table(index = 'Name',columns = 'Subject',values = 'Grade',aggfunc='mean',margins=True)=",
          df4.pivot_table(index = 'Name',columns = 'Subject',values = 'Grade',aggfunc='mean',margins=True))
    # df4.pivot_table(index = 'Name',columns = 'Subject',values = 'Grade',aggfunc='mean',margins=True)= Subject    Chinese  Math    All
    # Name
    # San Zhang     80.0   NaN  80.00
    # Si Li          NaN  92.5  92.50
    # All           80.0  92.5  86.25
    

    1.3 melt
    アスペクトテーブルはデータ提示方式の違いにすぎないが,その含む情報量は等価であり,pivotを用いてアスペクトテーブルをアスペクトテーブルに変換するとmelt関数は対応する逆操作でアスペクトテーブルをアスペクトテーブルに変換できると前述した.
    df5=pd.DataFrame({
         'Class':[1,2,3],'Name':['San Zhang', 'Si Li','Wu Wang'],'Chinese':[80, 90,85],'Math':[80, 75,95]})
    print("df5=",df5)
    # df5=    Class       Name  Chinese  Math
    # 0      1  San Zhang       80    80
    # 1      2      Si Li       90    75
    # 2      3    Wu Wang       85    95
    df5_m=df5.melt(id_vars = ['Class', 'Name'],value_vars = ['Chinese', 'Math'],
                   var_name = 'Subject',value_name = 'Grade')
    print("df5_m=",df5_m)
    # df5_m=    Class       Name  Subject  Grade
    # 0      1  San Zhang  Chinese     80
    # 1      2      Si Li  Chinese     90
    # 2      3    Wu Wang  Chinese     85
    # 3      1  San Zhang     Math     80
    # 4      2      Si Li     Math     75
    # 5      3    Wu Wang     Math     95
    df5_um=df5_m.pivot(index = ['Class', 'Name'], columns='Subject',values='Grade')
    print("df5_um=",df5_um)
    # df5_um= Subject          Chinese  Math
    # Class Name
    # 1     San Zhang       80    80
    # 2     Si Li           90    75
    # 3     Wu Wang         85    95
    df5_um=df5_um.reset_index().rename_axis(columns={
         'Subject':''})
    print("df5_um.equals(df5)=",df5_um.equals(df5))
    # df5_um.equals(df5)= True
    

    1.4 wide_to_long
    meltメソッドでは、カラムインデックスで圧縮された値のセットに対応するカラム要素は、values_という同じ階層の意味しか表しません.name .中間期末のカテゴリや国語数学のカテゴリなど、列にクロスカテゴリが含まれている場合はvalues_name対応のGradeは2列に拡張してそれぞれ国語の点数と数学の点数に対応して、中期末の情報だけを圧縮して、このような需要の下でwide_を使いますto_long関数で完了します.
    df6=pd.DataFrame({
         'Class':[1,2,1],'Name':['San Zhang', 'Si Li','Liu Liu'],'Chinese_Mid':[80, 75,85],
                      'Math_Mid':[90, 85,85],'Chinese_Final':[80, 75,81], 'Math_Final':[90, 85,92]})
    print("df6=",df6)
    # df6=    Class       Name  Chinese_Mid  Math_Mid  Chinese_Final  Math_Final
    # 0      1  San Zhang           80        90             80          90
    # 1      2      Si Li           75        85             75          85
    # 2      1    Liu Liu           85        85             81          92
    print("pd.wide_to_long(df6,stubnames=['Chinese', 'Math'],i = ['Class', 'Name'],j='Examination',sep='_',suffix='.+')=",
          pd.wide_to_long(df6,stubnames=['Chinese', 'Math'],i = ['Class', 'Name'],j='Examination',sep='_',suffix='.+'))
    # pd.wide_to_long(df6,stubnames=['Chinese', 'Math'],i = ['Class', 'Name'],j='Examination',sep='_',suffix='.+')=                              Chinese  Math
    # Class Name      Examination               
    # 1     San Zhang Mid               80    90
    #                 Final             80    90
    # 2     Si Li     Mid               75    85
    #                 Final             75    85
    # 1     Liu Liu   Mid               85    85
    #                 Final             81    92
    
    res = pivot_multi.copy()
    res.columns = res.columns.map(lambda x:'_'.join(x))
    res = res.reset_index()
    res = pd.wide_to_long(res, stubnames=['Grade', 'rank'],
                          i = ['Class', 'Name'],j = 'Subject_Examination',sep = '_',suffix = '.+')
    res = res.reset_index()
    res[['Subject', 'Examination']] = res['Subject_Examination'].str.split('_', expand=True)
    res = res[['Class', 'Name', 'Examination','Subject', 'Grade', 'rank']].sort_values('Subject')
    res = res.reset_index(drop=True)
    print("res=",res)
    # res=    Class       Name Examination  Subject  Grade  rank
    # 0      1  San Zhang         Mid  Chinese     80    10
    # 1      1  San Zhang       Final  Chinese     75    15
    # 2      2      Si Li         Mid  Chinese     85    21
    # 3      2      Si Li       Final  Chinese     65    15
    # 4      1  San Zhang         Mid     Math     90    20
    # 5      1  San Zhang       Final     Math     85     7
    # 6      2      Si Li         Mid     Math     92     6
    # 7      2      Si Li       Final     Math     88     2
    

    二、索引の変形
    2.1 stackとunstack
    swaplevelまたはreorderを使用levelsはインデックス内部のレイヤ交換を行い,行列インデックス間の交換はDataFrame次元の変化,すなわち変形操作に属する.第1節で説明した4つの変形関数は、インデックス間の変換ではなく、1つまたは複数のカラム要素とカラムインデックス間の変換に属している点で異なります.unstack関数の役割は、ローインデックスをカラムインデックスに変換することです.
    df7=pd.DataFrame(np.ones((6,3)),index = pd.Index([('A', 'cat', 'pig'),('A', 'dog', 'small'),('C', 'cat', 'pig'),('C', 'dog', 'small'),
                                                      ('B', 'cat', 'pig'),('B', 'dog', 'small')]),columns=['col_1', 'col_2', 'col_3'])
    print("df7=",df7)
    # df7=              col_1  col_2  col_3
    # A cat pig      1.0    1.0    1.0
    #   dog small    1.0    1.0    1.0
    # C cat pig      1.0    1.0    1.0
    #   dog small    1.0    1.0    1.0
    # B cat pig      1.0    1.0    1.0
    #   dog small    1.0    1.0    1.0
    print("df7.unstack()=",df7.unstack())
    # df7.unstack()=       col_1       col_2       col_3
    #         pig small   pig small   pig small
    # A cat   1.0   NaN   1.0   NaN   1.0   NaN
    #   dog   NaN   1.0   NaN   1.0   NaN   1.0
    # B cat   1.0   NaN   1.0   NaN   1.0   NaN
    #   dog   NaN   1.0   NaN   1.0   NaN   1.0
    # C cat   1.0   NaN   1.0   NaN   1.0   NaN
    #   dog   NaN   1.0   NaN   1.0   NaN   1.0
    # unstack            ,       ,          ,           
    print("df7.unstack(1)=",df7.unstack(1))
    # df7.unstack(1)=         col_1      col_2      col_3
    #           cat  dog   cat  dog   cat  dog
    # A pig     1.0  NaN   1.0  NaN   1.0  NaN
    #   small   NaN  1.0   NaN  1.0   NaN  1.0
    # B pig     1.0  NaN   1.0  NaN   1.0  NaN
    #   small   NaN  1.0   NaN  1.0   NaN  1.0
    # C pig     1.0  NaN   1.0  NaN   1.0  NaN
    #   small   NaN  1.0   NaN  1.0   NaN  1.0
    print("df7.unstack([0,2])",df7.unstack([0,2]))
    # df7.unstack([0,2])     col_1                              ... col_3                            
    #         A          C          B        ...     A          C          B      
    #       pig small  pig small  pig small  ...   pig small  pig small  pig small
    # cat   1.0   NaN  1.0   NaN  1.0   NaN  ...   1.0   NaN  1.0   NaN  1.0   NaN
    # dog   NaN   1.0  NaN   1.0  NaN   1.0  ...   NaN   1.0  NaN   1.0  NaN   1.0
    # 
    # [2 rows x 18 columns]
    
    df8=pd.DataFrame(np.ones((6,3)),index = pd.Index([('A', 'cat', 'big'),('A', 'dog', 'small'),('B', 'cat', 'big'),
                                                      ('B', 'dog', 'small'),('D', 'cat', 'big'),('D', 'dog', 'small')]),
                     columns=['index_1', 'index_2', 'index_3']).T
    print("df8=",df8)
    # df8=            A          B          D
    #          cat   dog  cat   dog  cat   dog
    #          big small  big small  big small
    # index_1  1.0   1.0  1.0   1.0  1.0   1.0
    # index_2  1.0   1.0  1.0   1.0  1.0   1.0
    # index_3  1.0   1.0  1.0   1.0  1.0   1.0
    print("df8.stack()=",df8.stack())
    # df8.stack()=                  A         B         D
    #                cat  dog  cat  dog  cat  dog
    # index_1 big    1.0  NaN  1.0  NaN  1.0  NaN
    #         small  NaN  1.0  NaN  1.0  NaN  1.0
    # index_2 big    1.0  NaN  1.0  NaN  1.0  NaN
    #         small  NaN  1.0  NaN  1.0  NaN  1.0
    # index_3 big    1.0  NaN  1.0  NaN  1.0  NaN
    #         small  NaN  1.0  NaN  1.0  NaN  1.0
    print("df8.stack([1, 2])=",df8.stack([1, 2]))
    # df8.stack([1, 2])=                      A    B    D
    # index_1 cat big    1.0  1.0  1.0
    #         dog small  1.0  1.0  1.0
    # index_2 cat big    1.0  1.0  1.0
    #         dog small  1.0  1.0  1.0
    # index_3 cat big    1.0  1.0  1.0
    #         dog small  1.0  1.0  1.0
    

    2.2重合と変形の関係
    以上のすべての関数では、集約効果のあるpivot_を除きます.table以外では,すべての関数は変形前後でvalues個数の変化をもたらすことはなく,これらの値は提示形式で変化しただけである.パケット集約操作では、新しい行列インデックスが生成されるため、必然的に何らかの特殊な変形操作にも属するが、集約後に元の複数の値を1つの値に変更するため、valuesの個数が変化する、すなわちパケット集約と変形関数の最大区別である.
    三、その他の変形関数
    3.1 crosstab
    crosstabは、すべての機能pivot_を実現できるため、推奨される関数ではありません.tableはすべて完成することができて、しかも速度はもっと速いです.デフォルトでは、crosstabは、要素の組合せが現れる周波数、すなわちcount操作を統計することができる.
    #    learn_pandas                 
    df9 = pd.read_csv('data/learn_pandas.csv')
    print("pd.crosstab(index = df9.School, columns = df9.Transfer)=",
          pd.crosstab(index = df9.School, columns = df9.Transfer))
    # pd.crosstab(index = df9.School, columns = df9.Transfer)= Transfer                        N  Y
    # School
    # Fudan University               38  1
    # Peking University              28  2
    # Shanghai Jiao Tong University  53  0
    # Tsinghua University            62  4
    #      crosstab
    print("pd.crosstab(index = df9.School, columns = df9.Transfer,values = [0]*df9.shape[0], aggfunc = 'count'=",
          pd.crosstab(index = df9.School, columns = df9.Transfer,values = [0]*df9.shape[0], aggfunc = 'count'))
    # pd.crosstab(index = df9.School, columns = df9.Transfer,values = [0]*df9.shape[0], aggfunc = 'count'= Transfer                          N    Y
    # School
    # Fudan University               38.0  1.0
    # Peking University              28.0  2.0
    # Shanghai Jiao Tong University  53.0  NaN
    # Tsinghua University            62.0  4.0
    ##    pivot_table       ,             ,
    #    values                     
    print("df9.pivot_table(index = 'School',columns = 'Transfer',values = 'Name',aggfunc = 'count')=",
          df9.pivot_table(index = 'School',columns = 'Transfer',values = 'Name',aggfunc = 'count'))
    # df9.pivot_table(index = 'School',columns = 'Transfer',values = 'Name',aggfunc = 'count')= Transfer                          N    Y
    # School
    # Fudan University               38.0  1.0
    # Peking University              28.0  2.0
    # Shanghai Jiao Tong University  53.0  NaN
    # Tsinghua University            62.0  4.0
    #          count   ,                        ,             
    print("pd.crosstab(index = df9.School, columns = df9.Transfer,values = df9.Height, aggfunc = 'mean')=",
          pd.crosstab(index = df9.School, columns = df9.Transfer,values = df9.Height, aggfunc = 'mean'))
    # pd.crosstab(index = df9.School, columns = df9.Transfer,values = df9.Height, aggfunc = 'mean')= Transfer                                N       Y
    # School                                           
    # Fudan University               162.043750  177.20
    # Peking University              163.429630  162.40
    # Shanghai Jiao Tong University  163.953846     NaN
    # Tsinghua University            163.253571  164.55
    

    3.2 explode
    explodeパラメータは、ある列の要素を縦方向に展開することができる、展開されたセルにはlist,tuple,Series,npを格納必要がある.ndarrayのタイプです.
    df10 = pd.DataFrame({
         'Q': [[1, 2],'my_str',{
         1, 2},pd.Series([3, 4])], 'R': 1})
    print("df10.explode('Q')=",df10.explode('Q'))
    # df10.explode('Q')=         Q  R
    # 0       1  1
    # 0       2  1
    # 1  my_str  1
    # 2  {1, 2}  1
    # 3       3  1
    # 3       4  1
    
    

    3.3 get_dummies
    get_dummiesは特徴構築に用いる重要な関数の一つであり,カテゴリ特徴を指示変数に変換する役割を果たす.例えば、学年の列を指示変数に変換し、ある学年に属する対応する列を1とし、そうでなければ0とし、コードは以下の通りである.
    print("pd.get_dummies(df9.Grade).head()=",pd.get_dummies(df9.Grade).head())
    # pd.get_dummies(df9.Grade).head()=    Freshman  Junior  Senior  Sophomore
    # 0         1       0       0          0
    # 1         1       0       0          0
    # 2         0       0       1          0
    # 3         0       0       0          1
    # 4         0       0       0          1
    

    参考文献
    1、https://datawhalechina.github.io/joyful-pandas/build/html/%E7%9B%AE%E5%BD%95/ch5.html