サイトアイコン たーちゃんの「ゼロよりはいくらかましな」

【python】pandasとnumpyでビニング処理(ビン分割処理)

ビニング処理(ビン分割処理)とは、

連続する値を値の境界で分割する処理です。

 

 

例えば、テストの点数でA、B、Cランクに分けたりするのが

イメージしやすいですかねー。

 

 

そしてこの手の処理は自前で書けなくもないですが、

pandasやnumpyでサクッとできてしまいますので、

車輪の再開発は不要です。

 

 

 

 

pandasのビニング処理

df = pd.DataFrame({"x": range(1, 100)})
df["bin_label"] = pd.qcut(df["x"], 4, labels=["A", "B", "C", "D"])
print(df)

 

これだけです。

結果は以下のようになります。

     x bin_label
0    1         A
1    2         A
2    3         A
3    4         A
4    5         A
..  ..       ...
94  95         D
95  96         D
96  97         D
97  98         D
98  99         D

 

データとしてはxというカラムに1〜99までのデータが入っていて、

それを4分割し、それぞれA、B、C、Dとラベルをつける処理になります。

 

分割数は、pd.qcutの第2引数で指定します。

この場合だと25%、50%、75%、100%でグループ分けされるようなイメージです。

 

 

numpyのビニング処理

pandasなんて使ってないよー。

ただの配列データも同じようにできないのー?となったらnumpyの出番です。

 

bin_data = [x for x in range(0, 100)]
hist = np.histogram(bin_data, bins=4)

print(hist)

bin_list = np.digitize(bin_data, hist[1][1:], right=True)

print(bin_list)

list_by_group = [
    [x for ind, x in enumerate(bin_data) if bin_list[ind] == bin_num]
    for bin_num in range(0, 4)
]
print(list_by_group)

 

まずはnp.histogramで境界を決定します。

第1引数に配列データ、binsに分割数を渡します。

すると、以下のようなデータが返却されます。

(array([25, 25, 25, 25]), array([ 0.  , 24.75, 49.5 , 74.25, 99.  ]))

 

最初のarrayは、各分割にいくつの要素があるか

2番目のarrayには、境界値が返却されます。

 

 

この結果を用いて、np.digitizeしていきます。

第1引数は配列データ、

第2引数に境界値、

最後のrightですが、これは最後の要素をどちらに含めるか?になります。

 

また、histgram[1][1:]としているのは、

histgramの境界値には必ず最初の要素だけを含むグループができてしまいます。

その状態でdigitizeしてしまうと同じように最初のグループが別にできてしまうので、

[1:]として最初の要素を省いています。

 

4分割した場合、境界値の最後の要素は別の分割になり、

5分割になってしまうのですが、これをTrueとすることで4つ目のグループに

含めますよーということになります。

 

 

ただ、このnp.digitizeの戻り値は以下のように各要素がどのグループに

属するか?という情報しか返ってきません。

[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3]

 

 

では、どうするか?というと、

list_by_group = [
    [x for ind, x in enumerate(bin_data) if bin_list[ind] == bin_num]
    for bin_num in range(0, 4)
]

 

こんな感じでグループごとに配列化してあげると良いかなと思います。

これで以下のように返ってきます。

 

[
  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], 
  [25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49], 
  [50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74], 
  [75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
]

 

 

もしかすると、あまり使用する機会にめぐりあわないかもしれませんが、

こんなことも出来たんだ!という発見の共有でした!

 

 

それでは!!!

 

 


にほんブログ村


人気ブログランキング

モバイルバージョンを終了