LoginSignup
1
0

More than 1 year has passed since last update.

numpy.bincount()で配列の非負整数をカウント

Last updated at Posted at 2022-07-31

numpy.bincount()関数で一次元配列の中で非負整数が何回登場したかを整数ごとにカウントできる。オプション引数weightsminlenghthについても触れる。

import numpy as np
x = np.tile([0, 1], 3)
print(x)
# 実行結果 
# [0 1 0 1 0 1] 

print(np.bincount(x))
# 実行結果
# [3 3]

y = np.array([1, 2])
z = np.hstack((x,y))
print(z)
# 実行結果 
# [0 1 0 1 0 1 1 2]
 
print(np.bincount(z))
# 実行結果 
# [3 4 1]

# 値が連続していない場合 
a = np.array([1, 5, 5])
print(np.bincount(a))
# 実行結果 
# [0 1 0 0 0 2]

配列aのnp.amax(a)の返り値がnだったとするとnp.bincount(a)の返り値の配列の長さは0を含めてデフォルトでn+1になる。配列に含まれていない数字に関しては0が返される。
一次元配列じゃない配列を入れるとValueErrorが出る。

b = np.arange(6).reshape(2, 3)
try:
    np.bincount(b)
except ValueError as e:
    print("ValueError :", e)
# 実行結果 
# ValueError : object too deep for desired array

その場合一旦平坦化する

print(np.bincount(b.ravel()))
# 実行結果 
# [1 1 1 1 1 1]

負の整数が入ってるとValueErrorが出る

c = np.array([-2, 3, 10, 4, 8])
 
try:
    np.bincount(c)
except ValueError as e:
    print("ValueError :", e)
# 実行結果 
# ValueError : 'list' argument must have no negative elements

代替案的な何か

d = np.vstack((np.arange(c.min(), c.max() + 1),
               np.bincount(c - c.min())))
print(d)
# 実行結果
# [[-2 -1  0  1  2  3  4  5  6  7  8  9 10]
#  [ 1  0  0  0  0  1  1  0  0  0  1  0  1]]

オプション引数

np.bincount(x, weights=None, minlength=0)

z = np.array([0, 1, 0, 1, 0, 1, 1, 2])
w = np.array([.1, .3, -.4, .2, .6, 1.3, 3., -2.])
print(np.bincount(z, w))
# 実行結果  
# [ 0.3 4.8 -2. ]

これは次と一緒 

print(np.array([w[z == i].sum() for i in np.unique(z)])
# 実行結果 
# [ 0.3 4.8 -2. ] 

weightsはxと同じ形の必要がある。
デフォルトではnp.bincount(arr)の返り値の長さはnp.amax(arr) + 1になるが、オプション引数minlengthで変更できる。

print(np.bincount(z))
# 実行結果 
# [3 4 1]

print(np.bincount(z, minlength=5)
# 実行結果 
# [3 4 1 0 0] 

print(np.bincount(z, minlength=1)
# 実行結果 
# [3 4 1] 

minlengthnp.amax(arr) + 1よりも大きい場合はnp.bincountの返り値の長さはminlengthになる。  
minlenghtnp.amax(arr) + 1以下である場合、返り値の長さはnp.amax(arr) + 1になる。 

サンプルコード 

scikit-learnのirisデータセットにnp.bincountを使ってみる。 

from sklearn.datasets import load_iris
iris = load_iris()

irisデータセットはクラス分類のためのトイデータ
iris.dataには150サンプルの4つの特徴量がnumpy_ndarrayとして格納されている。
iris.targetにはクラスラベル(3種類、1、2、3)
iris.target_namesはクラスの名前
iris.feature_namesに四つの特徴量の名前が入っている 

print(iris.data.shape)
# 実行結果 
# (150, 4) 

print(iris.target.shape)
# 実行結果 
# (150,)
 
print(np.unique(iris.target))
# 実行結果 
# [0 1 2]

print(iris.target_names)
# 実行結果 
# ['setosa' 'versicolor' 'virginica']

print(iris.feature_names)
# 実行結果
# ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

では本題 
np.bincount()を使ってみる 

# 各クラスにサンプルが何個ずつあるか?
for target, count in zip(iris.target_names,
                         np.bincount(iris.target)):
    print(target, count)
# 実行結果
# setosa 50
# versicolor 50
# virginica 50

# sepal length (cm) の各クラスごとの平均 
sl = iris.data[:, 0]
averages = np.bincount(iris.target, sl) / np.bincount(iris.target)
for name, average in zip(iris.target_names, averages):
    print(name, "{:.2f}".format(average))
# 実行結果 
# setosa 5.01 
# versicolor 5.94
# virginica 6.59

まとめ 

お疲れ様です
バージョンは 

print(np.__version__)
# 実行結果 
# 1.21.5

import sklearn
print(sklearn.__version__)
# 実行結果 
# 1.0.2
1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0