Python Pandas groupbyは便利
はじめに
データ分析していると、「集計後のデータがある条件にマッチする行だけ抽出したい」、「集計後のデータを集計前の対応する行に追加したい」などと思う場面があると思います。
それって、Pandasのgroupbyを使うと簡単にできます。みなさんご存じかもしれませんが、ちょっと使っていて便利だと思ったので共有したいと思います。
集計後のデータがある条件ににマッチする行だけ抽出したい
言葉で説明するとわかりにくいので実際に以下を例にしてみます。
Labelごとで集計してValueの合計が100より大きい場合、元のデータから対象の行を抽出する。
AのValueの合計は190(>100)、BののValueの合計は190(>100ではない)、CのValueの合計は120(>100)。このため、Label AとLabel Cの行を抽出するという動きです。
これは簡単にDataFrame.groupby.filterを使うことで実現できます。
df_test=pd.DataFrame([['A',50],['A',100],['A',40],['B',80],['B',10],['C',120]],columns=['Label','Value']) df_test.groupby(by=["Label"]).filter(lambda x: sum(x["Value"])>100) Label Value 0 A 50 1 A 100 2 A 40 5 C 120
filterを知らずにやろうとするといったん集計したデータを作ってjoinさせた上で特定の条件で絞り込む必要があります。
集計後のデータを使って集計前の対応する行ごとで計算したい
各グループごとでその個別の行の割合を出したいときですね。
これはDataFrame.groupby.applyを使うことで実現できます。
def calcPercent(x): x['Percentage']=x['Value']/x['Value'].sum() return x df_test.groupby(by=["Label"]).apply(calcPercent) Label Value Percentage 0 A 50 0.263158 1 A 100 0.526316 2 A 40 0.210526 3 B 80 0.888889 4 B 10 0.111111 5 C 120 1.000000
集計後のデータを集計前の対応する行に追加したい
こちらも言葉で説明するとわかりにくいので実際に以下を例にしてみます。
Labelごとで集計した合計値を元のデータフレームに追加する。
さきほどよりシンプルですが、これはDataFrame.groupby.transformを使うことで実現できます。
df_test["Total"]=df_test.groupby(by=["Label"])["Value"].transform('sum') Label Value Total 0 A 50 190 1 A 100 190 2 A 40 190 3 B 80 90 4 B 10 90 5 C 120 120
列ごとで異なる集計をしたい
言葉の通りですね。
これはDataFrame.groupby.aggregateを使うことで実現できます。
列名と集計方法のDictonaryをaggregateに渡します。
df_test=pd.DataFrame([['A',50,10],['A',100,20],['A',40,30],['B',80,40],['B',10,50],['C',120,60]],columns=['Label','Value','Value2']) df_test.groupby(by=["Label"]).aggregate({'Value':'sum','Value2':'mean'}) Value Value2 Label A 190 20 B 90 45 C 120 60
一つの列に対して異なる集計をしたい
これもDataFrame.groupby.aggregateを使うことで実現できます。
集計方法のListをaggregateに渡します。
df_test=pd.DataFrame([['A',50],['A',100],['A',40],['B',80],['B',10],['C',120]],columns=['Label','Value']) df_test.groupby(by=["Label"]).aggregate(['sum','max']) Value sum max Label A 190 100 B 90 80 C 120 120
以上です。