Создание TfidfVectorizer над текстовым столбцом огромного фрейма данных pandas

Мне нужно получить матрицу функций TF-IDF из текста, хранящегося в столбцах огромного dataframe, загруженный из файла CSV (который не помещается в памяти). Я пытаюсь перебрать фрейм данных, используя куски, но он возвращает объекты генератора, которые не являются ожидаемым типом переменной для метода TfidfVectorizer. Думаю, я делаю что-то не так при написании метода генератора ChunkIterator, показанного ниже.

import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer


#Will work only for small Dataset
csvfilename = 'data_elements.csv'
df = pd.read_csv(csvfilename)
vectorizer = TfidfVectorizer()
corpus  = df['text_column'].values
vectorizer.fit_transform(corpus)
print(vectorizer.get_feature_names())



#Trying to use a generator to parse over a huge dataframe
def ChunkIterator(filename):
    for chunk in pd.read_csv(csvfilename, chunksize=1):
       yield chunk['text_column'].values

corpus  = ChunkIterator(csvfilename)
vectorizer.fit_transform(corpus)
print(vectorizer.get_feature_names())

Кто-нибудь может посоветовать, как изменить метод ChunkIterator, указанный выше, или любой другой подход, используя фрейм данных. Я бы не хотел создавать отдельные текстовые файлы для каждой строки в фрейм данных. Ниже приведены некоторые фиктивные данные файла CSV для воссоздания сценария.

id,text_column,tags
001, This is the first document .,['sports','entertainment']
002, This document is the second document .,"['politics', 'asia']"
003, And this is the third one .,['europe','nato']
004, Is this the first document ?,"['sports', 'soccer']"

person oldmonk    schedule 13.12.2018    source источник


Ответы (1)


Метод отлично принимает генераторы. Но для этого требуется итерация необработанных документов, то есть строк. Ваш генератор - это итерация объектов numpy.ndarray. Так что попробуйте что-нибудь вроде:

def ChunkIterator(filename):
    for chunk in pd.read_csv(csvfilename, chunksize=1):
        for document in chunk['text_column'].values:
            yield document

Заметьте, я действительно не понимаю, почему вы здесь используете панд. Просто используйте обычный модуль csv, например:

import csv
def doc_generator(filepath, textcol=0, skipheader=True):
    with open(filepath) as f:
        reader = csv.reader(f)
        if skipheader:
            next(reader, None)
        for row in reader:
            yield row[textcol]

Итак, в вашем случае передайте 1 в textcol, например:

In [1]: from sklearn.feature_extraction.text import TfidfVectorizer

In [2]: import csv
   ...: def doc_generator(filepath, textcol=0, skipheader=True):
   ...:     with open(filepath) as f:
   ...:         reader = csv.reader(f)
   ...:         if skipheader:
   ...:             next(reader, None)
   ...:         for row in reader:
   ...:             yield row[textcol]
   ...:

In [3]: vectorizer = TfidfVectorizer()

In [4]: result = vectorizer.fit_transform(doc_generator('testing.csv', textcol=1))

In [5]: result
Out[5]:
<4x9 sparse matrix of type '<class 'numpy.float64'>'
    with 21 stored elements in Compressed Sparse Row format>

In [6]: result.todense()
Out[6]:
matrix([[ 0.        ,  0.46979139,  0.58028582,  0.38408524,  0.        ,
          0.        ,  0.38408524,  0.        ,  0.38408524],
        [ 0.        ,  0.6876236 ,  0.        ,  0.28108867,  0.        ,
          0.53864762,  0.28108867,  0.        ,  0.28108867],
        [ 0.51184851,  0.        ,  0.        ,  0.26710379,  0.51184851,
          0.        ,  0.26710379,  0.51184851,  0.26710379],
        [ 0.        ,  0.46979139,  0.58028582,  0.38408524,  0.        ,
          0.        ,  0.38408524,  0.        ,  0.38408524]])
person juanpa.arrivillaga    schedule 13.12.2018
comment
Спасибо @ juanpa.arrivillaga за предложение альтернативы. Я думал о том же. Полагаю, я был зациклен на фреймах данных из-за незнания генераторов. Я попробую оба и выберу тот, который работает быстрее. - person oldmonk; 13.12.2018
comment
@ juanpa.arrivillaga Спасибо за ваш ответ, это определенно полезно! Кажется, я могу получить все, кроме последнего шага. Когда я запускаю result.todense (), я получаю ошибку памяти. На самом деле, я хочу получить результат в виде фрейма данных pandas, и код, который я использовал для этого в прошлом: pd.DataFrame (result.toarray (), columns = vectorizer.get_feature_names ()), но он тоже получает мне MemoryError. Ты знаешь почему? Как я могу исправить это, чтобы получить мой фрейм данных pandas без MemoryError? Спасибо! - person bernando_vialli; 24.12.2018
comment
@mkheifetz ну, наверное, потому что у вас недостаточно памяти для создания из нее плотной структуры данных. Почему бы вам просто не использовать разреженное представление? - person juanpa.arrivillaga; 25.12.2018
comment
@ juanpa.arrivilagga, а как ты это делаешь? - person bernando_vialli; 25.12.2018
comment
@mkeifetz это то, что у вас уже было до звонка .todense - person juanpa.arrivillaga; 25.12.2018
comment
@ juanpa.arrivillaga, что здесь должно быть на выходе, когда я это сделаю: doc_generator (имя файла)? Я сейчас по какой-то причине получаю ‹объект-генератор doc_generator по адресу 0x0 ... и т. Д.? По какой-то причине после запуска вашего кода до .todense я получаю ValueError: emplty dictionary; возможно, документы содержат только стоп-слова - person bernando_vialli; 02.01.2019
comment
@mkheifetz это генератор. Это то, что он всегда возвращал. см. stackoverflow.com/questions/1756096/ - person juanpa.arrivillaga; 02.01.2019
comment
@ juanpa.arrivillaga Я попробовал тот же код, что и вы, для обучения векторизатора tfidf, но с биграммами все равно получаю ошибку памяти. Потребление памяти продолжает расти, и, наконец, я получаю ошибку памяти во время процесса настройки векторизатора. Есть идеи? - person Mohsin Ashraf; 18.02.2020