2011-08-08 33 views
27

在Python最大出現的項目,我有一個列表:Python-發現列表中的

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

我想,以確定發生的次數最多的項目。我能夠解決它,但我需要最快的方式來做到這一點。我知道這是一個很好的Pythonic答案。

+4

你說你能夠解決它。如果你可以提供你自己的解決方案作爲起點,這對其他人也是有教育意義的。 –

回答

10

這裏是一個defaultdict解決方案,將與Python版本2.5及以上的工作:

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] 則有六個4S和六個7S。然而,結果將是(4, 6),即六個4。

+2

很小,但'itemgetter(1)'可能比'lambda x:x [1]'結構在簡單性和速度方面都更好。即請參閱http://docs.python.org/howto/sorting.html#operator-module-functions –

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

對於老版本的Python(< 2.7),你可以使用this receipe得到Counter類。

+1

有關詳細信息,請參閱[Counter docs](http://docs.python.org/dev/library/collections.html#collections.Counter)。 – SiggyF

+0

這個解決方案非常優雅,但目前,另一個爲我工作。 – zubinmehta

21

在你的問題中,你問最快的方法來做到這一點。正如一再被證明的那樣,特別是在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是好的,但你付出一點點爲它的方便;使用dictget的速度稍快。

如果列表大得多,會發生什麼?上面添加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'方法的成本和inplace add的損失可能會相加(對生成的代碼的檢查僅作爲練習)。

但是對於修改後的測試數據,唯一項目值的數量沒有變化,所以推測dictdefaultdict比其他實現具有優勢。那麼,如果我們使用更大的列表,但會大幅增加獨特項目的數量,會發生什麼?與更換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 

所以現在Counter明顯快於groupby解決方案,但仍比iteritems版本dictdefaultdict慢。

這些例子的重點不是產生最佳解決方案。重點是經常沒有一個最佳通用解決方案。另外還有其他性能標準。這些解決方案中的內存要求會有很大差異,並且隨着輸入大小的增加,內存需求可能成爲算法選擇的首要因素。底線:這一切都取決於你需要測量。

+0

這是一個夢幻般的答案,是任何解決方案的時間測試替代品的大量粉絲。謝謝Ned。 – Eugene

21

我很驚訝沒有人提到的最簡單的解決方案,max()用鑰匙list.count

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,但要注意它只返回最頻繁的項目,而不是頻率。而且,在繪製(即聯合最頻繁項目)的情況下,僅返回單個項目。

我找到max()辦法是約快兩倍,Counter.most_common(1)

from collections import Counter 
from timeit import timeit 

def f1(lst): 
    return max(lst, key = lst.count) 

def f2(lst): 
    return Counter(lst).most_common(1) 

lst = range(100000) 

timeit(lambda: f1(lst), number = 1000) 
# 28.13 
timeit(lambda: f2(lst), number = 1000) 
# 59.01 
+0

非常好,優化的解決方案 – kkk

+0

我想解釋一下max如何與'key ='一起工作, – Asara

0

我使用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 

Tes與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 __name__ == '__main__': 
    from timeit import timeit 
    print(timeit("occurrence()", setup = "from __main__ import occurrence", number = 20000)) 

輸出(最好的):

0.1893607140000313 
0

我想在另一個解決方案,看起來不錯,是快扔短的名單。

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

您可以基準本與斯內德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

以下是我提出的解決方案,如果字符串中有多個字符都具有最高的頻率。

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} 

occurence的最高頻率:3

字符是:

e 

l