こしあん
2018-11-22

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

Pocket
LINEで送る
Delicious にシェア

8.3k{icon} {views}

新刊情報

技術書典8の新刊『モザイク除去から学ぶ 最先端のディープラーニング』(A4・195ページ)好評通販中です! 機械学習の入門からGANの最先端までを書いたおすすめの本となっています! Boothで試し読みできます。情報まとめ・質問用GitHub



アンサンブル学習などで、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でも多数決ができましたね。


新刊情報

技術書典8の新刊『モザイク除去から学ぶ 最先端のディープラーニング』好評通販中(A4・195ページ)です! Boothで試し読みもできるのでよろしくね!


Pocket
LINEで送る
Delicious にシェア

Add a Comment

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