Моя задача - найти частоту каждого слова в списке. Есть два пути к этому.
Метод1
def f(words):
wdict = {}
for word in words:
if word not in wdict:
wdict[word] = 0
wdict[word] += 1
return wdict
Метод 2
def g(words):
wdict = {}
for word in words:
try:
wdict[word] += 1
except KeyError:
wdict[word] = 1
Почему метод 2 эффективен? Разве в обоих случаях количество вызовов хеш-функций не совпадает с этим http://blackecho.github.io/blog/programming/2016/03/23/python-underlying-data-structures.html?
есть много способов сделать это. Некоторые из них более эффективны, чем Method2. См. collections.defaultDict или даже лучше collections.Counter.
Ev.kounis. Мой вопрос в том, почему Method2 эффективнее Method1 в случае количества вызовов хеш-функции?
Просто проверьте это сами: gist.github.com/BrunoDesthuilliers/…






Смоделируем несколько случаев.
Пример: «Птица летит»
words = ["A", "bird", "is", "flying"]
В вашем первом методе:
для каждого слова он будет искать в словаре 3 раза, поэтому будет найдено всего 3 * len(words) или 3 * 4 = 12
Во втором способе: он будет искать только 2 раза, если не будет найден; иначе 1 раз: так 2 * 4 = 8
Теоретически оба имеют одинаковую временную сложность.
Обновлять:
Спасибо Тьерри Латюий за указание. Действительно, метод 1 должен быть более эффективным, чем метод 2. В словаре Python используется хэш-карта, поэтому доступ к ключевой сложности будет O (n), но в среднем случае это O (1). и реализация CPython довольно эффективна. С другой стороны, обработка исключений try / catch выполняется медленно.
вы можете использовать defaultdict в своем методе 1 для более чистого кода.
Нет, это не правильно. Доступ к ключу в dict или проверка того, существует ли он, составляют примерно O (1), поэтому оба метода примерно O (n). В вашем примере я получаю 1,36 мкс для метода 1 и 2 мкс для метода 2, что на самом деле намного медленнее. Причина в том, что обрабатывать исключения намного дороже, чем тесты, поэтому метод 1 начнет работать быстрее, только если будет много повторяющихся слов.
Это зависит от ввода. Если в среднем большинство слов уже находится в диктовке, вы не получите много исключений. Если большинство слов уникальны, то накладные расходы на исключения замедлят второй метод.
triplee, видишь это хоть раз: blackecho.github.io/blog/programming/2016/03/23/…
Я быстро посмотрел, но не вижу, на какую реакцию вы надеетесь. Многие случайные блоги рады предоставить неполные или сомнительные советы по программированию.
В блоге говорится, что количество вызовов функций в методе 1 больше, чем в методе 2. Я не могу его переварить. Мне кажется, что количество вызовов функций в обоих случаях одинаково.
В нем говорится, что он выполняет много ненужных вычислений функции хэш, но это похоже на ложное утверждение. Почему это комментарий к моему ответу, а не, например, новый вопрос или комментарий автору блога?
@SheikhArbaz, вы можете проверить правильность утверждения этого сообщения в блоге, настроив быстрый и простой тест вроде этого: gist.github.com/BrunoDesthuilliers/… - как вы узнаете, на достаточно длинном реальном тексте (с большим количеством разных слов) проверка на содержание выполняется значительно быстрее (в 2 раза в Python 3.6 и в четыре в Python 2.7). Для фиктивного текста, в котором одни и те же три слова повторяются снова и снова.
Есть несколько подходов к этому ответу. Вы можете использовать цикл и при этом получить ожидаемый ответ. Я сосредотачиваюсь на двух методах:
Понимание списка
wordstring = 'it was the best of times it was the worst of times '
wordstring += 'it was the age of wisdom it was the age of foolishness'
wordlist = wordstring.split()
# Count each word
wordfreq = [wordlist.count(w) for w in wordlist] # a list comprehension
# Convert to set to remove repetitions
frequencies=set(zip(wordlist, wordfreq))
print(frequencies)
Вывод:
{('of', 4), ('best', 1), ('the', 4), ('worst', 1), ('age', 2), ('wisdom', 1), ('it', 4), ('was', 4), ('times', 2), ('foolishness', 1)}
Метод второй: стандартная библиотека
import collections
wordstring = 'it was the best of times it was the worst of times '
wordstring += 'it was the age of wisdom it was the age of foolishness'
wordlist = wordstring.split()
# Count frequency
freq=collections.Counter(wordlist)
print(freq)
Вывод:
Counter({'it': 4, 'was': 4, 'the': 4, 'of': 4, 'times': 2, 'age': 2, 'best': 1, 'worst': 1, 'wisdom': 1, 'foolishness': 1})
Выбор метода зависит от размера текста, с которым вы работаете. Приведенные выше методы подходят для текста небольшого размера.
это "понимание списка", а не "сжатие списка";) (исправлено).
Должно быть сжатие списка в python, а не понимание
Пожалуйста, проверьте свои факты: docs.python.org/3/tutorial/…
Не связано, но ваше первое решение будет работать лучше, если сначала наберет набор слов и только потом будет их подсчитывать, то есть: frequencies = [(word, wordlist.count(word)) for word in set(wordlist)]
Конечно, я хотел, чтобы это было просто.
Есть два основных отличия:
in для каждого слова, а метод 2 будет обновлять напрямую, когда это возможно.В конечном итоге это зависит от ввода, но если будет достаточное количество повторений, будет меньше операций.
Пример:
Давайте просто рассмотрим код здесь, чтобы получить общее представление (а не фактические операции).
['a', 'a']
Метод1
1 - 'а' не в wdict - True
2 - присвоить 'a'
3 - обновить 'a'
4 - 'a' не в слове - False
5 - обновить 'а'
Метод 2
1 - доступ 'a'
2 - ошибка
3 - присвоить "a" непосредственно 1
4 - обновить 'а' (второй 'а')
Хотя эти шаги не совсем соответствуют количеству операций, выполняемых при выполнении, они указывают на то, что Method2 более компактный и проходит меньше «шагов».
Наиболее эффективным, вероятно, является
Counterиз стандартной библиотеки:from collections import Counter; c = Counter(words).