Подсчитайте общее количество слов в корпусе, используя условное распределение частот NLTK в Python (newb ie) - PullRequest
1 голос
/ 19 февраля 2020

Мне нужно посчитать количество слов (появлений слов) в некотором корпусе, используя пакет NLTK.

Вот мой корпус:

corpus = PlaintextCorpusReader('C:\DeCorpus', '.*')

Вот как я пытаюсь получить общее количество слов для каждого документа:

cfd_appr = nltk.ConditionalFreqDist(
    (textname, num_appr)
    for textname in corpus.fileids()
    for num_appr in [len(w) for w in corpus.raw(fileids=textname).replace("\r", " ").replace("\n", " ").split()])

(я разбиваю строки на слова вручную, так или иначе, это работает лучше, чем при использовании corpus.words(), но проблема остается той же, поэтому она не имеет значения). Как правило, это выполняет ту же (неправильную) работу:

cfd_appr = nltk.ConditionalFreqDist(
    (textname, num_appr)
    for textname in corpus.fileids()
    for num_appr in [len(w) for w in corpus.words(fileids=textname)])

Вот что я получаю, набрав cfd.appr.tabulate():

                        1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  
2022.12.06_Bild 2.txt   3  36 109  40  47  43  29  29  33  23  24  12   8   6   4   2   2   0   0   0   0   
2022.12.06_Bild 3.txt   2  42 129  59  57  46  46  35  22  24  17  21  13   5   6   6   2   2   2   0   0   
2022.12.06_Bild 4.txt   3  36 106  48  43  32  38  30  19  39  15  14  16   6   5   8   3   2   3   1   0   
2022.12.06_Bild 5.txt   1  55 162  83  68  72  46  24  34  38  27  16  12   8   8   5   9   3   1   5   1   
2022.12.06_Bild 6.txt   7  69 216  76 113  83  73  52  49  42  37  20  19   9   7   5   3   6   3   0   1   
2022.12.06_Bild 8.txt   0   2   0   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   

Но это количество слов разной длины. Мне нужно только это (только один тип элемента (текста) должен быть посчитан по количеству слов):

2022.12.06_Bild 2.txt    451.0
2022.12.06_Bild 3.txt    538.0
2022.12.06_Bild 4.txt    471.0
2022.12.06_Bild 5.txt    679.0
2022.12.06_Bild 6.txt    890.0
2022.12.06_Bild 8.txt      3.0
dtype: float64

Т.е. сумма всех слов разной длины (или сумма составленных столбцов) используя DataFrame(cfd_appr).transpose().sum(axis=1). (Кстати, если есть какой-то способ задать имя для этого столбца, это также решение, но .rename({None: 'W. appear.'}, axis='columns') не работает, и решение, как правило, будет недостаточно ясным.

Итак, мне нужно:

                             1    
2022.12.06_Bild 2.txt    451.0
2022.12.06_Bild 3.txt    538.0
2022.12.06_Bild 4.txt    471.0
2022.12.06_Bild 5.txt    679.0
2022.12.06_Bild 6.txt    890.0
2022.12.06_Bild 8.txt      3.0

Буду благодарен за помощь!

Ответы [ 2 ]

1 голос
/ 19 февраля 2020

Давайте сначала попробуем скопировать вашу таблицу с печально известной BookCorpus со структурой каталогов:

/books_in_sentences
   books_large_p1.txt
   books_large_p2.txt

В коде:

from nltk.corpus import PlaintextCorpusReader
from nltk import ConditionalFreqDist
from nltk import word_tokenize

from collections import Counter

import pandas as pd

corpus = PlaintextCorpusReader('books_in_sentences/', '.*')

cfd_appr = ConditionalFreqDist(
    (textname, num_appr)
    for textname in corpus.fileids()
    for num_appr in [len(w) for w in 
                     word_tokenize(corpus.raw(fileids=textname))])

Затем pandas munging part:

# Idiom to convert a FreqDist / ConditionalFreqDist into pd.DataFrame.
df = pd.DataFrame([dict(Counter(freqdist)) 
                   for freqdist in cfd_appr.values()], 
                 index=cfd_appr.keys())
# Fill in the not-applicable with zeros.
df = df.fillna(0).astype(int)

# If necessary, sort order of columns and add accordingly.
df = df.sort_values(list(df))

# Sum all columns per row -> pd.Series
counts_per_row = df.sum(axis=1)

Наконец, для доступа к индексированной серии, например:

print('books_large_p1.txt', counts_per_row['books_large_p1.txt'])

В качестве альтернативы

Я бы рекомендовал вышеуказанное решение, чтобы вы можете работать с DataFrame для дальнейшей обработки чисел, но если все, что вам нужно, это просто количество столбцов в строке, то попробуйте следующее.

Если необходимо избежать pandas и использовать значения в CFD напрямую, тогда вам придется использовать ConditionalFreqDist.values() и тщательно его перебирать.

Если мы сделаем:

>>> list(cfd_appr.values())
[FreqDist({3: 6, 6: 5, 1: 5, 9: 4, 4: 4, 2: 3, 8: 2, 10: 2, 7: 1, 14: 1}),
 FreqDist({4: 10, 3: 9, 1: 5, 7: 4, 2: 4, 5: 3, 6: 3, 11: 1, 9: 1})]

Мы увидим список FreqDist, каждый из которых соответствует ключам (в данном случае имена файлов):

>>> list(cfd_appr.keys())
['books_large_p1.txt', 'books_large_p2.txt']

Поскольку мы знаем, что FreqDist является подклассом коллекций. Объект-основатель , если мы суммируем значения каждого объекта Counter, мы получим:

>>> [sum(fd.values()) for fd in cfd_appr.values()]
[33, 40]

, который выводит те же значения, что и df.sum(axis=1) выше.

Итак, чтобы собрать это вместе:

>>> dict(zip(cfd_appr.keys(), [sum(fd.values()) for fd in cfd_appr.values()]))
{'books_large_p1.txt': 33, 'books_large_p2.txt': 40}
0 голосов
/ 20 февраля 2020

Ну, вот что на самом деле нужно было:

Сначала получите количество слов разной длины (как я делал раньше):

cfd_appr = nltk.ConditionalFreqDist(
    (textname, num_appr)
    for textname in corpus.fileids()
    for num_appr in [len(w) for w in corpus.raw(fileids=textname).replace("\r", " ").replace("\n", " ").split()])

Затем добавьте import DataFrame как pd и добавьте to_frame(1) к серии dtype: float64, которую я получил путем суммирования столбцов:

pd.DataFrame(cfd_appr).transpose().sum(axis=1).to_frame(1)

Вот и все. Однако, если кто-то знает, как их суммировать в определении cfd_appr, это было бы более элегантным решением.

...