Pythonでndarray内の特定のアイテムの出現を数える方法は?


376

Pythonでは、次のように出力y されるndarray がありますarray([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

この配列にが0いくつあるか、がいくつあるかを数えようとしています1

しかし、私は、入力したときy.count(0)またはy.count(1)それが言います、

numpy.ndarray オブジェクトに属性がありません count

私は何をすべきか?


8
エースとゼロしかないので、合計と長さの関数を使用できませんか?
codingEnthusiast

この場合、単にを使用することも可能numpy.count_nonzeroです。
Mong H. Ng

回答:


610
>>> a = numpy.array([0, 3, 0, 1, 0, 1, 2, 1, 0, 0, 0, 0, 1, 3, 4])
>>> unique, counts = numpy.unique(a, return_counts=True)
>>> dict(zip(unique, counts))
{0: 7, 1: 4, 2: 1, 3: 2, 4: 1}

非派手な方法

を使用しcollections.Counterます。

>> import collections, numpy

>>> a = numpy.array([0, 3, 0, 1, 0, 1, 2, 1, 0, 0, 0, 0, 1, 3, 4])
>>> collections.Counter(a)
Counter({0: 7, 1: 4, 3: 2, 2: 1, 4: 1})

3
それは `` `unique、counts = numpy.unique(a、return_counts = True)dict(zip(unique、counts))` ``
細断します

25
辞書が必要な場合dict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi

2
変数に割り当てずに、配列の各一意の要素の出現回数にアクセスする場合はどうでしょうか-カウント。何かヒントはありますか?
sajis997

私は@ sajis997と同じ目標を持っています。groupbyの集計関数として 'count'を使用したい
p_sutherland

1
非常に大きなアレイ(〜30Gb)に対して両方の方法を使用してみました。Numpyメソッドはメモリ不足になりましたが、collections.Counter問題なく動作しました
Ivan Novikov

252

numpy.count_nonzeroようなものはどうですか

>>> import numpy as np
>>> y = np.array([1, 2, 2, 2, 2, 0, 2, 3, 3, 3, 0, 0, 2, 2, 0])

>>> np.count_nonzero(y == 1)
1
>>> np.count_nonzero(y == 2)
7
>>> np.count_nonzero(y == 3)
3

20
この回答は、賛成票が最も多い回答よりも優れているようです。
アレックス

1
numpy.ndarrayOPが最初に尋ねたようにこれはうまくいくとは思いません。
LYu 2018

5
@LYu-この答えのyはnp.ndarrayです。また、すべてではないにしてもほとんどのnp.something関数は問題なくndarrayで機能します。
mmagnuski

132

個人的には、私は行きます: (y == 0).sum()そして(y == 1).sum()

例えば

import numpy as np
y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
num_zeros = (y == 0).sum()
num_ones = (y == 1).sum()

1
それは間違いなく最も読みやすいです。質問は最速である、最も効率的なスペース
ネイサン

ベクトル(y == 0)を評価するため、numpy.count_nonzero(y == 0)よりスペース効率が低い可能性があります
Sridhar Thiagarajan '27

これはmatlab / octaveに似ているので、気に入っていますsum( vector==value )
ePi272314

39

あなたの場合は、numpy.bincountを調べることもできます

In [56]: a = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

In [57]: np.bincount(a)
Out[57]: array([8, 4])  #count of zeros is at index 0 : 8
                        #count of ones is at index 1 : 4

このコードは、私が実験した大規模な配列の最も速いソリューションの1つかもしれません。結果をリストとして取得することもおまけです。ありがとう!
Youngsup Kim、2018

そして、 'a'がn次元配列の場合、次のように使用できます。np.bincount(np.reshape(a、a.size))
アリ

21

あなたの配列は、変換yリストにlしてから行うl.count(1)l.count(0)

>>> y = numpy.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
>>> l = list(y)
>>> l.count(1)
4
>>> l.count(0)
8 

19
y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

あなたは彼らがちょうどあることを知っている場合01

np.sum(y)

1の数を与えます。 np.sum(1-y)ゼロを与える。

少し一般的に、0ゼロではなくカウントしたい場合(ただし、2または3):

np.count_nonzero(y)

非ゼロの数を与えます。

しかし、もっと複雑なものが必要な場合は、numpyが優れたcountオプションを提供するとは思いません。その場合は、コレクションに移動します。

import collections
collections.Counter(y)
> Counter({0: 8, 1: 4})

これは口述のように振る舞います

collections.Counter(y)[0]
> 8

13

探している番号が正確にわかっている場合は、以下を使用できます。

lst = np.array([1,1,2,3,3,6,6,6,3,2,1])
(lst == 2).sum()

配列で2が発生した回数を返します。


8

正直なところ、パンダシリーズまたはDataFrameに変換するのが最も簡単です。

import pandas as pd
import numpy as np

df = pd.DataFrame({'data':np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])})
print df['data'].value_counts()

または、Robert Muilによって提案されたこの素晴らしいワンライナー:

pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()

4
注:DataFrameやnumpyは必要ありません。リストからシリーズに直接移動できます: pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
Robert Muil

すごい、それは素晴らしいワンライナーです。ビッグアップ
ワードフォーザワイズ

8

での使用numpy.bincount(input, minlength)は推奨されていませんminlength = np.size(input)が、それは良い解決策であり、間違いなく最速のようです:

In [1]: choices = np.random.randint(0, 100, 10000)

In [2]: %timeit [ np.sum(choices == k) for k in range(min(choices), max(choices)+1) ]
100 loops, best of 3: 2.67 ms per loop

In [3]: %timeit np.unique(choices, return_counts=True)
1000 loops, best of 3: 388 µs per loop

In [4]: %timeit np.bincount(choices, minlength=np.size(choices))
100000 loops, best of 3: 16.3 µs per loop

それは間クレイジー高速化だnumpy.unique(x, return_counts=True)numpy.bincount(x, minlength=np.max(x))


ヒストグラムと比較してどうですか?
john ktejik 2018年

@johnktejik np.histogramは同じことを計算しません。histogram申し訳ありませんが、私が提案する3つのアプローチを機能と比較しても意味がありません。
Næreen

1
bincountただし、@Næreen は整数に対してのみ機能するため、OPの問題に対しては機能しますが、タイトルに記載されている一般的な問題に対しては機能しない可能性があります。またbincount、非常に大きなint を持つ配列を使用してみましたか?
不可解な夜

@ImperishableNightいいえ、私は大規模なint型を試していないが、しかし、誰もがそうすると、独自のベンチマークを投稿する歓迎です:-)
Næreen

この過小評価されたトリックをありがとう!私のマシンでbincountは、の約4倍高速ですunique
ビョルンLindqvist


6

y.tolist().count(val)

値0または1

Pythonリストにはネイティブ関数があるため、countその関数を使用する前にリストに変換することは簡単な解決策です。


5

さらに別の簡単な解決策は、numpy.count_nonzero()を使用することです

import numpy as np
y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
y_nonzero_num = np.count_nonzero(y==1)
y_zero_num = np.count_nonzero(y==0)
y_nonzero_num
4
y_zero_num
8

名前が誤解を招かないようにしてください。例のようにブール値で使用すると、うまくいきます。


5

発生数をカウントするには、次のように使用できますnp.unique(array, return_counts=True)

In [75]: boo = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

# use bool value `True` or equivalently `1`
In [77]: uniq, cnts = np.unique(boo, return_counts=1)
In [81]: uniq
Out[81]: array([0, 1])   #unique elements in input array are: 0, 1

In [82]: cnts
Out[82]: array([8, 4])   # 0 occurs 8 times, 1 occurs 4 times

4

私はnp.whereを使用します:

how_many_0 = len(np.where(a==0.)[0])
how_many_1 = len(np.where(a==1.)[0])


2

一般的で簡単な答えは次のとおりです。

numpy.sum(MyArray==x)   # sum of a binary list of the occurence of x (=0 or 1) in MyArray

これは、例としてこの完全なコードになります

import numpy
MyArray=numpy.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])  # array we want to search in
x=0   # the value I want to count (can be iterator, in a list, etc.)
numpy.sum(MyArray==0)   # sum of a binary list of the occurence of x in MyArray

MyArrayが複数の次元にあり、値の分布の発生を数えたい場合(=以下のパターン)

MyArray=numpy.array([[6, 1],[4, 5],[0, 7],[5, 1],[2, 5],[1, 2],[3, 2],[0, 2],[2, 5],[5, 1],[3, 0]])
x=numpy.array([5,1])   # the value I want to count (can be iterator, in a list, etc.)
temp = numpy.ascontiguousarray(MyArray).view(numpy.dtype((numpy.void, MyArray.dtype.itemsize * MyArray.shape[1])))  # convert the 2d-array into an array of analyzable patterns
xt=numpy.ascontiguousarray(x).view(numpy.dtype((numpy.void, x.dtype.itemsize * x.shape[0])))  # convert what you search into one analyzable pattern
numpy.sum(temp==xt)  # count of the searched pattern in the list of patterns

2

辞書内包表記を使用して、きちんとしたワンライナーを作成できます。辞書の理解についての詳細はここにあります

>>>counts = {int(value): list(y).count(value) for value in set(y)}
>>>print(counts)
{0: 8, 1: 4}

これにより、ndarray内の値をキーとして持つディクショナリが作成され、値の数がキーの値としてそれぞれカウントされます。

これは、このフォーマットの配列内の値の出現回数を数えたいときにいつでも機能します。


2

これを試して:

a = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
list(a).count(1)

1

これは次の方法で簡単に行うことができます

y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
y.tolist().count(1)

1

ndarrayには0と1しか含まれていないため、sum()を使用して1の出現を取得し、len()-sum()を使用して0の出現を取得できます。

num_of_ones = sum(array)
num_of_zeros = len(array)-sum(array)

1

ここには1と0だけの特別な配列があります。トリックは使用することです

np.mean(x)

これにより、配列内の1の割合がわかります。または、

np.sum(x)
np.sum(1-x)

配列の1と0の絶対数を取得します。


1
dict(zip(*numpy.unique(y, return_counts=True)))

ここに適切な答えに値するSeppo Enarviのコメントをコピーしました


0

これにはもう1つの手順が含まれますが、2D配列やより複雑なフィルターでも機能するより柔軟なソリューションは、ブールマスクを作成してから、マスクで.sum()を使用することです。

>>>>y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
>>>>mask = y == 0
>>>>mask.sum()
8

0

numpyまたはコレクションモジュールを使用したくない場合は、辞書を使用できます。

d = dict()
a = [0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]
for item in a:
    try:
        d[item]+=1
    except KeyError:
        d[item]=1

結果:

>>>d
{0: 8, 1: 4}

もちろん、if / elseステートメントを使用することもできます。Counter関数はほとんど同じことをすると思いますが、これはより透明です。


0

一般的なエントリの場合:

x = np.array([11, 2, 3, 5, 3, 2, 16, 10, 10, 3, 11, 4, 5, 16, 3, 11, 4])
n = {i:len([j for j in np.where(x==i)[0]]) for i in set(x)}
ix = {i:[j for j in np.where(x==i)[0]] for i in set(x)}

カウントを出力します:

{2: 2, 3: 4, 4: 2, 5: 2, 10: 2, 11: 3, 16: 2}

そしてインデックス:

{2: [1, 5],
3: [2, 4, 9, 14],
4: [11, 16],
5: [3, 12],
10: [7, 8],
11: [0, 10, 15],
16: [6, 13]}

0

ここに私は何かを持っています、それを通してあなたは特定の数の発生数を数えることができます:あなたのコードに従って

count_of_zero = list(y [y == 0])。count(0)

print(count_of_zero)

//一致に応じてブール値があり、True値に応じて数値0が返されます


0

最速の実行に関心がある場合、検索する値が事前にわかっており、配列が1Dであるか、それ以外の場合は、フラット化された配列の結果に関心があります(この場合、関数の入力はことnp.flatten(arr)だけではなくarr)、そしてNumbaはあなたの友達です。

import numba as nb


@nb.jit
def count_nb(arr, value):
    result = 0
    for x in arr:
        if x == value:
            result += 1
    return result

または、並列化が有益な非常に大きな配列の場合:

@nb.jit(parallel=True)
def count_nbp(arr, value):
    result = 0
    for i in nb.prange(arr.size):
        if arr[i] == value:
            result += 1
    return result

これらに対するベンチマークnp.count_nonzero()(回避できる一時的な配列を作成するという問題もあります)およびnp.unique()ベースのソリューション

import numpy as np


def count_np(arr, value):
    return np.count_nonzero(arr == value)
import numpy as np


def count_np2(arr, value):
    uniques, counts = np.unique(a, return_counts=True)
    counter = dict(zip(uniques, counts))
    return counter[value] if value in counter else 0 

入力で生成された場合:

def gen_input(n, a=0, b=100):
    return np.random.randint(a, b, n)

次のプロットが得られます(プロットの2行目は、より高速なアプローチのズームです)。

bm_full bm_zoom

NumbaベースのソリューションはNumPyの対応ソリューションよりも著しく高速であり、非常に大きな入力の場合、並列アプローチは単純なものより高速であることを示しています。


完全なコードはこちらから入手できます


0

ジェネレータを使用して非常に大きな配列を処理している場合は、オプションになる可能性があります。ここでの良い点は、このアプローチが配列とリストの両方で正常に機能し、追加のパッケージが必要ないことです。さらに、それほど多くのメモリを使用していません。

my_array = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
sum(1 for val in my_array if val==0)
Out: 8

-1

Numpyにはこのためのモジュールがあります。ほんの小さなハック。入力配列をビンとして配置します。

numpy.histogram(y, bins=y)

出力は2つの配列です。1つは値自体、もう1つは対応する頻度です。


「ビン」は数字ではないのですか?
john ktejik 2018年

1
はい、@ johnktejikのとおりです。この回答は機能しませ
Næreen

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.