2014-05-27 2 views
0

Я пытаюсь создать классификатор настроений для твитов, используя классификатор MultinomialNB SciKit. У меня есть набор данных, содержащий 1,6 миллиона секретных твитов, которые я хочу использовать для обучения моего классификатора. Поскольку все это сразу занимает слишком много памяти, я пытаюсь сделать это с помощью partial_fit().Naive Bayes в SciKit-learn training with partial_fit breaks из-за разных размеров массива

linecounter = 0 
classifier = MultinomialNB() 
data_frame = DataFrame({'text': [], 'class': []}) 

# open csv file 
with open('training.cleaned.csv', 'rb') as csvfile: 

    # parse csv file 
    tweet_reader = csv.reader(csvfile, delimiter=',', quotechar='"') 

    #loop through each line 
    for tweet in tweet_reader: 
     data_frame = data_frame.append(DataFrame({'text': [tweet[TEXT].decode('utf8')], 'class': tweet[SENTIMENT]}, index=[tweet[ID]])) 
     linecounter += 1 

     if linecounter % 100 == 0:   
      count_vectorizer = CountVectorizer(ngram_range=([1, 2]))    
      counts = count_vectorizer.fit_transform(numpy.asarray(data_frame['text'], dtype="|S6"))   
      targets = numpy.asarray(data_frame['class'], dtype="|S6") 
      classifier.partial_fit(counts, targets, numpy.asarray(['negative', 'neutral', 'positive'])) 

Для каждых 100 (для этой проверки) линий я хочу обучить классификатор. Первый раунд идет хорошо, но второй раунд он выдает ошибку:

File "/Library/Python/2.7/site-packages/sklearn/naive_bayes.py", line 443, in _count self.feature_count_ += safe_sparse_dot(Y.T, X) 
ValueError: operands could not be broadcast together with shapes (3,147) (3,246) (3,147) 

Я знаю, что это вызвано CountVectorizer, потому что каждый из 100 твитов совершенно разные, векторизатор будет отличаться. Я не уверен, как я могу это решить ... Есть ли способ сделать несколько векторов одинакового размера? Или есть еще один умный трюк, который я мог бы использовать для частичной подготовки моего классификатора?

+1

Примечание: количество строк может быть получено более легко 'for linecounter, tweet in enumerate (tweet_reader)'. –

ответ

1

Есть два варианта я могу думать:

1) Используйте HashingVectorizer вместо CountVectorizer. Проблема с последним заключается в том, что он изучает словарный запас, когда вы вызываете fit, и он не поддерживает частичную установку (по уважительным причинам). Вы можете найти пример использования хеширующего векторизатора here. Это рекомендуемый метод использования, когда у вас действительно слишком много данных.

2) На мой взгляд, миллион твитов - это не так много данных, и вам, возможно, удастся избежать использования CountVectorizer. Ваш код делает много ненужных преобразований в массив numpy и кадр данных pandas, что вызывает проблемы с памятью. Если вы убережете это, вы сможете тренироваться за один раз (см. Ниже). Кроме того, хорошо подумайте, если вам действительно нужны функции bigram (ngram_range=(1, 2)) или просто униграммы (ngram_range=(1, 1)). Часто вы получаете небольшую точность, используя bigrams, но размерность матриц, которые вы должны удерживать в памяти, взрывается.

with open('training.cleaned.csv', 'rb') as csvfile: 
    tweet_reader = csv.reader(csvfile, delimiter=',', quotechar='"') 
    data = [tweet[TEXT].decode('utf8') for tweet in tweet_reader] 
    targets = [tweet['class'] for tweet in tweet_reader] 
count_vectorizer = CountVectorizer(ngram_range=(1, 1))   
counts = count_vectorizer.fit_transform(data)   
classifier = MultinomialNB()  
classifier.fit(counts, targets) 

В качестве альтернативы, вы можете вручную извлечь словарь заранее и передать его счетчику счетчика в качестве параметра конструктора. Затем вам нужно будет позвонить transform только один раз и не нужно будет звонить fit.

voc = set([word for tweet in tweet_reader for word in tweet[TEXT].decode('utf8')]) 
count_vectorizer = CountVectorizer(vocabulary=voc) 
with open('training.cleaned.csv', 'rb') as csvfile: 
    tweet_reader = csv.reader(csvfile, delimiter=',', quotechar='"') 
    data = [tweet[TEXT].decode('utf8') for tweet in tweet_reader]   
counts = count_vectorizer.transform(data) 
+0

Вау, большое вам спасибо. Я думал, что не могу подходить только к обычным спискам, но, по-видимому, я ошибся. Теперь код намного быстрее. – Chris

+0

Функция CountVectorizer требуется .fit() для вызова перед .transform(), даже если словарь передается конструктору. Я просто подтвердил это в версии 0.17. – Ansari

Смежные вопросы