Статьи

Как использовать Python для нахождения Zipf-распределения текстового файла

Вы можете быть удивлены термином Zipf . Чтобы понять, что мы подразумеваем под этим термином, нам нужно сначала определить закон Ципфа . Не волнуйся, я сделаю все просто.

Закон Ципфа просто гласит, что, учитывая некоторый корпус (большой и структурированный набор текстов) высказываний на естественном языке, встречаемость наиболее часто встречающегося слова будет примерно в два раза чаще, чем второе наиболее часто встречаемое слово, в три раза больше, чем третье наиболее часто употребляемое слово, четыре раза как четвертое по частоте слово и так далее.

Давайте посмотрим на пример этого. Если вы загляните в « Коричневый корпус» американского английского, вы заметите, что наиболее частое слово — это (69 971 вхождение). Если мы посмотрим на второе самое частое слово, то есть, мы заметим, что оно встречается 36 411 раз.

На это слово приходится около 7% слов Brown Corpus (69 971 из немногим более 1 миллиона слов). Если мы подойдем к слову о , мы заметим, что на его долю приходится около 3,6% корпуса (около половины). Таким образом, мы можем заметить, что закон Ципфа относится к этой ситуации.

Таким образом, закон Ципфа пытается сказать нам, что небольшое количество предметов обычно составляет основную часть действий, которые мы наблюдаем. Например, небольшое количество заболеваний (рак, сердечно-сосудистые заболевания) составляют основную часть смертей. Это также относится к словам, которые составляют основную часть всех вхождений слов в литературе, и многих других примеров в нашей жизни.

Прежде чем двигаться дальше, позвольте мне направить вас к данным, которые мы будем использовать для экспериментов в нашем руководстве. Наши данные на этот раз будут из Национальной медицинской библиотеки . Мы будем загружать отсюда файл ASCII MeSH (заголовок медицинской темы). В частности, d2016.bin (28 МБ).

Я не буду вдаваться в детали при описании этого файла, поскольку он выходит за рамки данного руководства, и нам просто нужно поэкспериментировать с нашим кодом.

После того, как вы загрузили данные в приведенном выше разделе, давайте теперь приступим к созданию нашего скрипта Python, который найдет распределение данных d2016.bin в d2016.bin .

Первый нормальный шаг — open файл:

1
open_file = open(‘d2016.bin’, ‘r’)

Чтобы выполнить необходимые операции над файлом bin , нам нужно загрузить файл в строковую переменную. Это может быть просто достигнуто с помощью функции read() следующим образом:

1
file_to_string = open_file.read()

Поскольку мы будем искать какой-то шаблон (то есть слова), в игру вступают регулярные выражения . Таким образом, мы будем использовать модуль re Python.

На данный момент мы уже прочитали файл bin и загрузили его содержимое в строковую переменную. Найти распределение Zipf означает найти частоту встречаемости слов в bin файле. Таким образом, регулярное выражение будет использоваться для поиска слов в файле.

Метод, который мы будем использовать для сопоставления, — это findall() . Как упомянуто в документации модуля re о findall() , метод будет:

Возвратите все неперекрывающиеся совпадения шаблона в строке в виде списка строк. Строка сканируется слева направо, и совпадения возвращаются в указанном порядке. Если в шаблоне присутствует одна или несколько групп, вернуть список групп; это будет список кортежей, если шаблон имеет более одной группы. Пустые совпадения включаются в результат, если они не касаются начала другого совпадения.

Мы хотим написать регулярное выражение, которое найдет все отдельные слова в текстовой строковой переменной. Регулярное выражение, которое может выполнить эту задачу:

1
\b[A-Za-z][az]{2,10}\b

где \b является якорем для границ слова . В Python это можно представить следующим образом:

1
words = re.findall(r'(\b[A-Za-z][az]{2,9}\b)’, file_to_string)

Это регулярное выражение в основном говорит нам найти все слова, которые начинаются с буквы (верхнего или нижнего регистра) и сопровождаются последовательностью букв, состоящей как минимум из 2 символов и не более 9 символов. Другими словами, размер слов, которые будут включены в вывод, будет варьироваться от 3 до 10 символов.

Теперь мы можем запустить цикл, который предназначен для вычисления частоты появления каждого слова:

1
2
3
for word in words:
   count = frequency.get(word,0)
   frequency[word] = count + 1

Здесь, если слово еще не найдено в списке слов, вместо KeyError , возвращается значение по умолчанию 0 . В противном случае, счетчик увеличивается на 1 , представляя количество случаев, когда слово встречалось в списке до сих пор.

Наконец, мы напечатаем пару ключ-значение в словаре , показывая слово (ключ) и количество раз, которое оно появилось в списке (значение):

1
2
for key, value in reversed(sorted(frequency.items(), key = itemgetter(1))):
   print key, value

Эта sorted(frequency.items(), key = itemgetter(1)) часть sorted(frequency.items(), key = itemgetter(1)) сортирует выходные данные по значению в порядке возрастания, то есть показывает слова от наименее частого вхождения до наиболее частого вхождения. Чтобы перечислить наиболее часто встречающиеся слова в начале, мы используем метод reversed() .

Пройдя через различные строительные блоки программы, давайте посмотрим, как все это выглядит вместе:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
import re
from operator import itemgetter
 
frequency = {}
open_file = open(‘d2016.bin’, ‘r’)
file_to_string = open_file.read()
words = re.findall(r'(\b[A-Za-z][az]{2,9}\b)’, file_to_string)
 
for word in words:
    count = frequency.get(word,0)
    frequency[word] = count + 1
     
for key, value in reversed(sorted(frequency.items(), key = itemgetter(1))):
    print key, value

Я покажу здесь первые десять слов и их частоты, возвращаемые программой:

01
02
03
04
05
06
07
08
09
10
the 42602
abcdef 31913
and 30699
abbcdef 27016
was 17430
see 16189
with 14380
under 13127
for 9767
abcdefv 8694

Из этого распределения Zipf мы можем проверить закон Zipf в том смысле, что некоторые слова (высокочастотные слова) представляют собой большую часть слов, как мы можем видеть выше and for . Это также относится к последовательностям abcdef , abbcdef и abcdefv которые являются очень частыми буквенными последовательностями, имеющими некоторое значение, характерное для этого файла.

В этом уроке мы увидели, как Python облегчает работу со статистическими понятиями, такими как закон Ципфа. Python особенно удобен при работе с большими текстовыми файлами, что потребует много времени и усилий, если мы найдем дистрибутив Zipf вручную. Как мы увидели, мы смогли быстро загрузить, проанализировать и найти распределение Zipf файла размером 28 МБ. Не говоря уже о простоте сортировки результатов благодаря словарям Python.