【问题标题】:classify new document - Random Forest, Bag of Words分类新文档 - 随机森林,词袋
【发布时间】:2017-05-28 18:42:11
【问题描述】:

这是我第一次尝试使用 ML 和 Python 进行文档分类。

  1. 我首先查询我的数据库以提取 5000 篇与洗钱相关的文章并将它们转换为 pandas df
  2. 然后我提取了 500 篇与洗钱无关的文章,并将它们转换为 pandas df
  3. 我连接两个 dfs 并将它们标记为“洗钱”或“其他”
  4. 我进行预处理(删除标点符号和停用词、小写等)
  5. 然后根据词袋原理喂模型如下:

    vectorizer = CountVectorizer(analyzer = "word",   
                         tokenizer = None,    
                         preprocessor = None, 
                         stop_words = None,   
                         max_features = 5000) 
    
    text_features = vectorizer.fit_transform(full_df["processed full text"])    
    text_features = text_features.toarray()    
    labels = np.array(full_df['category'])
    X_train, X_test, y_train, y_test = train_test_split(text_features, labels, test_size=0.33)    
    forest = RandomForestClassifier(n_estimators = 100)     
    forest = forest.fit(X_train, y_train)    
    y_pred = forest.predict(X_test)    
    accuracy_score(y_pred=y_pred, y_true=y_test)
    

直到现在它都可以正常工作(尽管给我的准确率太高了 99%)。但我现在想在一个全新的文本文档上测试它。如果我对它进行矢量化并执行forest.predict(test),它显然会说:

ValueError: Number of features of the model must  match the input. Model n_features is 5000 and  input n_features is 45 

我不知道如何克服这个问题才能对全新的文章进行分类。

【问题讨论】:

  • vectorize 函数将文本语料库映射到(多维)空间中。您应该检查一下,但是从我的角度来看,由于映射函数是依赖于语料库的,因此可以预期,如果您添加一个不是来自初始文本语料库的新文本,则先前的映射对这个新文本没有微不足道的意义文本。这就是为什么在您的情况下,使用真正的新文本,代码不会运行。有 ML / 统计方法可以解决您的问题,但我认为这更像是一个统计挑战而不是编程问题。
  • 听起来您正在重新安装矢量化器。请记住,您在训练阶段适合矢量化器和分类器。在预测阶段,您只需在矢量化器上调用变换并在分类器上进行预测。
  • @probaPerception 你是对的,新文章应该适合模型。否则没有意义。

标签: python python-3.x scikit-learn nlp


【解决方案1】:

我的第一个朴素贝叶斯实现来自 Text Blob 库。它非常慢,我的机器最终内存不足。

第二次尝试是基于这篇文章http://zacstewart.com/2015/04/28/document-classification-with-scikit-learn.html 并使用了来自 sklearn.naive_bayes 库的 MultinomialNB。它的工作就像一个魅力:

#initialize vectorizer
count_vectorizer = CountVectorizer(analyzer = "word",   
                             tokenizer = None,    
                             preprocessor = None, 
                             stop_words = None,   
                             max_features = 5000)
counts = count_vectorizer.fit_transform(df['processed full text'].values)
targets = df['category'].values

#divide into train and test sets
X_train, X_test, y_train, y_test = train_test_split(counts, targets, test_size=0.33)

#create classifier
classifier = MultinomialNB()

classifier.fit(X_train, y_train)

#check accuracy
y_pred = classifier.predict(X_test)
accuracy_score(y_true=y_test, y_pred=y_pred)

#check on completely new example
new_counts = count_vectorizer.transform([processed_test_string])
prediction = classifier.predict(new_counts)
prediction

输出:

array(['money laundering'], 
      dtype='<U16')

准确率在 91% 左右,比 99.96% 更逼真..

正是我想要的。也很高兴看到最丰富的功能,我会努力解决的。谢谢大家。

【讨论】:

    【解决方案2】:

    首先,尽管我的提议可能有效,但我强烈强调,此解决方案具有一些统计和计算结果,您需要在运行此代码之前了解这些结果。 假设您有一个初始文本语料库 full_df["processed full text"]test 是您要测试的新文本。 然后,用full_dftest 定义文本语料库full_added

    text_features = vectorizer.fit_transform(full_added)    
    text_features = text_features.toarray()    
    

    您可以使用full_df 作为您的火车组(X_train = full_df["processed full text"]y_train = np.array(full_df['category']))。 然后你就可以运行了

    forest = RandomForestClassifier(n_estimators = 100)     
    forest = forest.fit(X_train, y_train)    
    y_pred = forest.predict(test)    
    

    当然,在这个解决方案中,您已经定义了参数,并且您认为您的模型在新数据上是稳健的。

    另外一点是,如果你有一个新的文本流作为你想要分析的输入,那么这个解决方案将会很糟糕,因为计算一个新的vectorizer.fit_transform(full_added) 的计算时间会急剧增加。

    我希望它有所帮助。

    【讨论】:

    • 谢谢。是的,这是有道理的。我也同意这不是最好的解决方案,因为每篇新文章都必须重新计算矩阵。我也尝试过 Native Bayes,但训练部分花费的时间太长,最终内存不足......
    猜你喜欢
    • 2016-05-25
    • 2018-05-18
    • 2019-09-05
    • 2013-09-22
    • 2018-02-18
    • 1970-01-01
    • 2014-03-08
    • 2018-07-15
    • 2020-02-08
    相关资源
    最近更新 更多