こしあん
2018-08-28

Numpyのみでグループ別に集計し平均を出す方法(for文、Pandasなし)

Pocket
LINEで送る


Numpy配列をグループ別に集計するときに、大抵Pandasを使うのですが、Numpyだけで集計するのってできるのかな?どうやるんだろうという話です。答えは「できます」。one-hotベクトルを使って集計する方法を紹介していきます。

このアイディアはTwitterで教えてもらったものです。教えてくださった方に感謝。

データの用意

説明のためにIrisデータセットを使います。(花弁の長さ, アヤメの種類)の形式の配列を作ります。花弁の長さはcmで、アヤメの種類はSetosa, Versicolour, Virginicaの順に0,1,2とします。

from sklearn.datasets import load_iris
import numpy as np

iris = load_iris()
# [花弁の長さ, アヤメの種類]のデータを作る
data = np.c_[np.array(iris["data"][:,3]), np.array(iris["target"])]
print(data)
print()

このような配列です。

[[0.2 0. ]
 [0.2 0. ]
 [0.2 0. ]
(略)
 [1.4 1. ]
 [1.5 1. ]
 [1.5 1. ]
 (略)]

集計

アヤメの種類をOne-hotベクトル化します。これと集計したい花弁の長さのベクトルをかけ合わせて、列単位の平均を取ります。

# アヤメの種類をone-hotベクトル化
onehot = np.eye(int(np.max(data[:,1]))+1)[data[:,1].astype("int")]
# one-hotの0をNaNに置き換える
onehot[onehot==0] = np.nan
# 花弁の長さ×one-hot
length_oh = data[:,0].reshape(-1,1) * onehot
# 列単位の平均(Nanを除外して平均)
group_mean = np.nanmean(length_oh, axis=0)
print(group_mean)

グループの数が多いとちょっとメモリ食うかもしれません。one-hotベクトルをそのまま平均を取ってしまうと0の影響を受けてしまうので事前にNaNに置き換えます。np.nanmeanはNaNを除外して計算する関数です。標準偏差を取りたい場合はnanstdとします。

結果は以下の通りです。

[0.244 1.326 2.026]

NaNでもなんでもいいので、one-hotベクトル使って集計するときは必ず0を除外することを忘れないようにしてください。

Pocket
Delicious にシェア

Tags:

Add a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です