こしあん
2018-11-22

Numpyの配列に対して「最も多く存在する値」を求める方法


20.4k{icon} {views}


アンサンブル学習などで、Numpyの配列のある軸に対して「最も多く存在する値」を求めたい、つまり「多数決」をしたいことがあります。その方法を見ていきます。

最も大きい値がmax, 最も大きい値が存在するインデックスがargmax, では「最も多く存在する値」は?

配列のある軸に対して、「最も大きい値」「最も大きい値が存在するインデックス」を求めるのは簡単です。どちらもNumpyの関数であり、np.max, np.argmaxを使えばいいのです。

import numpy as np

np.random.seed(2)
X = np.random.randint(0, 3, size=(5, 3))
print(X)

# 列の中での最大値を求める
print(np.max(X, axis=-1))

# 列の中での、最大値が存在するインデックスを求める
print(np.argmax(X, axis=-1))

出力は以下のとおりです。

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

要するにmaxやargmaxと同じような感覚で使える、「最も存在する値」を求める関数がほしいのです。どうすればよいのでしょうか?

scipy.stats.modeを使う

「最も存在する値」とは統計学の用語では「最頻値」なので、これを返す関数を使えばいいのです。運良くnp.maxやnp.argmaxなどと同じように軸を指定できます。

scipy.stats.mode
https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.mode.html

ただし、注意点が1つだけ。数量が同一の値が複数存在したら、数字が小さいほうの値が返されます。例えば、「0, 1, 1, 2, 2」という値に対してmodeを使うと、返される値は「1」となります。

import numpy as np
import scipy.stats as stats

np.random.seed(2)
X = np.random.randint(0, 3, size=(5, 3))
print(X)

# 最頻値を求める(最頻値、その数 の順番)
print(stats.mode(X, axis=-1))

# 分割してもOK
mode_val, mode_num = stats.mode(X, axis=-1)
print(mode_val)

# インデックスでやってもOK
print(stats.mode(X, axis=-1)[0])

このようになります。返り値は2つあり、「最頻値」と「最頻値が存在する個数」になります。

[[0 1 0]
 [2 2 0]
 [2 1 1]
 [2 0 0]
 [0 1 2]]
ModeResult(mode=array([[0],
       [2],
       [1],
       [0],
       [0]]), count=array([[2],
       [2],
       [2],
       [2],
       [1]]))
[[0]
 [2]
 [1]
 [0]
 [0]]
[[0]
 [2]
 [1]
 [0]
 [0]]

以上です。これでNumpyでも多数決ができましたね。



Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内

技術書コーナー

北海道の駅巡りコーナー


Add a Comment

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