リストアイテムの出現回数をどのようにカウントできますか?


1530

アイテムが与えられた場合、Pythonのリストでその出現回数をどのようにカウントできますか?

回答:


1853

1つのアイテムの数だけが必要な場合は、次のcountメソッドを使用します。

>>> [1, 2, 3, 4, 1, 4, 1].count(1)
3

複数のアイテムをカウントする場合、これを使用しないでくださいcountループで呼び出すには、count呼び出しごとにリストを個別に渡す必要があるため、パフォーマンスが壊滅的になる可能性があります。Counter他の回答で説明されているように、すべてのアイテム、または複数のアイテムを数える場合は、を使用します。


6
mylist = [1,7,7,7,3,9,9,9,7,9,10,0] print sorted(set([i for i in mylist if mylist.count(i)>2]))
cpp-coder

1746

CounterPython 2.7または3.xを使用していて、各要素の出現回数を知りたい場合に使用します。

>>> from collections import Counter
>>> z = ['blue', 'red', 'blue', 'yellow', 'blue', 'red']
>>> Counter(z)
Counter({'blue': 3, 'red': 2, 'yellow': 1})

2
これをたくさん使用すると(何百万もの文字列について)、への呼び出しのために非常に遅くなることがわかりましたisinstance。したがって、操作しているデータについて確信がある場合は、型とインスタンスのチェックを行わずにカスタム関数を記述する方がよいでしょう。
Bram Vanroy

2
@BramVanroy:何をisinstance呼びますか?何百万もの文字列がある場合でも、呼び出しにCounterは1つのisinstance呼び出しのみが含まれ、その引数がマッピングであるかどうかを確認します。あなたはおそらく、あなたがいつも食べているものを誤って判断したのでしょう。
user2357112は2018

あなたは私が何を意味するのかを誤解しました:CounterはCounterを作成する前にデータのタイプをチェックします。これには比較的時間がかかり、データのタイプが事前にわかっている場合は、Counterのupdateメソッドを見ると、何かを行う前に3つのifステートメントを通過する必要があることがわかります。updateを頻繁に呼び出す場合、これはすぐに加算されます。データを制御でき、入力が実際に反復可能であることがわかっている場合は、最初の2つのチェックをスキップできます。私が言ったように、私は何百万ものアップデートを処理しているときにこれに気づいたので、それはエッジケースです。
Bram Vanroy、2018年

2
@BramVanroy:数百万の文字列を数えるだけでなく、数百万の更新を実行している場合、それは別の話です。の最適化作業でCounterは、多数の反復可能オブジェクトを数えるのではなく、大きな反復可能オブジェクトを数えるようになりました。100万文字列の反復可能オブジェクトを数えるCounterと、手動で実装するよりも速くなります。update多くのイテラブルで呼び出したい場合は、でイテラブルを1つに結合することで、速度を上げることができる場合がありますitertools.chain
user2357112は

262

リスト内の1つのアイテムの出現回数を数える

使用できるリストアイテムを1つだけカウントする場合 count()

>>> l = ["a","b","b"]
>>> l.count("a")
1
>>> l.count("b")
2

リスト内のすべてのアイテムの出現回数を数えることは、リストの「集計」、または集計カウンターの作成とも呼ばれます。

count()ですべてのアイテムを数える

アイテムの出現回数をカウントするにlは、リスト内包表記とcount()メソッドを使用するだけです。

[[x,l.count(x)] for x in set(l)]

(または辞書と同様にdict((x,l.count(x)) for x in set(l))

例:

>>> l = ["a","b","b"]
>>> [[x,l.count(x)] for x in set(l)]
[['a', 1], ['b', 2]]
>>> dict((x,l.count(x)) for x in set(l))
{'a': 1, 'b': 2}

Counter()ですべてのアイテムを数える

または、ライブラリのより高速なCounterクラスがありcollectionsます

Counter(l)

例:

>>> l = ["a","b","b"]
>>> from collections import Counter
>>> Counter(l)
Counter({'b': 2, 'a': 1})

カウンターはどれくらい速いですか?

Counterリストの集計がどれほど速いかを確認しました。私は両方の方法をいくつかの値で試してみましたが、約2の定数倍だけ高速であるnように見えますCounter

これが私が使用したスクリプトです:

from __future__ import print_function
import timeit

t1=timeit.Timer('Counter(l)', \
                'import random;import string;from collections import Counter;n=1000;l=[random.choice(string.ascii_letters) for x in range(n)]'
                )

t2=timeit.Timer('[[x,l.count(x)] for x in set(l)]',
                'import random;import string;n=1000;l=[random.choice(string.ascii_letters) for x in range(n)]'
                )

print("Counter(): ", t1.repeat(repeat=3,number=10000))
print("count():   ", t2.repeat(repeat=3,number=10000)

そして出力:

Counter():  [0.46062711701961234, 0.4022796869976446, 0.3974247490405105]
count():    [7.779430688009597, 7.962715800967999, 8.420845870045014]

32
Counterある方法より速く、より大きなリストのため。リスト内包表記法はO(n ^ 2)でCounterあり、O(n)でなければなりません。
fhucho 2015

20
カウンターは2倍高速ではありません。カウンターはn倍高速です(O(n ^ 2)vs O(n))。
Martijn Pieters

これをたくさん使用すると(何百万もの文字列について)、への呼び出しのために非常に遅くなることがわかりましたisinstance。したがって、操作しているデータについて確信がある場合は、型とインスタンスのチェックを行わずにカスタム関数を記述する方がよいでしょう。
Bram Vanroy

66

辞書で、各項目の発生数を取得する別の方法:

dict((i, a.count(i)) for i in a)

49
これは、私が戦闘で頻繁に思いつく構成の1つに似ていますが、len(a)回実行されます。これは、2次の実行時の複雑さを意味します(各実行は再びlen(a)に依存するため)。
Nicolas78 2012年

5
dict((i、a.count(i))for i(set(a))の方がより正確で高速でしょうか?
hugo24 2013

6
@ hugo24:少しですが、最悪の場合、漸近的に速くなることはありません。それがかかりますn * (number of different items)、それはセットを構築するのにかかる時間をカウントしない、動作を制御します。使用collections.Counterは本当にはるかに優れています。
クレメント2013年

パーティーに非常に遅れますが、リストにの複数のインスタンスが含まれている場合i、辞書に同じ値の複数のキーを入力しようとするため、次のコードはエラーをスローしません。 dict((i, a.count(i)) for i in a)
rp1


45

アイテムが与えられた場合、Pythonのリストでその出現回数をどのようにカウントできますか?

次にリストの例を示します。

>>> l = list('aaaaabbbbcccdde')
>>> l
['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'e']

list.count

list.count方法があります

>>> l.count('b')
4

これはどのリストでも問題なく機能します。タプルにもこのメソッドがあります:

>>> t = tuple('aabbbffffff')
>>> t
('a', 'a', 'b', 'b', 'b', 'f', 'f', 'f', 'f', 'f', 'f')
>>> t.count('f')
6

collections.Counter

そして、collections.Counterがあります。反復可能オブジェクトをリストだけでなく、カウンターにダンプできます。カウンターは、要素のカウントのデータ構造を保持します。

使用法:

>>> from collections import Counter
>>> c = Counter(l)
>>> c['b']
4

カウンターはPython辞書に基づいており、それらのキーは要素であるため、キーはハッシュ可能である必要があります。それらは基本的に、それらに冗長な要素を許可するセットのようなものです。

のさらなる使用 collections.Counter

カウンターからイテラブルを追加または減算できます。

>>> c.update(list('bbb'))
>>> c['b']
7
>>> c.subtract(list('bbb'))
>>> c['b']
4

また、カウンターを使用してマルチセット操作を行うこともできます。

>>> c2 = Counter(list('aabbxyz'))
>>> c - c2                   # set difference
Counter({'a': 3, 'c': 3, 'b': 2, 'd': 2, 'e': 1})
>>> c + c2                   # addition of all elements
Counter({'a': 7, 'b': 6, 'c': 3, 'd': 2, 'e': 1, 'y': 1, 'x': 1, 'z': 1})
>>> c | c2                   # set union
Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1, 'y': 1, 'x': 1, 'z': 1})
>>> c & c2                   # set intersection
Counter({'a': 2, 'b': 2})

なぜパンダではないのですか?

別の答えは示唆しています:

パンダを使ってみませんか?

パンダは一般的なライブラリですが、標準ライブラリにはありません。要件として追加するのは簡単ではありません。

リストオブジェクト自体と標準ライブラリには、このユースケースの組み込みソリューションがあります。

プロジェクトにまだパンダが必要ない場合、この機能だけを要件とするのはばかげています。


4
「なぜPandasではないのか」が適切ですが、「NumPyをいつ使用するか」、つまり大きな数値配列の場合はおそらくそれに伴うはずです。決定的な要素はプロジェクトの制限だけではなく、ビッグデータで明らかになるNumPyのメモリ効率があります。
1

深刻な依存関係としてPandasなどに言及していただきありがとうございます。これらのパッケージの一部には、マイナスの副作用があります。ささいなニーズにこれらの資産を追加すると、多くの時間と$がかかる可能性があります。個人的には、NumpyとSciPiがCIパイプラインに30分追加するのを経験しており、パッケージキャッシュを正しく取得するのに数日かかりました。素晴らしいパッケージですが、隠れた費用がかかることもあります。+1された
Marc、

36

私は提案されたすべてのソリューション(およびいくつかの新しいソリューション)をperfplot(私の小さなプロジェクト)と比較しました

1つのアイテムを数える

十分な大きさの配列の場合、

numpy.sum(numpy.array(a) == 1) 

他のソリューションよりもわずかに高速です。

ここに画像の説明を入力してください

すべてのアイテムを数える

以前確立されたように

numpy.bincount(a)

あなたが欲しいものです。

ここに画像の説明を入力してください


プロットを再現するコード:

from collections import Counter
from collections import defaultdict
import numpy
import operator
import pandas
import perfplot


def counter(a):
    return Counter(a)


def count(a):
    return dict((i, a.count(i)) for i in set(a))


def bincount(a):
    return numpy.bincount(a)


def pandas_value_counts(a):
    return pandas.Series(a).value_counts()


def occur_dict(a):
    d = {}
    for i in a:
        if i in d:
            d[i] = d[i]+1
        else:
            d[i] = 1
    return d


def count_unsorted_list_items(items):
    counts = defaultdict(int)
    for item in items:
        counts[item] += 1
    return dict(counts)


def operator_countof(a):
    return dict((i, operator.countOf(a, i)) for i in set(a))


perfplot.show(
    setup=lambda n: list(numpy.random.randint(0, 100, n)),
    n_range=[2**k for k in range(20)],
    kernels=[
        counter, count, bincount, pandas_value_counts, occur_dict,
        count_unsorted_list_items, operator_countof
        ],
    equality_check=None,
    logx=True,
    logy=True,
    )

2。

from collections import Counter
from collections import defaultdict
import numpy
import operator
import pandas
import perfplot


def counter(a):
    return Counter(a)


def count(a):
    return dict((i, a.count(i)) for i in set(a))


def bincount(a):
    return numpy.bincount(a)


def pandas_value_counts(a):
    return pandas.Series(a).value_counts()


def occur_dict(a):
    d = {}
    for i in a:
        if i in d:
            d[i] = d[i]+1
        else:
            d[i] = 1
    return d


def count_unsorted_list_items(items):
    counts = defaultdict(int)
    for item in items:
        counts[item] += 1
    return dict(counts)


def operator_countof(a):
    return dict((i, operator.countOf(a, i)) for i in set(a))


perfplot.show(
    setup=lambda n: list(numpy.random.randint(0, 100, n)),
    n_range=[2**k for k in range(20)],
    kernels=[
        counter, count, bincount, pandas_value_counts, occur_dict,
        count_unsorted_list_items, operator_countof
        ],
    equality_check=None,
    logx=True,
    logy=True,
    )

7
numpy.bincount()は、intアイテムを含むリストでのみ機能します。
Mukarram Pasha 2018

35

すべての値を一度カウントしたい場合はbincount、以下のようにnumpy配列を使用して非常に高速に行うことができます

import numpy as np
a = np.array([1, 2, 3, 4, 1, 4, 1])
np.bincount(a)

与える

>>> array([0, 3, 1, 1, 2])

19

あなたが使用できる場合はpandas、その後、value_counts救助のためにそこにあります。

>>> import pandas as pd
>>> a = [1, 2, 3, 4, 1, 4, 1]
>>> pd.Series(a).value_counts()
1    3
4    2
3    1
2    1
dtype: int64

また、頻度に基づいて結果を自動的にソートします。

結果をリストのリストにしたい場合は、以下のようにします

>>> pd.Series(a).value_counts().reset_index().values.tolist()
[[1, 3], [4, 2], [3, 1], [2, 1]]

ただし、パンダはオーバーヘッドが多いため、データ量が少ない場合は最も遅いソリューションです。 stackoverflow.com/a/46195192/125507
エンドリス

14

パンダを使用しないのはなぜですか?

import pandas as pd

l = ['a', 'b', 'c', 'd', 'a', 'd', 'a']

# converting the list to a Series and counting the values
my_count = pd.Series(l).value_counts()
my_count

出力:

a    3
d    2
b    1
c    1
dtype: int64

あなたが特定の要素の数を探しているなら、言って、試してみてください。

my_count['a']

出力:

3

13

今日私はこの問題を抱えていて、SOをチェックする前に自分の解決策を展開しました。この:

dict((i,a.count(i)) for i in a)

大きなリストでは本当に遅いです。私の解決策

def occurDict(items):
    d = {}
    for i in items:
        if i in d:
            d[i] = d[i]+1
        else:
            d[i] = 1
return d

少なくともPython 2.7では、実際にはCounterソリューションより少し高速です。


1
カウンターはエントリを
並べ替えますが、並べ

3
Python 2のカウンターは少し遅いです、はい。ただし、Python 3でカウントを行うためにCに最適化されたコードを使用し、ループを簡単に打ち負かします。
Martijn Pieters

12
# Python >= 2.6 (defaultdict) && < 2.7 (Counter, OrderedDict)
from collections import defaultdict
def count_unsorted_list_items(items):
    """
    :param items: iterable of hashable items to count
    :type items: iterable

    :returns: dict of counts like Py2.7 Counter
    :rtype: dict
    """
    counts = defaultdict(int)
    for item in items:
        counts[item] += 1
    return dict(counts)


# Python >= 2.2 (generators)
def count_sorted_list_items(items):
    """
    :param items: sorted iterable of items to count
    :type items: sorted iterable

    :returns: generator of (item, count) tuples
    :rtype: generator
    """
    if not items:
        return
    elif len(items) == 1:
        yield (items[0], 1)
        return
    prev_item = items[0]
    count = 1
    for item in items[1:]:
        if prev_item == item:
            count += 1
        else:
            yield (prev_item, count)
            count = 1
            prev_item = item
    yield (item, count)
    return


import unittest
class TestListCounters(unittest.TestCase):
    def test_count_unsorted_list_items(self):
        D = (
            ([], []),
            ([2], [(2,1)]),
            ([2,2], [(2,2)]),
            ([2,2,2,2,3,3,5,5], [(2,4), (3,2), (5,2)]),
            )
        for inp, exp_outp in D:
            counts = count_unsorted_list_items(inp) 
            print inp, exp_outp, counts
            self.assertEqual(counts, dict( exp_outp ))

        inp, exp_outp = UNSORTED_WIN = ([2,2,4,2], [(2,3), (4,1)])
        self.assertEqual(dict( exp_outp ), count_unsorted_list_items(inp) )


    def test_count_sorted_list_items(self):
        D = (
            ([], []),
            ([2], [(2,1)]),
            ([2,2], [(2,2)]),
            ([2,2,2,2,3,3,5,5], [(2,4), (3,2), (5,2)]),
            )
        for inp, exp_outp in D:
            counts = list( count_sorted_list_items(inp) )
            print inp, exp_outp, counts
            self.assertEqual(counts, exp_outp)

        inp, exp_outp = UNSORTED_FAIL = ([2,2,4,2], [(2,3), (4,1)])
        self.assertEqual(exp_outp, list( count_sorted_list_items(inp) ))
        # ... [(2,2), (4,1), (2,1)]

2
@plaes:どうやって?「エンタープライズ」とは、Py3kアノテーションの準備として「文書化」されていることを意味するのであれば、私も同感です。
ウェスターナー

1
私は主に2.7で開発しているので、これは良い例ですが、2.4への移行パスが必要です。
アダムルイス

9

以下は3つのソリューションです。

最速はforループを使用してそれをDictに格納することです。

import time
from collections import Counter


def countElement(a):
    g = {}
    for i in a:
        if i in g: 
            g[i] +=1
        else: 
            g[i] =1
    return g


z = [1,1,1,1,2,2,2,2,3,3,4,5,5,234,23,3,12,3,123,12,31,23,13,2,4,23,42,42,34,234,23,42,34,23,423,42,34,23,423,4,234,23,42,34,23,4,23,423,4,23,4]


#Solution 1 - Faster
st = time.monotonic()
for i in range(1000000):
    b = countElement(z)
et = time.monotonic()
print(b)
print('Simple for loop and storing it in dict - Duration: {}'.format(et - st))

#Solution 2 - Fast
st = time.monotonic()
for i in range(1000000):
    a = Counter(z)
et = time.monotonic()
print (a)
print('Using collections.Counter - Duration: {}'.format(et - st))

#Solution 3 - Slow
st = time.monotonic()
for i in range(1000000):
    g = dict([(i, z.count(i)) for i in set(z)])
et = time.monotonic()
print(g)
print('Using list comprehension - Duration: {}'.format(et - st))

結果

#Solution 1 - Faster
{1: 4, 2: 5, 3: 4, 4: 6, 5: 2, 234: 3, 23: 10, 12: 2, 123: 1, 31: 1, 13: 1, 42: 5, 34: 4, 423: 3}
Simple for loop and storing it in dict - Duration: 12.032000000000153
#Solution 2 - Fast
Counter({23: 10, 4: 6, 2: 5, 42: 5, 1: 4, 3: 4, 34: 4, 234: 3, 423: 3, 5: 2, 12: 2, 123: 1, 31: 1, 13: 1})
Using collections.Counter - Duration: 15.889999999999418
#Solution 3 - Slow
{1: 4, 2: 5, 3: 4, 4: 6, 5: 2, 34: 4, 423: 3, 234: 3, 42: 5, 12: 2, 13: 1, 23: 10, 123: 1, 31: 1}
Using list comprehension - Duration: 33.0

9

すべての要素の数 itertools.groupby()

リスト内のすべての要素の数を取得するための別の可能性は、 itertools.groupby()

「重複」カウントあり

from itertools import groupby

L = ['a', 'a', 'a', 't', 'q', 'a', 'd', 'a', 'd', 'c']  # Input list

counts = [(i, len(list(c))) for i,c in groupby(L)]      # Create value-count pairs as list of tuples 
print(counts)

戻り値

[('a', 3), ('t', 1), ('q', 1), ('a', 1), ('d', 1), ('a', 1), ('d', 1), ('c', 1)]

最初の3つaのを最初のグループとして組み合わせた方法に注目aしてください。他のグループはリストの下にあります。これは、入力リストLがソートされなかったために発生します。これは、グループを実際に分離する必要がある場合に利点になることがあります。

ユニークなカウント

一意のグループ数が必要な場合は、入力リストを並べ替えるだけです。

counts = [(i, len(list(c))) for i,c in groupby(sorted(L))]
print(counts)

戻り値

[('a', 5), ('c', 1), ('d', 2), ('q', 1), ('t', 1)]

注:一意のカウントを作成するために、他の多くの回答は、groupbyソリューションと比較してより簡単で読みやすいコードを提供します。ただし、ここでは、重複カウントの例に対応するものを示しています。


7

numpyのbincountを使用することが推奨されていましたが、ない整数を持つ1 次元配列に対してのみ機能します。また、結果の配列は混乱する可能性があります(元のリストのminからmaxまでの整数の出現が含まれ、欠落している整数を0に設定します)。

numpyでそれを行うより良い方法は、属性をTrueに設定して一意の関数を使用することreturn_countsです。一意の値の配列と各一意の値の発生の配列を含むタプルを返します。

# a = [1, 1, 0, 2, 1, 0, 3, 3]
a_uniq, counts = np.unique(a, return_counts=True)  # array([0, 1, 2, 3]), array([2, 3, 1, 2]

そして、次のようにペアリングできます

dict(zip(a_uniq, counts))  # {0: 2, 1: 3, 2: 1, 3: 2}

他のデータタイプや「2Dリスト」でも機能します。

>>> a = [['a', 'b', 'b', 'b'], ['a', 'c', 'c', 'a']]
>>> dict(zip(*np.unique(a, return_counts=True)))
{'a': 3, 'b': 3, 'c': 2}

6

共通のタイプを持つ多様な要素の数を数えるには:

li = ['A0','c5','A8','A2','A5','c2','A3','A9']

print sum(1 for el in li if el[0]=='A' and el[1] in '01234')

与える

3 6ではなく


4

とても古い質問ですが、ライナーが見つからなかったので作りました。

# original numbers in list
l = [1, 2, 2, 3, 3, 3, 4]

# empty dictionary to hold pair of number and its count
d = {}

# loop through all elements and store count
[ d.update( {i:d.get(i, 0)+1} ) for i in l ]

print(d)

副作用にリスト内包表記を使用しないでください。参照:副作用のみにリスト内包表記を使用するのはPythonicですか?
Georgy

3

countOf組み込みモジュールのメソッドを使用することもできますoperator

>>> import operator
>>> operator.countOf([1, 2, 3, 4, 1, 4, 1], 1)
3

1
どのようにcountOf実装されていますか?それはより明白なlist.count(C実装から利益を得る)とどのように比較しますか?何か利点はありますか?
Chris_Rands 2017年

2

最も効率的ではない可能性があり、重複を削除するには追加のパスが必要です。

機能の実装:

arr = np.array(['a','a','b','b','b','c'])
print(set(map(lambda x  : (x , list(arr).count(x)) , arr)))

戻り値 :

{('c', 1), ('b', 3), ('a', 2)}

またはとして返すdict

print(dict(map(lambda x  : (x , list(arr).count(x)) , arr)))

戻り値 :

{'b': 3, 'c': 1, 'a': 2}

1
sum([1 for elem in <yourlist> if elem==<your_value>])

これにより、your_valueの出現回数が返されます


1

私はを使用しfilter()、Lukaszの例をとります:

>>> lst = [1, 2, 3, 4, 1, 4, 1]
>>> len(filter(lambda x: x==1, lst))
3

0

特定の要素の数を必要とする場合:

>>> from collections import Counter
>>> z = ['blue', 'red', 'blue', 'yellow', 'blue', 'red']
>>> single_occurrences = Counter(z)
>>> print(single_occurrences.get("blue"))
3
>>> print(single_occurrences.values())
dict_values([3, 2, 1])

-1
def countfrequncyinarray(arr1):
    r=len(arr1)
    return {i:arr1.count(i) for i in range(1,r+1)}
arr1=[4,4,4,4]
a=countfrequncyinarray(arr1)
print(a)

3
このコードは質問に答えることがありますが、このコードが質問に答える理由や方法に関する追加のコンテキストを提供すると、長期的な価値が向上します。
Alex Riabov

-1
l2=[1,"feto",["feto",1,["feto"]],['feto',[1,2,3,['feto']]]]
count=0
 def Test(l):   
        global count 
        if len(l)==0:
             return count
        count=l.count("feto")
        for i in l:
             if type(i) is list:
                count+=Test(i)
        return count   
    print(Test(l2))

これは、リストのリスト内であっても、リスト内のアイテムを再帰的にカウントまたは検索します


一部の人が回答に反対票を投じただけで、それが完全に役立つ理由がわかりません
Mohamed Fathallah
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.