Ответ 1
Вид
from collections import defaultdict
fq= defaultdict( int )
for w in words:
fq[w] += 1
Это обычно работает хорошо.
Каков наилучший способ преобразования списка/кортежа в dict, где ключи являются отдельными значениями списка, а значениями являются частоты этих различных значений?
Другими словами:
['a', 'b', 'b', 'a', 'b', 'c']
-->
{'a': 2, 'b': 3, 'c': 1}
(Мне приходилось делать что-то подобное выше столько раз, есть ли что-нибудь в стандартной библиотеке, которая делает это для вас?)
EDIT:
Якоб Габриэльсон указывает на то, что что-то входит в стандартную lib для ветки 2.7/3.1
Вид
from collections import defaultdict
fq= defaultdict( int )
for w in words:
fq[w] += 1
Это обычно работает хорошо.
Я считаю, что проще всего понять (хотя и не самый эффективный) способ:
{i:words.count(i) for i in set(words)}
Просто обратите внимание, что, начиная с Python 2.7/3.1, эта функциональность будет встроена в модуль collections
, см. эту ошибку Чтобы получить больше информации. Вот пример из примечания к выпуску:
>>> from collections import Counter
>>> c=Counter()
>>> for letter in 'here is a sample of english text':
... c[letter] += 1
...
>>> c
Counter({' ': 6, 'e': 5, 's': 3, 'a': 2, 'i': 2, 'h': 2,
'l': 2, 't': 2, 'g': 1, 'f': 1, 'm': 1, 'o': 1, 'n': 1,
'p': 1, 'r': 1, 'x': 1})
>>> c['e']
5
>>> c['z']
0
Это мерзость, но:
from itertools import groupby
dict((k, len(list(xs))) for k, xs in groupby(sorted(items)))
Я не могу придумать причины, по которым этот метод следовал бы над С. Лоттом, но если кто-то будет указывать на это, это может быть и я.:)
На самом деле, ответ Counter уже упоминался, но мы можем сделать лучше (проще)!
from collections import Counter
my_list = ['a', 'b', 'b', 'a', 'b', 'c']
Counter(my_list) # returns a Counter, dict-like object
>> Counter({'b': 3, 'a': 2, 'c': 1})
Мне нужно поделиться интересным, но вроде нелепым способом сделать это, что я только что придумал:
>>> class myfreq(dict):
... def __init__(self, arr):
... for k in arr:
... self[k] = 1
... def __setitem__(self, k, v):
... dict.__setitem__(self, k, self.get(k, 0) + v)
...
>>> myfreq(['a', 'b', 'b', 'a', 'b', 'c'])
{'a': 2, 'c': 1, 'b': 3}
Я решил пойти дальше и протестировать предложенные версии, я обнаружил, что collections.Counter
, предложенный Джейкобом Габриэльсоном, был самым быстрым, а за ним последовала версия defaultdict
SLott.
Вот мои коды:
from collections import defaultdict
from collections import Counter
import random
# using default dict
def counter_default_dict(list):
count=defaultdict(int)
for i in list:
count[i]+=1
return count
# using normal dict
def counter_dict(list):
count={}
for i in list:
count.update({i:count.get(i,0)+1})
return count
# using count and dict
def counter_count(list):
count={i:list.count(i) for i in set(list)}
return count
# using count and dict
def counter_counter(list):
count = Counter(list)
return count
list=sorted([random.randint(0,250) for i in range(300)])
if __name__=='__main__':
from timeit import timeit
print("collections.Defaultdict ",timeit("counter_default_dict(list)", setup="from __main__ import counter_default_dict,list", number=1000))
print("Dict",timeit("counter_dict(list)",setup="from __main__ import counter_dict,list",number=1000))
print("list.count ",timeit("counter_count(list)", setup="from __main__ import counter_count,list", number=1000))
print("collections.Counter.count ",timeit("counter_counter(list)", setup="from __main__ import counter_counter,list", number=1000))
И мои результаты:
collections.Defaultdict
0.06787874956330614
Dict
0.15979115872995675
list.count
1.199258431219126
collections.Counter.count
0.025896202538920665
Дайте мне знать, как я могу улучшить анализ.
Я думаю, что использование библиотеки коллекций - это самый простой способ получить ее. Но если вы хотите получить частотный словарь, не используя его, то это другой способ,
l = [1,4,2,1,2,6,8,2,2]
d ={}
for i in l:
if i in d.keys():
d[i] = 1 + d[i]
else:
d[i] = 1
print (d)
оп:
{1: 2, 4: 1, 2: 4, 6: 1, 8: 1}