Oh Wow,textblob即使是合理数量的数据,它的默认设置也无法处理。
TL;DR:您确实需要更好地控制库的功能。
NaiveBayesClassifier类,或者更确切地说它的超类NLTKClassifier使用默认的 of feature_extractor。在这种情况下,它使用basic_extractor,除了以某种方式(与我们在这里无关)词干之外,它还执行以下操作:
features = dict(((u'contains({0})'.format(word), (word in tokens))
for word in word_features))
每个文件(样本)一次。
哎哟! 这将为每个文档创建一个 python 字典。并将每个文档的术语频率存储在这些字典中。在 16k 行(文档/样本)上,这很可能是太多的内存。
在 Ubuntu 上,您可能有交换空间,这是用作内存的额外磁盘空间,您的操作系统发现它内存不足,开始将内存页面交换到此交换空间。然而,如果与实际内存相比,交换空间非常慢,因此计算需要很长时间。最后,正是这种交换空间和这种缓慢性使算法永远运行,而不是使您的 CPU 过热或使机器完全冻结和内存不足。
解决问题的更好方法
ML 技术一般不理解单词或字符串,它们只理解数字。 textblob对您隐藏这个事实,因为它在幕后执行特征提取。这适用于玩具问题,但可能会损害任何更复杂问题的解决方案(可能是因为问题复杂性或数据量,或两者兼而有之)。
您需要自己控制特征提取。朴素贝叶斯分类器是一种相当简单的算法,可以很好地与多种提取技术配合使用。只要您不使用昂贵的 python 字典将频率保存在内存中,术语频率(简单地计算每个文档中每个不同单词的数量)就可以很好地工作。但是,一旦您控制了特征提取,就可以使用更多技术:TF-IDF、n-gram。我觉得sklearn对文本特征的解释很有启发性。但我离题了。
不幸的是, nltk(下面的库texblob)并没有让事情变得更容易。它要求其训练集具有字典接口。换句话说,如果没有大量的 hack,nltk就无法在大量数据上进行训练。
nltk选项1:直接挂钩
首先让我们假设您的文件已命名data.csv,我们将尝试提取逐行读取文件的特征。首先让我生成一个数据文件:
import nltk
nltk.download('gutenberg') # just in case
from nltk.corpus import gutenberg
corpus = gutenberg.words('melville-moby_dick.txt')
with open('data.csv', 'w') as f:
for i in range(10**4): # 10k
f.write(' '.join([w for w in corpus[i*3:i*3+3] if w != ','])
+ ',' + str(i%2) + '\n')
f.close()
这只是一些数据的生成,与手头的问题没有太大关系。我没有你的文件,所以我只是随机使用 Moby Dick 文本中的单词生成一个随机的 10k 行 CSV。
进入实际代码。我们仍将使用texblob's朴素贝叶斯,但不允许它构建庞大的字典列表。相反,我们将直接挂钩:
from textblob.classifiers import NaiveBayesClassifier
import csv
cls = NaiveBayesClassifier('')
class FeatureDict(object):
def __iter__(self):
with open('data.csv') as f:
for row in csv.reader(f):
yield {w: w for w in row[0].split()}, row[1]
cls.train_features = FeatureDict() # this is passed to nltk
cls.classify('bang Boom!')
这是一个 hack,但在不断的内存中运行。
选项2:切换到sklearn
sklearn的矢量化器将在(或在' 数据帧内NumPy的 NumPy 数组内)执行操作。pandas哪些是内存效率高的——尤其是与数千个 python 字典相比。
sklearn需要分两步执行此操作:一个用于数据矢量化,另一个用于预测 。make_pipeline加入步骤。假设data.csv我们可以做相同的数据准备:
from sklearn.feature_extraction.text import tfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import make_pipeline
import pandas as pd
data = pd.read_csv('data.csv', names=['doc', 'label'])
# some words are badly formatted, sklearn have issues with them
data = data.dropna()
model = make_pipeline(TfidfVectorizer(), MultinomialNB())
model.fit(data['doc'], data['label'])
model.predict(['buggy ho!'])
该sklearn解决方案稍微优雅一些,但可能会在某些时候耗尽内存(可能是 500k 样本)。在那种情况下,一个人需要破解sklearn自己才能在不断的记忆中做事。