CountVectorize словарная спецификация для биграмм Python - PullRequest
0 голосов
/ 03 июля 2018

Я пытаюсь получить разреженную матрицу подсчета сроков огромного (~ 160.000) количества документов.

Я очистил текст и хочу перебрать все документы (то есть посчитать векторизацию по одному за раз и добавить полученные массивы 1xN. Следующий код работает для случая слово за словом, но не для биграмм:

cv1 = sklearn.feature_extraction.text.CountVectorizer(stop_words=None,vocabulary=dictionary1)
cv2 = sklearn.feature_extraction.text.CountVectorizer(stop_words=None,vocabulary=dictionary2)

for row in range(start,end+1):
    report_name = fund_reports_table.loc[row, "report_names"]
    raw_report = open("F:/EDGAR_ShareholderReports/" + report_name, 'r', encoding="utf8").read()

    ## word for word
    temp = cv1.fit_transform([raw_report]).toarray()
    res1 = np.concatenate((res1,temp),axis=0)

    ## big grams
    bigram=set()
    sentences = raw_report.split(".")
    for line in sentences:
        token = nltk.word_tokenize(line)
        bigram = bigram.union(set(list(ngrams(token, 2)))  )

    temp = cv2.fit_transform(list(bigram)).toarray()
    res2=np.concatenate((res2,temp),axis=0)

Python возвращает

"AttributeError: 'tuple' object has no attribute 'lower'" 

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

"raw_report" - это строка. Словарь по одному слову:

dictionary1 =['word1', 'words2',...]

dictionary2 аналогичен, но основан на биграммах, построенных путем объединения всех биграмм всех документов (и сохранения уникальных значений, сделанных в предыдущем), так что результирующая структура будет

dictionary2 =[('word1','word2'),('wordn','wordm'),...]

Биграмма документа имеет такую ​​же структуру, поэтому я озадачен, почему python не примет ввод. Есть ли способ исправить это или весь мой подход не очень питоничен и начинает иметь неприятные последствия?

Заранее спасибо за любую помощь!

Примечание: я понимаю, что мог бы выполнить весь процесс более сложной командой CountVectorize (т. Е. Очисткой, токенизацией и подсчетом за один шаг), но я бы предпочел сделать это сам (для того, чтобы увидеть и сохранить). промежуточные выходы). Кроме того, я боюсь, что у меня проблемы с памятью из-за большого количества текста, который я использую.

1 Ответ

0 голосов
/ 03 июля 2018

Ваша проблема связана с тем, что ваш словарь2 основан на кортежах. Вот минималистский пример, который показывает, что это работает, когда биграммы являются строками. Если вы хотите обрабатывать каждый файл отдельно, вы можете передать его в vectorizer.transform () в виде списка.

from sklearn.feature_extraction.text import CountVectorizer

Doc1 = 'Wimbledon is one of the four Grand Slam tennis tournaments, the others being the Australian Open, the French Open and the US Open.'
Doc2 = 'Since the Australian Open shifted to hardcourt in 1988, Wimbledon is the only major still played on grass'
doc_set = [Doc1, Doc2]

my_vocabulary= ['Grand Slam', 'Australian Open', 'French Open', 'US Open']

vectorizer = CountVectorizer(ngram_range=(2, 2))
vectorizer.fit_transform(my_vocabulary)
term_count = vectorizer.transform(doc_set)

# Show the index key for each bigram
vectorizer.vocabulary_
Out[11]: {'grand slam': 2, 'australian open': 0, 'french open': 1, 'us open': 3}

# Sparse matrix of bigram counts - each row corresponds to a document
term_count.toarray()
Out[12]: 
array([[1, 1, 1, 1],
       [1, 0, 0, 0]], dtype=int64)

Вы можете использовать понимание списка, чтобы изменить свой словарь2.

dictionary2 = [('Grand', 'Slam'), ('Australian', 'Open'), ('French', 'Open'), ('US', 'Open')]
dictionary2 = [' '.join(tup) for tup in dictionary2]

dictionary2
Out[26]: ['Grand Slam', 'Australian Open', 'French Open', 'US Open']

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

from sklearn.feature_extraction.text import CountVectorizer

# Modify dictionary2 to be compatible with CountVectorizer
dictionary2_cv = [' '.join(tup) for tup in dictionary2]

# Initialize and train CountVectorizer
cv2 = CountVectorizer(ngram_range=(2, 2))
cv2.fit_transform(dictionary2_cv)

for row in range(start,end+1):
    report_name = fund_reports_table.loc[row, "report_names"]
    raw_report = open("F:/EDGAR_ShareholderReports/" + report_name, 'r', encoding="utf8").read()

    ## word for word
    temp = cv1.fit_transform([raw_report]).toarray()
    res1 = np.concatenate((res1,temp),axis=0)

    ## big grams
    bigram=set()
    sentences = raw_report.split(".")
    for line in sentences:
        token = nltk.word_tokenize(line)
        bigram = bigram.union(set(list(ngrams(token, 2)))  )

    # Modify bigram to be compatible with CountVectorizer
    bigram = [' '.join(tup) for tup in bigram]

    # Note you must not fit_transform here - only transform using the trained cv2
    temp = cv2.transform(list(bigram)).toarray()
    res2=np.concatenate((res2,temp),axis=0)
...