Программа подсчета частоты слов на Python варианты реализации
Различные подходы к реализации программы подсчета частоты слов
Эта статья посвящена одной программе на Python - подсчету частоты слов в тексте. Показаны различные варианты решения, от простого до более сложного, с пояснениями и разбором типичных ошибок.
Основной рекомендуемый подход
Данный вариант использует модуль collections.Counter, фильтрацию пунктуации и нормализацию регистра. Он наиболее сбалансирован по простоте и производительности.
import re
from collections import Counter
def word_frequency(text):
# удаляем пунктуацию, приводим к нижнему регистру
words = re.findall(r'\b\w+\b', text.lower())
return Counter(words)
text = "Python - это язык программирования. Python популярен!"
result = word_frequency(text)
print(result)1 программа на python (одна программа на python)
Counter({'python': 2, 'это': 1, 'язык': 1, 'программирования': 1, 'популярен': 1})Пояснение: re.findall(r'\b\w+\b', text.lower()) находит все последовательности букв и цифр (слова) в нижнем регистре, игнорируя знаки препинания. Затем Counter подсчитывает количество вхождений.
Типичные ошибки:
- Забыть про регистр - слова "Python" и "python" считаются разными. Решается вызовом
.lower(). - Использовать
str.split()без очистки пунктуации - слова с точкой или запятой будут отличны от чистых слов. Регулярное выражение решает эту проблему. - Для очень больших файлов чтение всего текста в память неэффективно - следует читать построчно (см. вариант с файлами).
Цель: получение быстрого и чистого результата для текстов среднего размера. Используется в анализе логов, обработке отзывов, подготовке данных для NLP.
Как реализовать ручной подсчет без Counter?
def word_frequency_manual(text):
frequency = {}
words = text.lower().split()
for word in words:
word = word.strip('.,!?;:"()[]{}')
if word:
frequency[word] = frequency.get(word, 0) + 1
return frequency
print(word_frequency_manual("Hello, hello! World.")){'hello': 2, 'world': 1}Пояснение: здесь вручную обрабатывается каждый элемент: приводится к нижнему регистру, удаляются знаки препинания, затем обновляется словарь.
Проблемы:
- Метод
strip()удаляет только символы с начала и конца строки, но не внутри (например, "don't" останется как "don't"). Если нужно разделить по всем небуквенным символам, лучше использовать регулярные выражения. - Высокая сложность при большом количестве символов пунктуации - нужно перечислять их все.
Цель: обучение основам работы со словарями и строками. Подходит для начинающих.
Как обработать текст из файла построчно для больших данных?
from collections import Counter
import re
def word_frequency_from_file(filename):
counter = Counter()
with open(filename, 'r', encoding='utf-8') as f:
for line in f:
words = re.findall(r'\b\w+\b', line.lower())
counter.update(words)
return counter
# Пример с файлом 'sample.txt'
result = word_frequency_from_file('sample.txt')
print(result.most_common(5))Пояснение: файл читается построчно, что позволяет обрабатывать даже гигабайтные файлы без загрузки в память целиком. counter.update() добавляет новые вхождения.
Ошибки:
- Забыть указать кодировку
encoding='utf-8'- получится ошибка UnicodeDecodeError при наличии нелатинских символов. - Не обработать пустые строки -
re.findallвернет пустой список, это безопасно.
Цель: работа с большими файлами (логи сервера, корпусы текстов).
Как добавить поддержку аргументов командной строки?
import argparse
import re
from collections import Counter
def main():
parser = argparse.ArgumentParser(description='Подсчет частоты слов')
parser.add_argument('file', help='путь к текстовому файлу')
parser.add_argument('-n', '--top', type=int, default=10, help='количество выводимых слов')
args = parser.parse_args()
with open(args.file, 'r', encoding='utf-8') as f:
counter = Counter()
for line in f:
words = re.findall(r'\b\w+\b', line.lower())
counter.update(words)
for word, count in counter.most_common(args.top):
print(f"{word}: {count}")
if __name__ == '__main__':
main()Пояснение: модуль argparse позволяет задавать имя файла и опцию --top из командной строки. Это делает программу пригодной для реального использования в конвейерах.
Проблемы:
- Если файл не существует, программа упадет с FileNotFoundError - требуется обработка исключений.
- При указании неверного ключа argparse выведет справку.
Цель: создание утилиты командной строки для автоматизации.
Как исключить стоп-слова (предлоги, союзы)?
import re
from collections import Counter
STOP_WORDS = {'и', 'в', 'на', 'с', 'по', 'для', 'а', 'но', 'да', 'или', 'не', 'так', 'что', 'как', 'это', 'то', 'все', 'она', 'его', 'их', 'мы', 'вы', 'у', 'о', 'об', 'от', 'из', 'за', 'до', 'без', 'над', 'под', 'при', 'через', 'около', 'после', 'во', 'ко', 'со', 'же', 'бы', 'ли', 'ни', 'чем', 'чтобы', 'потому', 'поэтому'}
def word_frequency_no_stop(text):
words = re.findall(r'\b\w+\b', text.lower())
return Counter(word for word in words if word not in STOP_WORDS)
print(word_frequency_no_stop("Python и Java - это языки программирования. Python популярен."))Counter({'python': 2, 'java': 1, 'языки': 1, 'программирования': 1, 'популярен': 1})Пояснение: стоп-слова отфильтровываются на лету с помощью генераторного выражения. Список стоп-слов можно загрузить из файла.
Замечание:
Стоп-слова зависят от языка и задачи. Иногда удаление предлогов ухудшает анализ (например, в поиске фраз).
Цель: очистка текста для последующего анализа (облако тегов, кластеризация).
Расширенные примеры и нестандартные решения
Помимо базовых вариантов, для одной программы на Python можно применять различные расширения. Ниже приведены несколько подробных примеров с кодом и результатами.
Использование регулярных выражений с захватом всех слов (включая апострофы)
import re
from collections import Counter
text = "don't can't "isn't" it's a cat's"
words = re.findall(r"\b[\w']+\b", text.lower())
print(Counter(words))Counter({"don't": 1, "can't": 1, "isn't": 1, "it's": 1, "a": 1, "cat's": 1})Пояснение: шаблон \b[\w']+\b позволяет включать апостроф в состав слова. Это полезно для обработки английского языка.
Подсчет биграмм (пар слов)
import re
from collections import Counter
def bigrams(text):
words = re.findall(r'\b\w+\b', text.lower())
return Counter(zip(words, words[1:]))
text = "Python это язык Python это инструмент"
result = bigrams(text)
for bigram, count in result.most_common():
print(f"{' '.join(bigram)}: {count}")python это: 2 это язык: 1 язык python: 1 это инструмент: 1
Пояснение: zip(words, words[1:]) создает пары последовательных слов. Counter подсчитывает количество каждой пары. Аналогично можно считать триграммы.
Вывод результата в порядке убывания с ранжированием
from collections import Counter
import re
text = "яблоко апельсин яблоко банан яблоко банан"
words = re.findall(r'\b\w+\b', text.lower())
counter = Counter(words)
sorted_words = counter.most_common()
for rank, (word, cnt) in enumerate(sorted_words, 1):
print(f"{rank}. {word}: {cnt}")1. яблоко: 3 2. банан: 2 3. апельсин: 1
Пояснение: метод most_common() возвращает список кортежей, отсортированных по убыванию частоты. Функция enumerate добавляет ранжирование.
Экспорт результата в CSV
import csv
import re
from collections import Counter
text = "кот собака кот мышь кот"
words = re.findall(r'\b\w+\b', text.lower())
counter = Counter(words)
with open('frequency.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(['Word', 'Frequency'])
writer.writerows(counter.most_common())
print("CSV файл создан")CSV файл создан
Содержимое frequency.csv:
Word,Frequency кот,2 собака,1 мышь,1
Пояснение: модуль csv упрощает запись таблицы. Данные можно открыть в Excel или Google Sheets.
Визуализация топ-10 слов с помощью matplotlib
import matplotlib.pyplot as plt
import re
from collections import Counter
text = "яблоко яблоко груша груша груша слива персик персик абрикос манго киви лимон лайм"
words = re.findall(r'\b\w+\b', text.lower())
top = Counter(words).most_common(10)
words_list = [pair[0] for pair in top]
counts = [pair[1] for pair in top]
plt.bar(words_list, counts)
plt.xlabel('Слова')
plt.ylabel('Частота')
plt.title('Топ-10 слов')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()Пояснение: график строится с помощью matplotlib. Перед запуском убедитесь, что библиотека установлена. Результат (описание) - появляется окно с гистограммой.