今回は、Pandasを使って条件付きで値をグループ化する方法を紹介します。
Python Pandasのgroupbyについては、すでに詳しく解説しています。
そのため、関数の仕組みがよくわからない場合は記事に目を通しておくとよいでしょう。
グループ化とは
データベースやデータフレームをグループ化することは、日常的なデータ分析やデータクリーニングでよく行われることです。
グループ化とは、同じデータ(または同じ性質を持つデータ)を異なるグループにまとめることです。
例えば 例えば、ある学校のデータベースに、すべてのクラスの生徒が登録されているとします。
校長がクラス間の成績や出席率を比較したい場合、各クラスの平均データを比較する必要があります。
しかし、どのようにそれを行うことができますか?校長は、生徒のデータをどのクラスに属するかによってグループ分けし(同じクラスの生徒は同じグループに入る)、次にグループ内の各生徒のデータを平均化するのです。
この例は非常に理想的な状況を扱っていますが、これはグループ化の最も基本的な応用です。
グループ化は、複数のプロパティに基づくことができます。
これは階層的なグループ化と呼ばれ、データの他の特性に基づいてグループがさらに小さなグループに分割されることもあります。
これにより、クエリーは必要なだけ複雑にすることができる。
また、この例では無視したのですが、データベース内のすべてのデータが平均化されている必要はないという、非常に基本的な問題があります。
例えば、各クラスの平均的な出席率とパーセンテージだけを比較する必要がある場合、携帯電話番号やロール番号など、平均が意味をなさない他の値を無視することができます。
今回は、このような複雑なグループ化コマンドをpandasで作成する方法を学びます。
df.groupby() を使った Pandas でのグループ化
Pandasの df.groupby()
は、データフレームを分割して mean()
や sum()
などの関数を適用し、グループ化されたデータセットを形成する機能を提供します。
これはデータフレームにとって怖い操作に思えるので、まずはデータの分割とデータの適用・結合の2組に作業を分けてみましょう。
この例では、Kaggleのスーパーマーケットデータセットを使用します。
# Importing the data import pandas as pd
# Our dataframe. The csv file can be downloaded fro above hyperlink. df = pd.read_csv( 'supermarket_sales - Sheet1.csv' )
# We drop some redundant columns df.drop([ 'Date' , 'Invoice ID' , 'Tax 5%' ], axis = 1 , inplace = True )
# Display the dataset df.head() |
# We split the dataset by column 'Branch'. # Rows having the same Branch will be in the same group. groupby = df.groupby( 'Branch' , axis = 0 )
# We apply the accumulator function that we want. Here we use the mean function here but we can also other functions. groupby.mean() |
出力する
# Binning of the data based on a condition df.loc[df.Quantity < 3 , 'Quantity' ] = 0
df.loc[df.Quantity > = 3 , 'Quantity' ] = 1
# Grouping and couting df.groupby( 'Quantity' ).count()
|
df.groupby()関数は、ラベルまたはラベルのリストを受け取ることができます。
ここでは、Branchという列を基準にグループ化したいので、関数の定義で’Branch’のみを指定しています。
また、どの軸に沿ってグループ化を行うかを指定する必要があります。
軸=1は「列」を表し、軸=0`は「インデックス」を表します。
# Filter out columns of our interest df_1 = df.loc[:, [ "Quantity" , "Unit price" ]]
# We have already binned the quantity data into 0 and 1's for counting. # So we don't need any pre-processing # Group the data groupby = df_1.groupby( "Quantity" , axis = 0 )
# Apply the function(here mean) groupby.mean() |
結果は以下の通りです。
df = pd.read_csv( 'supermarket_sales - Sheet1.csv' )
# We need to mention the labels to be filterd in items df. filter (items = [ "City" , "Gender" ]).head()
|
グループ化されたデータフレームの作成方法を学んだので、次はグループ化するための条件をデータに適用する方法を学びます。
この記事もチェック:Pandasのデータフレームに行を追加する5つの簡単な方法
Discrete and Continuous Data (離散および連続データ)
# We can specify the regex literal under regex in the function df. filter (regex = "^C" ).head()
|
グループ化には離散(表形式)データを使うのが一般的です。
連続データはグループ化には不向きです。
しかし、これではデータ分析に限界があるのではないでしょうか?もちろんそうです。
そこで、回避策が必要です。
連続データをビンニングして、表形式にするのです。
例えば、パーセンテージは連続データですが、これをラベル付きのデータに変換するために、あらかじめ4つのグループ(Excellent (75-100), Good (50-75), Poor (25-50), Very-Poor (0-25))を定義しておくのです。
この4つのグループに分類されたデータは、どんなに多様なデータであっても、この4つのグループに分類されることになります。
df.query( 'Quantity > 3' ).head()
|
もう一つの方法は、異なる値に対して真と偽を使うことです。
例えば、スーパーマーケットの店長は、一度に3つ以上の商品を買った客が何人いるかを調べたい。
この場合、商品の数を、3個以上なら1/真、それ以外なら0/偽で置き換えるのが一つの方法です。
df.query( 'Quantity > 3 & Payment=="Cash"' ).head()
|
結果を出力すると、以下の様になります。
# Query the database for Quantity greater than 3 df_g = df.query( 'Quantity > 3' )
# Filter out labels of interest df_g = df_g. filter ([ 'City' , 'Unit price' ])
# Group the value according to a condition df_g.groupby( 'City' ).mean()
|
他のカラムに基づく条件付きグループ化
最後のクエリでは、3つ以上の商品が売れたかどうかに基づいて、データフレームをグループにグループ化する必要があります。
一度に 3 つ以上の商品を購入した場合の平均単価を求める必要があります。
-
- 興味のある列をフィルタリングする必要があります。
-
- 連続データに対してグループ化する場合、連続データを表形式データに変換する必要がある。
-
- データを分割するために
df.groupby()
を使用します。
- データを分割するために
-
- 集計関数を適用します。
上の図からわかるように、一度に3つ以上購入された商品の単価は55.5846です。
Pandasは df.filter()
や df.query()
などの組み込み関数により、クエリを簡単に行うことができます。
これにより、ユーザはデータベースに対してより高度で複雑なクエリを作成することができます。
これらは、前の例で見たdf.locの上位の抽象化です。
df.filter()メソッド
Pandasのfilterメソッドは、dataframeのラベルをフィルタリングすることができます。
データフレームの中身に作用するわけではありません。
以下は、データセットのCityとGenderのラベルをフィルタリングする例です。
Regexもラベルのフィルタリングに利用できる。
ここでは、文字Cで始まるラベルをフィルタリングしてみる。
df.query()メソッド
query メソッドは、データフレームのカラムの内容を任意の複雑さにクエリすることができます。
ここでは、顧客が一度に3つ以上の記事を購入したケースを見つける例を示します。
また、’&’や’|’を使って多くの条件を組み合わせることができる。
例えば、「一度に3つ以上の商品を購入し、現金で支払った場合」を調べたい場合です。
df.query() と df.filter() と df.groupby() の組み合わせ
3個以上売れたかどうかでdataframeをグループ分けする問題を解決したい。
各都市で一度に3つ以上購入された記事の平均単価を求める必要があります。
この3つのステップで進める。
-
-
df.query()
を使って、3つ以上の物品を持つデータをフィルタリングします。
-
-
-
df.filter()
を使って、関心のあるラベル(ここでは City と Unit Price)だけを残す。
-
-
-
df.groupby()
を使って、データをグループ化します。
-
参考文献
- Pandasのgroupby()関数の理解
- Pandas の groupby 関数について – JournalDev.