『Pythonによるデータ分析』第9章groupby技術とデータ集約ノート

24392 ワード

groupbyテクノロジーとデータ集約
データセットをグループ化し、集約または変換にかかわらず、各グループに関数を適用することは、データ分析の重要な一環です.データセットを準備した後、通常のタスクは、パケット統計の計算またはピボット・テーブルの生成です.
この章では、1つ以上のキー(関数、配列、DataFrame列名など)に基づいてpandasオブジェクトを分割することを学びます.-カウント、平均、標準偏差、ユーザー定義関数などのグループ化要約統計を計算します.-DataFrameのカラムには、さまざまな関数が適用されます.-正規化、線形回帰、ランキング、サブセットの選択など、グループ内変換またはその他の演算を適用します.-ピボットまたはクロス集計を計算します.-ビット数分析およびその他のグループ分析を実行します.
パケット演算の最初のフェーズでは、pandasオブジェクト(Series、DataFrame、その他)のデータは、あなたが提供した1つ以上のキーに基づいて複数のグループに分割されます.分割操作は、オブジェクトの特定の軸で実行されます.例えば、DataFrameは、その行(axis=0)または列(axis=1)上でグループ化することができる.次に、関数を各パケットに適用し、新しい値を生成します.最後に、これらの関数の実行結果はすべて最終的な結果オブジェクトにマージされます.結果オブジェクトの形式は、一般に、データ上で実行される操作に依存します.図9〜図1は、単純なパケット集約プロセスを概略的に示す.
GroupByテクノロジー
グループ化キーには、さまざまな形式があり、同じタイプである必要はありません.
  • リストまたは配列.その長さは、グループ化される軸と同じである.
  • は、DataFrameのカラム名の値を表します.
  • 辞書またはSeriesは、パケットされる軸上の値とパケット名との対応関係を与える.
  • 関数は、軸インデックスまたはインデックスの各ラベルを処理するために使用されます.
  • from pandas import Series,DataFrame
    import pandas as pd
    import numpy as np
    df=DataFrame({'key1':['a','a','b','b','a'],'key2':['one','two','one','two','one'],
                  'data1':np.random.randn(5),'data2':np.random.randn(5)})
    df

    key 1でグループ化し、data 1列の平均値を計算します.data 1にアクセスし、key 1に基づいてgroupbyを呼び出すことができます.
    grouped=df['data1'].groupby(df['key1'])
    grouped
    
    

    変数groupedはGroupByオブジェクトであり、次にGroupByのmeanメソッドを呼び出してパケット平均値を計算します.
    grouped.mean()
    key1
    a    0.597727
    b    0.318738
    Name: data1, dtype: float64
    

    複数の配列が一度に入力されると、異なる結果が得られます.
    means=df['data1'].groupby([df['key1'],df['key2']]).mean()
    means
    key1  key2
    a     one     0.595071
          two     0.603039
    b     one    -0.077999
          two     0.715474
    Name: data1, dtype: float64
    

    上から2つのキーでデータをグループ化したSeriesは階層化されたインデックス(一意のキーペアで構成されている)を持っており、次に置換する
    means.unstack()

    以上の例ではパケットキーはいずれもSeriesである.実際には、パケットキーは任意の長さの適切な配列であってもよい
    states=np.array(['Ohio','California','California','Ohio','Ohio'])
    years=np.array([2005,2005,2006,2005,2006])
    states
    array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'],
          dtype='
    years
    array([2005, 2005, 2006, 2005, 2006])
    
    df['data1'].groupby([states,years]).mean()
    California  2005    0.603039
                2006   -0.077999
    Ohio        2005    0.107602
                2006    1.690412
    Name: data1, dtype: float64
    

    列名の文字列、数値、またはその他のPythonオブジェクトをグループ化キーとして使用できます.
    df.groupby('key1').mean()
    df.groupby(['key1','key2']).mean()

    グループbyのsizeメソッドは、パケットサイズを含むSeriesを返すことができます.
    df.groupby(['key1','key2']).size()
    key1  key2
    a     one     2
          two     1
    b     one     1
          two     1
    dtype: int64
    

    グループの反復
    groupbyオブジェクトは、グループ名とデータブロックからなる二元グループのセットを生成できます.
    for name,group in df.groupby('key1'):
        print(name)
        print(group)
    a
          data1     data2 key1 key2
    0 -0.500271  1.820004    a  one
    1  0.603039 -0.783806    a  two
    4  1.690412 -2.138761    a  one
    b
          data1     data2 key1 key2
    2 -0.077999 -1.464172    b  one
    3  0.715474  1.048138    b  two
    

    マルチキーの場合、メタグループの最初の要素はキー値からなるメタグループになります.
    for (k1,k2),group in df.groupby(['key1','key2']):
        print(k1,k2)
        print(group)
    a one
          data1     data2 key1 key2
    0 -0.500271  1.820004    a  one
    4  1.690412 -2.138761    a  one
    a two
          data1     data2 key1 key2
    1  0.603039 -0.783806    a  two
    b one
          data1     data2 key1 key2
    2 -0.077999 -1.464172    b  one
    b two
          data1     data2 key1 key2
    3  0.715474  1.048138    b  two
    

    これらのデータの断片を辞書にします
    pieces=dict(list(df.groupby('key1')))
    pieces
    {'a':       data1     data2 key1 key2
     0 -0.500271  1.820004    a  one
     1  0.603039 -0.783806    a  two
     4  1.690412 -2.138761    a  one, 'b':       data1     data2 key1 key2
     2 -0.077999 -1.464172    b  one
     3  0.715474  1.048138    b  two}
    
    pieces['b']

    groupbyのデフォルトはaxis=0でグループ化され、次にdtypeに基づいてカラムをグループ化します.
    df.dtypes
    data1    float64
    data2    float64
    key1      object
    key2      object
    dtype: object
    
    grouped=df.groupby(df.dtypes,axis=1)
    dict(list(grouped))
    {dtype('float64'):       data1     data2
     0 -0.500271  1.820004
     1  0.603039 -0.783806
     2 -0.077999 -1.464172
     3  0.715474  1.048138
     4  1.690412 -2.138761, dtype('O'):   key1 key2
     0    a  one
     1    a  two
     2    b  one
     3    b  two
     4    a  one}
    

    1つまたは複数の列の選択
    DataFrameによって生成されたGroup Byオブジェクトに対して、1つの(単一文字列)または1つの(文字列配列)カラム名でインデックスを付けると、一部のカラムを集約する目的が達成されます.
    df.groupby('key1')['data1']
    
    
    df['data1'].groupby(df['key1'])
    
    

    大きなデータセットの場合、一部のカラムを集約するだけで済みます.例えば、前のデータセットでは、data 2列の平均値を計算してデータFrame形式で結果を得るだけで、作成できます.
    df.groupby(['key1','key2'])[['data2']].mean()

    このインデックス操作で返されるオブジェクトは、リストまたは配列が入力された場合にパケット化されたDataFrameまたはパケット化されたSeries(スカラー形式の単一カラム名が入力された場合)です.
    s_grouped=df.groupby(['key1','key2'])['data2']
    s_grouped
    
    
    s_grouped.mean()
    key1  key2
    a     one    -0.159378
          two    -0.783806
    b     one    -1.464172
          two     1.048138
    Name: data2, dtype: float64
    

    辞書またはSeriesによるグループ化
    配列に加えて、パケット情報は他の形式で存在することもできます.例:DataFrame
    people=DataFrame(np.random.randn(5,5),columns=['a','b','c','d','e'],
                    index=['Joe','Steve','Wes','Jim','Travis'])
    people.loc[2:3,['b','c']]=np.nan #  NA 
    people

    既知のカラムのパケット関係を仮定し,パケットに基づいてカラムの合計を計算したい場合は,まずこの辞書をgroupbyに渡す.
    mapping={'a':'red','b':'red','c':'blue','d':'blue','e':'red','f':'orange'}
    by_column=people.groupby(mapping,axis=1)
    by_column.sum()

    Seriesにも同様の機能があり,固定サイズのマッピングと見なすことができる.この例では、Seriesをパケットキーとして使用すると、pandasはSeriesをチェックして、インデックスがパケット軸に整列していることを確認します.
    map_series=Series(mapping)
    map_series
    a       red
    b       red
    c      blue
    d      blue
    e       red
    f    orange
    dtype: object
    
    people.groupby(map_series,axis=1).count()

    blue
    red
    Joe
    2
    3
    Steve
    2
    3
    Wes
    1
    2
    Jim
    2
    3
    Travis
    2
    3
    関数によるグループ化
    パケットキーとして使用される関数は、各インデックス値で1回呼び出され、その戻り値がパケット名として使用されます.
    具体的には、上記の例であるDataFrameを例とし、そのインデックス値は人の名前である.人名の長さに基づいてグループ化したいと仮定すると、文字列の長さ配列を求めることができますが、len関数だけが入力されます.
    people.groupby(len).sum()

    関数を配列、リスト、辞書、Seriesと混合して使用できます.これは、最終的にはすべてのものが配列に変換されるためです.
    key_list=['one','one','one','two','two']
    people.groupby([len,key_list]).min()

    インデックス・レベルでグループ化
    階層化されたインデックス・データセットが最も便利なのは、インデックス・レベルに基づいて集約できることです.レベルキーによるレベル番号または名前の入力
    columns=pd.MultiIndex.from_arrays([['US','US','US','JP','JP'],
                                         [1,3,5,1,3]],names=['cty','tenor'])
    hier_df=DataFrame(np.random.randn(4,5),columns=columns)
    hier_df
    hier_df.groupby(level='cty',axis=1).count()

    データの集約
    集約とは、配列からスカラー値を生成できる任意のデータ変換プロセスを指します.独自に発明された集約演算を使用して、パケット・オブジェクトで定義された任意の方法を呼び出すこともできます.
    例えば、quantileは、SeriesまたはDataFrame列のサンプルビット数を計算することができる
    df=DataFrame({'key1':['a','a','b','b','a'],'key2':['one','two','one','two','one'],
                  'data1':np.random.randn(5),'data2':np.random.randn(5)})
    df
    grouped=df.groupby('key1')
    grouped['data1'].quantile(0.9)
    key1
    a   -0.932423
    b   -0.006997
    Name: data1, dtype: float64
    

    独自の集約関数を使用する場合は、aggregateメソッドまたはaggメソッドに渡すだけです.
    def peak_to_peak(arr):
        return arr.max()-arr.min()
    grouped.agg(peak_to_peak)

    describeも使用できますが、厳密には集約演算ではありません.
    grouped.describe()
    
    data1     data2
    key1
    a    count  3.000000  3.000000
         mean   0.746672  0.910916
         std    1.109736  0.712217
         min   -0.204708  0.092908
         25%     0.137118  0.669671
         50%     0.478943  1.246435
         75%     1.222362  1.319920
         max     1.965781  1.393406
    b    count   2.000000  2.000000
         mean   -0.537585  0.525384
         std     0.025662  0.344556
         min    -0.555730  0.281746
         25%    -0.546657  0.403565
         50%    -0.537585  0.525384
         75%    -0.528512  0.647203
         max    -0.519439  0.769023

    注:カスタム集約関数は、表9-1の最適化された関数よりもずっと遅いです.これは、中間パケットデータブロックを構築する際に非常に大きなオーバーヘッド(関数呼び出し、データ再配置など)が存在するためである
    より高度な集約機能を説明するために、レストランのチップに関するデータセット(本書のGitHubライブラリ)を使用します.https://github.com/wesm/pydata-book/tree/1st-edition
    read_経由csvロード後、チップの割合を表す列tip_を追加します.pct
    tips=pd.read_csv('pydata_book/ch08/tips.csv')  #    
    tips[:8]  #   8    
    
        total_bill  tip sex smoker  day time    size
    0   16.99   1.01    Female  No  Sun Dinner  2
    1   10.34   1.66    Male    No  Sun Dinner  3
    2   21.01   3.50    Male    No  Sun Dinner  3
    3   23.68   3.31    Male    No  Sun Dinner  2
    4   24.59   3.61    Female  No  Sun Dinner  4
    5   25.29   4.71    Male    No  Sun Dinner  4
    6   8.77    2.00    Male    No  Sun Dinner  2
    7   26.88   3.12    Male    No  Sun Dinner  4
    tips['tip_pct']=tips['tip']/tips['total_bill']  #  “        ”  
    tips[:8]
    
        total_bill  tip sex smoker  day time    size    tip_pct
    0   16.99   1.01    Female  No  Sun Dinner  2   0.059447
    1   10.34   1.66    Male    No  Sun Dinner  3   0.160542
    2   21.01   3.50    Male    No  Sun Dinner  3   0.166587
    3   23.68   3.31    Male    No  Sun Dinner  2   0.139780
    4   24.59   3.61    Female  No  Sun Dinner  4   0.146808
    5   25.29   4.71    Male    No  Sun Dinner  4   0.186240
    6   8.77    2.00    Male    No  Sun Dinner  2   0.228050
    7   26.88   3.12    Male    No  Sun Dinner  4   0.116071
    

    カラム向けマルチファンクションアプリケーション
    Series列またはDataFrame列の集約演算は、実際にはaggregate(カスタム関数を使用)を使用するか、mean、stdなどの呼び出し方法であることが明らかになった.しかし、異なるカラムに対して異なる集約関数を使用するか、複数の関数を一度に適用したい場合があります.
    次に、さまざまな例を練習します.
    grouped=tips.groupby(['sex','smoker'])#  sex smoker tips    
    grouped_pct=grouped['tip_pct']   #             
    grouped_pct.agg('mean')
    sex     smoker
    Female  No        0.156921
            Yes       0.182150
    Male    No        0.160669
            Yes       0.152771
    Name: tip_pct, dtype: float64
    

    関数または関数名のセットが入力されると、取得されたDataFrameの列は対応する関数で名前が付けられます.
    grouped_pct.agg(['mean','std',peak_to_peak])
    
    
    mean    std peak_to_peak
    sex smoker          
    Female  No  0.156921    0.036421    0.195876
    Yes 0.182150    0.071595    0.360233
    Male    No  0.160669    0.041849    0.220186
    Yes 0.152771    0.090588    0.674707

    入力された(name,function)メタグループからなるリストである場合、各メタグループの最初の要素はDataFrameのカラム名として使用されます(このようなメタグループリストは秩序マッピングと見なすことができます).
    grouped_pct.agg([('foo','mean'),('bar',np.std)])
    
            foo bar
    sex smoker      
    Female  No  0.156921    0.036421
    Yes 0.182150    0.071595
    Male    No  0.160669    0.041849
    Yes 0.152771    0.090588

    DataFrameの場合、すべてのカラムに適用される関数のセットを定義するか、異なるカラムに異なる関数を適用します.tip_に対してpctとtotal_bill列計算の3つの統計
    functions=['count','mean','max']
    result=grouped['tip_pct','total_bill'].agg(functions)
    result

    結果DataFrameには階層化されたカラムがあります.これは、各カラムを集約し、concatで結果を統合することに相当します(カラム名はkeysパラメータとして使用されます).
    result['tip_pct']

    カスタム名付きメタグループのリストを入力
    ftuples=[('Durchschnitt','mean'),('Abweichung',np.var)]
    grouped['tip_pct','total_bill'].agg(ftuples)

    異なるカラムに異なる関数を適用する場合.具体的にはaggにカラム名から関数にマッピングされた辞書を渡すことです
    grouped.agg({'tip':np.max,'size':'sum'})
    grouped.agg({'tip_pct':['min','max','mean','std'],'size':'sum'})

    複数の関数を少なくとも1つのカラムに適用する場合にのみ、DataFrameは階層化されたカラムを持ちます.
    集約データをインデックスなしで返す
    例の集約データには、一意のグループ化キーからなるインデックス(階層化されている可能性があります)があります.必ずしもそうではないので、groupbyにas_を転送することができます.index=Falseこの機能を無効にする
    結果に対してreset_を呼び出すindexもこのような形式の結果を得ることができます
    tips.groupby(['sex','smoker'],as_index=False).mean()

    次のセクションでは、パケットレベルの演算と変換を学習します.