web-dev-qa-db-ja.com

Python-リスト内で最大の出現回数を持つアイテムを見つける

Pythonには、リストがあります。

L = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]  

最も多く発生したアイテムを特定したい。私はそれを解決することができますが、そうするための最速の方法が必要です。これに対する素晴らしいPythonicの答えがあることを知っています。

49
zubinmehta

Pythonバージョン2.5以降で動作するdefaultdictソリューションは次のとおりです。

from collections import defaultdict

L = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67]
d = defaultdict(int)
for i in L:
    d[i] += 1
result = max(d.iteritems(), key=lambda x: x[1])
print result
# (4, 6)
# The number 4 occurs 6 times

L = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 7, 7, 7, 7, 7, 56, 6, 7, 67]その後、6つの4と6つの7があります。ただし、結果は(4, 6)すなわち6つの4。

14
Andrew Clark
from collections import Counter
most_common,num_most_common = Counter(L).most_common(1)[0] # 4, 6 times

古いPythonバージョン(<2.7)の場合、 this receipe を使用して Counter クラスを取得できます。

96
phihag

キー_list.count_を持つ最も簡単な解決策max()を誰も言及していないことに驚いています:

_max(lst,key=lst.count)
_

例:

_>>> lst = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]
>>> max(lst,key=lst.count)
4
_

これはPython 3または2で動作しますが、頻度ではなく最も頻度の高い項目のみを返すことに注意してください。また、drawの場合(つまり、最も頻繁に結合されるアイテム)単一のアイテムのみが返されます。

max()を使用する時間の複雑さは、 PM 2Ring コメントとしてCounter.most_common(1)を使用するよりも劣りますが、このアプローチはCの迅速な実装とこのアプローチは、短いリストの場合は最速ですが、大きなリストの場合は遅くなります(Python 3.6のタイミングはIPython 5.3に示されています)。

_In [1]: from collections import Counter
   ...: 
   ...: def f1(lst):
   ...:     return max(lst, key = lst.count)
   ...: 
   ...: def f2(lst):
   ...:     return Counter(lst).most_common(1)
   ...: 
   ...: lst0 = [1,2,3,4,3]
   ...: lst1 = lst0[:] * 100
   ...: 

In [2]: %timeit -n 10 f1(lst0)
10 loops, best of 3: 3.32 us per loop

In [3]: %timeit -n 10 f2(lst0)
10 loops, best of 3: 26 us per loop

In [4]: %timeit -n 10 f1(lst1)
10 loops, best of 3: 4.04 ms per loop

In [5]: %timeit -n 10 f2(lst1)
10 loops, best of 3: 75.6 us per loop
_
74
Chris_Rands

あなたの質問で、あなたはそれをする最も速い方法を求めました。特にPythonで繰り返し実証されているように、直感は信頼できるガイドではありません。測定する必要があります。

以下は、いくつかの異なる実装の簡単なテストです。

import sys
from collections import Counter, defaultdict
from itertools import groupby
from operator import itemgetter
from timeit import timeit

L = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67]

def max_occurrences_1a(seq=L):
    "dict iteritems"
    c = dict()
    for item in seq:
        c[item] = c.get(item, 0) + 1
    return max(c.iteritems(), key=itemgetter(1))

def max_occurrences_1b(seq=L):
    "dict items"
    c = dict()
    for item in seq:
        c[item] = c.get(item, 0) + 1
    return max(c.items(), key=itemgetter(1))

def max_occurrences_2(seq=L):
    "defaultdict iteritems"
    c = defaultdict(int)
    for item in seq:
        c[item] += 1
    return max(c.iteritems(), key=itemgetter(1))

def max_occurrences_3a(seq=L):
    "sort groupby generator expression"
    return max(((k, sum(1 for i in g)) for k, g in groupby(sorted(seq))), key=itemgetter(1))

def max_occurrences_3b(seq=L):
    "sort groupby list comprehension"
    return max([(k, sum(1 for i in g)) for k, g in groupby(sorted(seq))], key=itemgetter(1))

def max_occurrences_4(seq=L):
    "counter"
    return Counter(L).most_common(1)[0]

versions = [max_occurrences_1a, max_occurrences_1b, max_occurrences_2, max_occurrences_3a, max_occurrences_3b, max_occurrences_4]

print sys.version, "\n"

for vers in versions:
    print vers.__doc__, vers(), timeit(vers, number=20000)

私のマシンでの結果:

2.7.2 (v2.7.2:8527427914a2, Jun 11 2011, 15:22:34) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] 

dict iteritems (4, 6) 0.202214956284
dict items (4, 6) 0.208412885666
defaultdict iteritems (4, 6) 0.221301078796
sort groupby generator expression (4, 6) 0.383440971375
sort groupby list comprehension (4, 6) 0.402786016464
counter (4, 6) 0.564319133759

したがって、Counterソリューションは最速ではないようです。そして、少なくともこの場合、groupbyは高速です。 defaultdictは良いですが、その利便性のために少し料金を支払います。 dictで通常のgetを使用する方がわずかに高速です。

リストがもっと大きい場合はどうなりますか?上記のテストにL *= 10000を追加し、繰り返し回数を200に減らします:

dict iteritems (4, 60000) 10.3451900482
dict items (4, 60000) 10.2988479137
defaultdict iteritems (4, 60000) 5.52838587761
sort groupby generator expression (4, 60000) 11.9538850784
sort groupby list comprehension (4, 60000) 12.1327362061
counter (4, 60000) 14.7495789528

defaultdictが明確な勝者になりました。そのため、おそらく「get」メソッドのコストとインプレースアドの損失が加算されます(生成されたコードの検査は演習として残されます)。

ただし、変更されたテストデータでは、一意の項目値の数は変更されなかったため、dictおよびdefaultdictが他の実装よりも優れていると考えられます。それでは、より大きなリストを使用するが、一意のアイテムの数を大幅に増やすとどうなりますか? Lの初期化を次のように置き換えます。

LL = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67]
L = []
for i in xrange(1,10001):
    L.extend(l * i for l in LL)

dict iteritems (2520, 13) 17.9935798645
dict items (2520, 13) 21.8974409103
defaultdict iteritems (2520, 13) 16.8289561272
sort groupby generator expression (2520, 13) 33.853593111
sort groupby list comprehension (2520, 13) 36.1303369999
counter (2520, 13) 22.626899004

したがって、Countergroupbyソリューションよりも明らかに高速ですが、iteritemsおよびdictdefaultdictバージョンよりも依然として低速です。

これらの例のポイントは、最適なソリューションを作成することではありません。ポイントは、one最適な一般解が存在しないことが多いということです。さらに、他のパフォーマンス基準があります。メモリ要件はソリューション間で大幅に異なり、入力のサイズが大きくなると、メモリ要件がアルゴリズム選択の最優先要因になる場合があります。

結論:それはすべて依存しており、測定する必要があります。

27
Ned Deily

おそらく most_common() メソッド

2
Danny

Python 3.5.2:を使用して、この関数でgroupbyモジュールからitertoolsで最良の結果を得ました:

from itertools import groupby

a = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]

def occurrence():
    occurrence, num_times = 0, 0
    for key, values in groupby(a, lambda x : x):
        val = len(list(values))
        if val >= occurrence:
            occurrence, num_times =  key, val
    return occurrence, num_times

occurrence, num_times = occurrence()
print("%d occurred %d times which is the highest number of times" % (occurrence, num_times))

出力:

4 occurred 6 times which is the highest number of times

timeitモジュールのtimeitでテストします。

number= 20000を使用したテストにこのスクリプトを使用しました。

from itertools import groupby

def occurrence():
    a = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]
    occurrence, num_times = 0, 0
    for key, values in groupby(a, lambda x : x):
        val = len(list(values))
        if val >= occurrence:
            occurrence, num_times =  key, val
    return occurrence, num_times

if __== '__main__':
    from timeit import timeit
    print(timeit("occurrence()", setup = "from __main__ import occurrence",  number = 20000))

出力(最適なもの):

0.1893607140000313
1
Chiheb Nexus

ライブラリまたはセットなしの簡単な方法

def mcount(l):
  n = []                  #To store count of each elements
  for x in l:
      count = 0
      for i in range(len(l)):
          if x == l[i]:
              count+=1
      n.append(count)
  a = max(n)              #largest in counts list
  for i in range(len(n)):
      if n[i] == a:
          return(l[i],a)  #element,frequency
  return                  #if something goes wrong
1
Prashanth ram

私の(単純な)コード(Pythonを勉強する3か月):

def more_frequent_item(lst):
    new_lst = []
    times = 0
    for item in lst:
        count_num = lst.count(item)
        new_lst.append(count_num)
        times = max(new_lst)
    key = max(lst, key=lst.count)
    print("In the list: ")
    print(lst)
    print("The most frequent item is " + str(key) + ". Appears " + str(times) + " times in this list.")


more_frequent_item([1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67])

出力は次のようになります。

In the list: 
[1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]
The most frequent item is 4. Appears 6 times in this list.
0
Rentis

素敵に見え、shortリストに対して高速な別のソリューションを投入したいと思います。

def mc(seq=L):
    "max/count"
    max_element = max(seq, key=seq.count)
    return (max_element, seq.count(max_element))

Ned Deilyが提供するコードを使用して、これをベンチマークできます。これにより、最小のテストケースで以下の結果が得られます。

3.5.2 (default, Nov  7 2016, 11:31:36) 
[GCC 6.2.1 20160830] 

dict iteritems (4, 6) 0.2069783889998289
dict items (4, 6) 0.20462976200065896
defaultdict iteritems (4, 6) 0.2095775119996688
sort groupby generator expression (4, 6) 0.4473949929997616
sort groupby list comprehension (4, 6) 0.4367636879997008
counter (4, 6) 0.3618192010007988
max/count (4, 6) 0.20328268999946886

しかし、注意してください、それは非効率的であるため、本当にが大きなリストに対して遅くなります!

0
dd23

以下は、文字列に複数の文字がすべて最高頻度である場合に私が思いついた解決策です。

mystr = input("enter string: ")
#define dictionary to store characters and their frequencies
mydict = {}
#get the unique characters
unique_chars = sorted(set(mystr),key = mystr.index)
#store the characters and their respective frequencies in the dictionary
for c in unique_chars:
    ctr = 0
    for d in mystr:
        if d != " " and d == c:
            ctr = ctr + 1
    mydict[c] = ctr
print(mydict)
#store the maximum frequency
max_freq = max(mydict.values())
print("the highest frequency of occurence: ",max_freq)
#print all characters with highest frequency
print("the characters are:")
for k,v in mydict.items():
    if v == max_freq:
        print(k)

入力:「こんにちは人」

出力:

{'o': 2, 'p': 2, 'h': 1, ' ': 0, 'e': 3, 'l': 3}

発生頻度が最も高い:3

文字は次のとおりです。

e

l
0
Arko

シンプルで最高のコード:

def max_occ(lst,x):
    count=0
    for i in lst:
        if (i==x):
            count=count+1
    return count

lst=[1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]
x=max(lst,key=lst.count)
print(x,"occurs ",max_occ(lst,x),"times")

出力: 4は6回発生します

0
Ranjith M