データフレームをピボットする方法


358
  • ピボットとは何ですか?
  • ピボットするにはどうすればよいですか?
  • これはピボットですか?
  • ロングフォーマットからワイドフォーマット?

ピボットテーブルについての質問をたくさん見てきました。ピボットテーブルについて質問していることを知らなくても、通常はそうです。ピボットのすべての側面を網羅する標準的な質問と回答を書くことは事実上不可能です...

...しかし、私はそれを試してみるつもりです。


既存の質疑応答の問題は、多くの既存の適切な解答を使用するために、OPが一般化するのが難しいニュアンスに質問が集中していることが多いことです。ただし、すべての回答が包括的な説明を試みることはありません(これは困難な作業であるため)

私のグーグル検索からいくつかの例を見てください

  1. パンダでデータフレームをピボットする方法は?
    • 良い質問と答え。しかし、答えはほとんど説明せずに特定の質問に答えるだけです。
  2. パンダのピボットテーブルからデータフレームへ
    • この質問では、OPはピボットの出力に関係しています。つまり、列の外観。OPはRのように見せたかったのですが、これはパンダのユーザーにとってはあまり役に立ちません。
  3. データフレームをピボットするパンダ、重複する行
    • 別のまともな質問ですが、答えは1つの方法、すなわち pd.DataFrame.pivot

したがって、誰かが検索を行うpivotと、散発的な結果が得られますが、特定の質問には答えられない可能性があります。


セットアップ

列と関連する列の値に目立つように名前を付けて、以下の回答でどのようにピボットを行うかに対応していることに気付くでしょう。

import numpy as np
import pandas as pd
from numpy.core.defchararray import add

np.random.seed([3,1415])
n = 20

cols = np.array(['key', 'row', 'item', 'col'])
arr1 = (np.random.randint(5, size=(n, 4)) // [2, 1, 2, 1]).astype(str)

df = pd.DataFrame(
    add(cols, arr1), columns=cols
).join(
    pd.DataFrame(np.random.rand(n, 2).round(2)).add_prefix('val')
)
print(df)

     key   row   item   col  val0  val1
0   key0  row3  item1  col3  0.81  0.04
1   key1  row2  item1  col2  0.44  0.07
2   key1  row0  item1  col0  0.77  0.01
3   key0  row4  item0  col2  0.15  0.59
4   key1  row0  item2  col1  0.81  0.64
5   key1  row2  item2  col4  0.13  0.88
6   key2  row4  item1  col3  0.88  0.39
7   key1  row4  item1  col1  0.10  0.07
8   key1  row0  item2  col4  0.65  0.02
9   key1  row2  item0  col2  0.35  0.61
10  key2  row0  item2  col1  0.40  0.85
11  key2  row4  item1  col2  0.64  0.25
12  key0  row2  item2  col3  0.50  0.44
13  key0  row4  item1  col4  0.24  0.46
14  key1  row3  item2  col3  0.28  0.11
15  key0  row3  item1  col1  0.31  0.23
16  key0  row0  item2  col3  0.86  0.01
17  key0  row4  item0  col3  0.64  0.21
18  key2  row2  item2  col0  0.13  0.45
19  key0  row2  item0  col4  0.37  0.70

質問

  1. なぜ私は得るのですか ValueError: Index contains duplicate entries, cannot reshape

  2. 値が列、値がインデックス、平均が値になるdfようにピボットするにはどうすればよいですか?colrowval0

    col   col0   col1   col2   col3  col4
    row                                  
    row0  0.77  0.605    NaN  0.860  0.65
    row2  0.13    NaN  0.395  0.500  0.25
    row3   NaN  0.310    NaN  0.545   NaN
    row4   NaN  0.100  0.395  0.760  0.24
    
  3. どのようにして旋回しないdfようなcol値が列です、row値は、平均で、インデックスされているval0値であり、欠損値がありますか0

    col   col0   col1   col2   col3  col4
    row                                  
    row0  0.77  0.605  0.000  0.860  0.65
    row2  0.13  0.000  0.395  0.500  0.25
    row3  0.00  0.310  0.000  0.545  0.00
    row4  0.00  0.100  0.395  0.760  0.24
    
  4. meanたぶん、以外のものをもらえますsumか?

    col   col0  col1  col2  col3  col4
    row                               
    row0  0.77  1.21  0.00  0.86  0.65
    row2  0.13  0.00  0.79  0.50  0.50
    row3  0.00  0.31  0.00  1.09  0.00
    row4  0.00  0.10  0.79  1.52  0.24
    
  5. 一度に複数の集計を実行できますか?

           sum                          mean                           
    col   col0  col1  col2  col3  col4  col0   col1   col2   col3  col4
    row                                                                
    row0  0.77  1.21  0.00  0.86  0.65  0.77  0.605  0.000  0.860  0.65
    row2  0.13  0.00  0.79  0.50  0.50  0.13  0.000  0.395  0.500  0.25
    row3  0.00  0.31  0.00  1.09  0.00  0.00  0.310  0.000  0.545  0.00
    row4  0.00  0.10  0.79  1.52  0.24  0.00  0.100  0.395  0.760  0.24
    
  6. 複数の値列を集計できますか?

          val0                             val1                          
    col   col0   col1   col2   col3  col4  col0   col1  col2   col3  col4
    row                                                                  
    row0  0.77  0.605  0.000  0.860  0.65  0.01  0.745  0.00  0.010  0.02
    row2  0.13  0.000  0.395  0.500  0.25  0.45  0.000  0.34  0.440  0.79
    row3  0.00  0.310  0.000  0.545  0.00  0.00  0.230  0.00  0.075  0.00
    row4  0.00  0.100  0.395  0.760  0.24  0.00  0.070  0.42  0.300  0.46
    
  7. 複数の列で細分割できますか?

    item item0             item1                         item2                   
    col   col2  col3  col4  col0  col1  col2  col3  col4  col0   col1  col3  col4
    row                                                                          
    row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.605  0.86  0.65
    row2  0.35  0.00  0.37  0.00  0.00  0.44  0.00  0.00  0.13  0.000  0.50  0.13
    row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.000  0.28  0.00
    row4  0.15  0.64  0.00  0.00  0.10  0.64  0.88  0.24  0.00  0.000  0.00  0.00
    
  8. または

    item      item0             item1                         item2                  
    col        col2  col3  col4  col0  col1  col2  col3  col4  col0  col1  col3  col4
    key  row                                                                         
    key0 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.86  0.00
         row2  0.00  0.00  0.37  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.50  0.00
         row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.00  0.00  0.00
         row4  0.15  0.64  0.00  0.00  0.00  0.00  0.00  0.24  0.00  0.00  0.00  0.00
    key1 row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.81  0.00  0.65
         row2  0.35  0.00  0.00  0.00  0.00  0.44  0.00  0.00  0.00  0.00  0.00  0.13
         row3  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.28  0.00
         row4  0.00  0.00  0.00  0.00  0.10  0.00  0.00  0.00  0.00  0.00  0.00  0.00
    key2 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.40  0.00  0.00
         row2  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.13  0.00  0.00  0.00
         row4  0.00  0.00  0.00  0.00  0.00  0.64  0.88  0.00  0.00  0.00  0.00  0.00
    
  9. 列と行が一緒に出現する頻度、つまり「クロス集計」を集計できますか?

    col   col0  col1  col2  col3  col4
    row                               
    row0     1     2     0     1     1
    row2     1     0     2     1     2
    row3     0     1     0     2     0
    row4     0     1     2     2     1
    
  10. 2つの列のみをピボットすることによって、DataFrameをロングからワイドに変換するにはどうすればよいですか?与えられた、

    np.random.seed([3, 1415])
    df2 = pd.DataFrame({'A': list('aaaabbbc'), 'B': np.random.choice(15, 8)})        
    df2        
       A   B
    0  a   0
    1  a  11
    2  a   2
    3  a  11
    4  b  10
    5  b  10
    6  b  14
    7  c   7
    

    予想は次のようになります

          a     b    c
    0   0.0  10.0  7.0
    1  11.0  10.0  NaN
    2   2.0  14.0  NaN
    3  11.0   NaN  NaN
    
  11. 後で複数のインデックスを単一のインデックスにフラット化する方法 pivot

    から

       1  2   
       1  1  2        
    a  2  1  1
    b  2  1  0
    c  1  0  0
    

       1|1  2|1  2|2               
    a    2    1    1
    b    2    1    0
    c    1    0    0
    

回答:


301

最初の質問に答えることから始めます。

質問1

なぜ私は得るのですか ValueError: Index contains duplicate entries, cannot reshape

これは、パンダが重複するエントリを持つcolumnsまたはindexオブジェクトのインデックスを再作成しようとしているために発生します。ピボットを実行できるさまざまな使用方法があります。それらのいくつかは、ピボットするように要求されているキーの重複がある場合にはあまり適していません。例えば。考えてくださいpd.DataFrame.pivotrowとのcol値を共有する重複したエントリがあることを知っています。

df.duplicated(['row', 'col']).any()

True

だから私がpivot使うとき

df.pivot(index='row', columns='col', values='val0')

上記のエラーが発生します。実際、次のコマンドで同じタスクを実行しようとすると、同じエラーが発生します。

df.set_index(['row', 'col'])['val0'].unstack()

これは、ピボットに使用できるイディオムのリストです

  1. pd.DataFrame.groupby + pd.DataFrame.unstack
    • ほぼすべてのタイプのピボットを実行するための優れた一般的なアプローチ
    • ピボットされた行レベルと列レベルを1つのグループで構成するすべての列を指定します。その後に、集計する残りの列と集計を実行する関数を選択します。最後unstackに、列インデックスに含めるレベルを指定します。
  2. pd.DataFrame.pivot_table
    • groupbyより直感的なAPI を備えた栄光のバージョン。多くの人にとって、これは好ましいアプローチです。そして、開発者が意図したアプローチです。
    • 行レベル、列レベル、集計する値、および集計を実行する関数を指定します。
  3. pd.DataFrame.set_index + pd.DataFrame.unstack
    • 一部のユーザーにとって便利で直感的です(自分も含む)。グループ化された重複キーを処理できません。
    • groupbyパラダイムと同様に、最終的に行または列レベルになるすべての列を指定し、それらをインデックスに設定します。次にunstack、列に必要なレベルを設定します。残りのインデックスレベルまたは列レベルのいずれかが一意でない場合、このメソッドは失敗します。
  4. pd.DataFrame.pivot
    • set_index複製キーの制限を共有するという点で非常に似ています。APIも非常に制限されています。それだけのためにスカラー値をとりindexcolumnsvalues
    • pivot_tableピボットする行、列、および値を選択するという点で、メソッドと同様です。ただし、集計することはできません。行または列が一意でない場合、このメソッドは失敗します。
  5. pd.crosstab
    • これpivot_tableは、いくつかのタスクを実行するための最も直感的な方法であり、その最も純粋な形式の特殊バージョンです。
  6. pd.factorize + np.bincount
    • これは非常に高度な技術であり、あいまいですが非常に高速です。すべての状況で使用できるわけではありませんが、使用できて快適に使用できる場合は、パフォーマンスが向上します。
  7. pd.get_dummies + pd.DataFrame.dot
    • クロス集計を巧みに実行するためにこれを使用します。

以降の各回答と質問で私がやろうとしていることは、を使用して回答することpd.DataFrame.pivot_tableです。次に、同じタスクを実行するための代替手段を提供します。

質問3

どのようにして旋回しないdfようなcol値が列です、row値は、平均で、インデックスされているval0値であり、欠損値がありますか0

  • pd.DataFrame.pivot_table

    • fill_valueデフォルトでは設定されていません。私はそれを適切に設定する傾向があります。この場合はに設定し0ます。お知らせ私はスキップ質問2を、それはせずに、この答えと同じだとしてfill_value
    • aggfunc='mean'デフォルトであり、設定する必要はありませんでした。明確にするために含めました。

      df.pivot_table(
          values='val0', index='row', columns='col',
          fill_value=0, aggfunc='mean')
      
      col   col0   col1   col2   col3  col4
      row                                  
      row0  0.77  0.605  0.000  0.860  0.65
      row2  0.13  0.000  0.395  0.500  0.25
      row3  0.00  0.310  0.000  0.545  0.00
      row4  0.00  0.100  0.395  0.760  0.24
      
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].mean().unstack(fill_value=0)
  • pd.crosstab

    pd.crosstab(
        index=df['row'], columns=df['col'],
        values=df['val0'], aggfunc='mean').fillna(0)
    

問題4

meanたぶん、以外のものをもらえますsumか?

  • pd.DataFrame.pivot_table

    df.pivot_table(
        values='val0', index='row', columns='col',
        fill_value=0, aggfunc='sum')
    
    col   col0  col1  col2  col3  col4
    row                               
    row0  0.77  1.21  0.00  0.86  0.65
    row2  0.13  0.00  0.79  0.50  0.50
    row3  0.00  0.31  0.00  1.09  0.00
    row4  0.00  0.10  0.79  1.52  0.24
    
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].sum().unstack(fill_value=0)
  • pd.crosstab

    pd.crosstab(
        index=df['row'], columns=df['col'],
        values=df['val0'], aggfunc='sum').fillna(0)
    

問題5

一度に複数の集計を実行できますか?

以下のためということに注意してくださいpivot_tablecrosstab私は呼び出し可能オブジェクトのリストを渡す必要がありました。一方、groupby.agg特殊な関数の限られた数の文字列を取ることができます。 groupby.agg他にも渡したのと同じ呼び出し可能オブジェクトを使用することもできますが、効率を上げるために文字列関数名を利用する方が効率的であることがよくあります。

  • pd.DataFrame.pivot_table

    df.pivot_table(
        values='val0', index='row', columns='col',
        fill_value=0, aggfunc=[np.size, np.mean])
    
         size                      mean                           
    col  col0 col1 col2 col3 col4  col0   col1   col2   col3  col4
    row                                                           
    row0    1    2    0    1    1  0.77  0.605  0.000  0.860  0.65
    row2    1    0    2    1    2  0.13  0.000  0.395  0.500  0.25
    row3    0    1    0    2    0  0.00  0.310  0.000  0.545  0.00
    row4    0    1    2    2    1  0.00  0.100  0.395  0.760  0.24
    
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].agg(['size', 'mean']).unstack(fill_value=0)
  • pd.crosstab

    pd.crosstab(
        index=df['row'], columns=df['col'],
        values=df['val0'], aggfunc=[np.size, np.mean]).fillna(0, downcast='infer')
    

質問6

複数の値列を集計できますか?

  • pd.DataFrame.pivot_table合格しvalues=['val0', 'val1']ましたが、完全に省略できました

    df.pivot_table(
        values=['val0', 'val1'], index='row', columns='col',
        fill_value=0, aggfunc='mean')
    
          val0                             val1                          
    col   col0   col1   col2   col3  col4  col0   col1  col2   col3  col4
    row                                                                  
    row0  0.77  0.605  0.000  0.860  0.65  0.01  0.745  0.00  0.010  0.02
    row2  0.13  0.000  0.395  0.500  0.25  0.45  0.000  0.34  0.440  0.79
    row3  0.00  0.310  0.000  0.545  0.00  0.00  0.230  0.00  0.075  0.00
    row4  0.00  0.100  0.395  0.760  0.24  0.00  0.070  0.42  0.300  0.46
    
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0', 'val1'].mean().unstack(fill_value=0)

質問7

複数の列で細分割できますか?

  • pd.DataFrame.pivot_table

    df.pivot_table(
        values='val0', index='row', columns=['item', 'col'],
        fill_value=0, aggfunc='mean')
    
    item item0             item1                         item2                   
    col   col2  col3  col4  col0  col1  col2  col3  col4  col0   col1  col3  col4
    row                                                                          
    row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.605  0.86  0.65
    row2  0.35  0.00  0.37  0.00  0.00  0.44  0.00  0.00  0.13  0.000  0.50  0.13
    row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.000  0.28  0.00
    row4  0.15  0.64  0.00  0.00  0.10  0.64  0.88  0.24  0.00  0.000  0.00  0.00
    
  • pd.DataFrame.groupby

    df.groupby(
        ['row', 'item', 'col']
    )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)
    

問題8

複数の列で細分割できますか?

  • pd.DataFrame.pivot_table

    df.pivot_table(
        values='val0', index=['key', 'row'], columns=['item', 'col'],
        fill_value=0, aggfunc='mean')
    
    item      item0             item1                         item2                  
    col        col2  col3  col4  col0  col1  col2  col3  col4  col0  col1  col3  col4
    key  row                                                                         
    key0 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.86  0.00
         row2  0.00  0.00  0.37  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.50  0.00
         row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.00  0.00  0.00
         row4  0.15  0.64  0.00  0.00  0.00  0.00  0.00  0.24  0.00  0.00  0.00  0.00
    key1 row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.81  0.00  0.65
         row2  0.35  0.00  0.00  0.00  0.00  0.44  0.00  0.00  0.00  0.00  0.00  0.13
         row3  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.28  0.00
         row4  0.00  0.00  0.00  0.00  0.10  0.00  0.00  0.00  0.00  0.00  0.00  0.00
    key2 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.40  0.00  0.00
         row2  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.13  0.00  0.00  0.00
         row4  0.00  0.00  0.00  0.00  0.00  0.64  0.88  0.00  0.00  0.00  0.00  0.00
    
  • pd.DataFrame.groupby

    df.groupby(
        ['key', 'row', 'item', 'col']
    )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)
    
  • pd.DataFrame.set_index キーのセットは行と列の両方で一意であるため

    df.set_index(
        ['key', 'row', 'item', 'col']
    )['val0'].unstack(['item', 'col']).fillna(0).sort_index(1)
    

問題9

列と行が一緒に出現する頻度、つまり「クロス集計」を集計できますか?

  • pd.DataFrame.pivot_table

    df.pivot_table(index='row', columns='col', fill_value=0, aggfunc='size')
    
        col   col0  col1  col2  col3  col4
    row                               
    row0     1     2     0     1     1
    row2     1     0     2     1     2
    row3     0     1     0     2     0
    row4     0     1     2     2     1
    
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].size().unstack(fill_value=0)
  • pd.crosstab

    pd.crosstab(df['row'], df['col'])
  • pd.factorize + np.bincount

    # get integer factorization `i` and unique values `r`
    # for column `'row'`
    i, r = pd.factorize(df['row'].values)
    # get integer factorization `j` and unique values `c`
    # for column `'col'`
    j, c = pd.factorize(df['col'].values)
    # `n` will be the number of rows
    # `m` will be the number of columns
    n, m = r.size, c.size
    # `i * m + j` is a clever way of counting the 
    # factorization bins assuming a flat array of length
    # `n * m`.  Which is why we subsequently reshape as `(n, m)`
    b = np.bincount(i * m + j, minlength=n * m).reshape(n, m)
    # BTW, whenever I read this, I think 'Bean, Rice, and Cheese'
    pd.DataFrame(b, r, c)
    
          col3  col2  col0  col1  col4
    row3     2     0     0     1     0
    row2     1     2     1     0     2
    row0     1     0     1     2     1
    row4     2     2     0     1     1
    
  • pd.get_dummies

    pd.get_dummies(df['row']).T.dot(pd.get_dummies(df['col']))
    
          col0  col1  col2  col3  col4
    row0     1     2     0     1     1
    row2     1     0     2     1     2
    row3     0     1     0     2     0
    row4     0     1     2     2     1
    

質問10

2つの列のみをピボットすることによって、DataFrameをロングからワイドに変換するにはどうすればよいですか?

最初のステップは、各行に番号を割り当てることです。この番号は、ピボットされた結果におけるその値の行インデックスになります。これは以下を使用して行われGroupBy.cumcountます:

df2.insert(0, 'count', df.groupby('A').cumcount())
df2

   count  A   B
0      0  a   0
1      1  a  11
2      2  a   2
3      3  a  11
4      0  b  10
5      1  b  10
6      2  b  14
7      0  c   7

2番目のステップは、新しく作成された列をインデックスとして使用して呼び出すことDataFrame.pivotです。

df2.pivot(*df)
# df.pivot(index='count', columns='A', values='B')

A         a     b    c
count                 
0       0.0  10.0  7.0
1      11.0  10.0  NaN
2       2.0  14.0  NaN
3      11.0   NaN  NaN

質問11

後で複数のインデックスを単一のインデックスにフラット化する方法 pivot

文字列でcolumns入力objectする場合join

df.columns = df.columns.map('|'.join)

そうしないと format

df.columns = df.columns.map('{0[0]}|{0[1]}'.format) 

43
公式ドキュメントの拡張を検討していただけませんか?
MaxU

質問#10の答えで何が起こりましたか?わかりますKeyError: 'A'。答えはまだありますか?
モニカヘドネック

@MonicaHeddneckもう一度確認し、必要に応じて更新します。ただし、グループ化するデータフレームに'A'列があると想定'A'しています。
piRSquared

複数の値列を集計できますか?これに対する答えは、異なるデータ型の列に対して機能します。例:values = ['val0'、 'val1']、ここでval0はint、val1はstring
Anil Kumar

1
問題の列10を挿入する必要はありません。ピボットテーブルの引数として直接渡すことができます
ansev

4

@piRSquaredの回答を拡張するには、質問10の別のバージョン

質問10.1

データフレーム:

d = data = {'A': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 3, 6: 5},
 'B': {0: 'a', 1: 'b', 2: 'c', 3: 'a', 4: 'b', 5: 'a', 6: 'c'}}
df = pd.DataFrame(d)

   A  B
0  1  a
1  1  b
2  1  c
3  2  a
4  2  b
5  3  a
6  5  c

出力:

   0     1     2
A
1  a     b     c
2  a     b  None
3  a  None  None
5  c  None  None

使用するdf.groupbyと、pd.Series.tolist

t = df.groupby('A')['B'].apply(list)
out = pd.DataFrame(t.tolist(),index=t.index)
out
   0     1     2
A
1  a     b     c
2  a     b  None
3  a  None  None
5  c  None  None

またはpd.pivot_tablewith を使用したはるかに良い代替手段df.squeeze.

t = df.pivot_table(index='A',values='B',aggfunc=list).squeeze()
out = pd.DataFrame(t.tolist(),index=t.index)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.