用户警告:您的停用词可能与您的预处理不一致。

20

我正在按照这个文档聚类教程进行操作。我提供了一个txt文件作为输入,可以在这里下载。它是三个其他txt文件的组合,使用\n分割。在创建tf-idf矩阵后,我收到了以下警告:

,,UserWarning: Your stop_words may be inconsistent with your preprocessing. 
Tokenizing the stop words generated tokens ['abov', 'afterward', 'alon', 'alreadi', 'alway', 'ani', 'anoth', 'anyon', 'anyth', 'anywher', 'becam', 'becaus', 'becom', 'befor', 'besid', 'cri', 'describ', 'dure', 'els', 'elsewher', 'empti', 'everi', 'everyon', 'everyth', 'everywher', 'fifti', 'forti', 'henc', 'hereaft', 'herebi', 'howev', 'hundr', 'inde', 'mani', 'meanwhil', 'moreov', 'nobodi', 'noon', 'noth', 'nowher', 'onc', 'onli', 'otherwis', 'ourselv', 'perhap', 'pleas', 'sever', 'sinc', 'sincer', 'sixti', 'someon', 'someth', 'sometim', 'somewher', 'themselv', 'thenc', 'thereaft', 'therebi', 'therefor', 'togeth', 'twelv', 'twenti', 'veri', 'whatev', 'whenc', 'whenev', 'wherea', 'whereaft', 'wherebi', 'wherev', 'whi', 'yourselv'] not in stop_words.
  'stop_words.' % sorted(inconsistent))". 

我猜这可能与词形还原和停用词的顺序有关,但由于这是我在文本处理方面的第一个项目,我有点困惑,不知道该如何解决这个问题...

import pandas as pd
import nltk
from nltk.corpus import stopwords
import re
import os
import codecs
from sklearn import feature_extraction
import mpld3
from nltk.stem.snowball import SnowballStemmer
from sklearn.feature_extraction.text import TfidfVectorizer


stopwords = stopwords.words('english')
stemmer = SnowballStemmer("english")

def tokenize_and_stem(text):
    # first tokenize by sentence, then by word to ensure that punctuation is caught as it's own token
    tokens = [word for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent)]
    filtered_tokens = []
    # filter out any tokens not containing letters (e.g., numeric tokens, raw punctuation)
    for token in tokens:
        if re.search('[a-zA-Z]', token):
            filtered_tokens.append(token)
    stems = [stemmer.stem(t) for t in filtered_tokens]
    return stems


def tokenize_only(text):
    # first tokenize by sentence, then by word to ensure that punctuation is caught as it's own token
    tokens = [word.lower() for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent)]
    filtered_tokens = []
    # filter out any tokens not containing letters (e.g., numeric tokens, raw punctuation)
    for token in tokens:
        if re.search('[a-zA-Z]', token):
            filtered_tokens.append(token)
    return filtered_tokens


totalvocab_stemmed = []
totalvocab_tokenized = []
with open('shortResultList.txt', encoding="utf8") as synopses:
    for i in synopses:
        allwords_stemmed = tokenize_and_stem(i)  # for each item in 'synopses', tokenize/stem
        totalvocab_stemmed.extend(allwords_stemmed)  # extend the 'totalvocab_stemmed' list
        allwords_tokenized = tokenize_only(i)
        totalvocab_tokenized.extend(allwords_tokenized)

vocab_frame = pd.DataFrame({'words': totalvocab_tokenized}, index = totalvocab_stemmed)
print ('there are ' + str(vocab_frame.shape[0]) + ' items in vocab_frame')
print (vocab_frame.head())

#define vectorizer parameters
tfidf_vectorizer = TfidfVectorizer(max_df=0.8, max_features=200000,
                                 min_df=0.2, stop_words='english',
                                 use_idf=True, tokenizer=tokenize_and_stem, ngram_range=(1,3))

with open('shortResultList.txt', encoding="utf8") as synopses:
    tfidf_matrix = tfidf_vectorizer.fit_transform(synopses) #fit the vectorizer to synopses

print(tfidf_matrix.shape)

你有检查过这里或者这里吗? - BringBackCommodore64
您的链接显示上传不存在。 - Starbucks
4个回答

28
警告信息提示您,如果文本中包含“always”,它将在匹配停用词列表时被规范化为“alway”。因此,它不会从单词集中删除,而该停用词列表包括“always”但不包括“alway”。
解决方法是确保预处理您的停用词列表,以确保其像标记一样被规范化,并将已规范化的单词列表作为“stop_words”传递给向量化器。

2
说实话,这是一项非常烦人的任务。如果我将“please”定义为停用词,向量化器会抱怨,因为它被分词为“pleas”。如果我传递“pleas”(即已分词的停用词),向量化器会抱怨,因为它被分词为“plea”。 - MERose
1
@MERose,我仍然不确定处理这个问题的最佳方法是什么。不同的软件包具有不同的停用词列表和标记化/词形还原方法。有一种解决方法,可以使用或不使用停用词列表,即基于语料库的停用词。您可以通过CountVectorizer()TfidfVectorizer()中的max_dfmin_df来控制此内容。在此处查看stop_words - andreassot10
为了对停用词进行分词处理:tokenizer = TfidfVectorizer().build_tokenizer(),然后 my_stop_words = sum([tokenizer(stop_word) for stop_word in my_stop_words], []) - Alaa M.

7
我有同样的问题,以下方法对我起效:
  1. tokenize 函数中加入 stopwords,然后
  2. tfidfVectorizer 中删除 stopwords 参数。
像这样:

1.

stopwords = stopwords.words('english')
stemmer = SnowballStemmer("english")

def tokenize_and_stem(text):
    tokens = [word for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent)]
    filtered_tokens = []
    for token in tokens:
        if re.search('[a-zA-Z]', token):
            filtered_tokens.append(token)

    #exclude stopwords from stemmed words
    stems = [stemmer.stem(t) for t in filtered_tokens if t not in stopwords]

    return stems
  1. 从向量化器中删除 stopwords 参数:
tfidf_vectorizer = TfidfVectorizer(
    max_df=0.8, max_features=200000, min_df=0.2,
    use_idf=True, tokenizer=tokenize_and_stem, ngram_range=(1,3)
)

我测试了你的代码,但说实话它并不是很好。它将“Khadse”视为“khads”。 - edusanketdk
1
@edusanketdk,我的代码提供了一个很好的解决方案来回答问题。你所描述的问题是一个不同的问题,而不是由于我的代码,而主要是由于库的功能。请注意,我的答案明确针对“英语”作为一种语言,并且“Khadse”不是英语单词。 - Suki
确实。但是数据中总会包含英语词汇表中没有的名词和名称。因此,我们期望创建一个强大的模型,不会像那样失败。另外,我理解这是库的问题,所以我们不应该使用它们,或者至少进行一些优化。对吧? - edusanketdk
@edusanketdk 在这种情况下,您可以手动扩展停用词列表以包括常见的非英语单词。据我所见,nltk库仍然是最广泛使用且最有效的库之一。如果您知道其他更好的库,请随时添加另一个答案。 - Suki
我认为代码中有一个错别字。在第一段代码片段中,应该是:stems = [stemmer.stem(t) for t in filtered_tokens if t not in stopwords] - Gaspar Avit Ferrero
1
@GasparAvitFerrero 是的,我认为你可能是对的,发现得很好。 - Suki

4

我遇到这个问题是因为我的语言设置为PT-BR。

简而言之:删除你的语言中的重音符号。

# Special thanks for the user Humberto Diogenes from Python List (answer from Aug 11, 2008)
# Link: http://python.6.x6.nabble.com/O-jeito-mais-rapido-de-remover-acentos-de-uma-string-td2041508.html

# I found the issue by chance (I swear, haha) but this guy gave the tip before me
# Link: https://github.com/scikit-learn/scikit-learn/issues/12897#issuecomment-518644215

import spacy
nlp = spacy.load('pt_core_news_sm')

# Define default stopwords list
stoplist = spacy.lang.pt.stop_words.STOP_WORDS

def replace_ptbr_char_by_word(word):
  """ Will remove the encode token by token"""
    word = str(word)
    word = normalize('NFKD', word).encode('ASCII','ignore').decode('ASCII')
    return word

def remove_pt_br_char_by_text(text):
  """ Will remove the encode using the entire text"""
    text = str(text)
    text = " ".join(replace_ptbr_char_by_word(word) for word in text.split() if word not in stoplist)
    return text

df['text'] = df['text'].apply(remove_pt_br_char_by_text)

我在这个代码片段中提供了解决方案和参考资料。


0

手动将这些单词添加到“stop_words”列表中可以解决问题。

stop_words = safe_get_stop_words('en')
stop_words.extend(['abov', 'afterward', 'alon', 'alreadi', 'alway', 'ani', 'anoth', 'anyon', 'anyth', 'anywher', 'becam', 'becaus', 'becom', 'befor', 'besid', 'cri', 'describ', 'dure', 'els', 'elsewher', 'empti', 'everi', 'everyon', 'everyth', 'everywher', 'fifti', 'forti', 'henc', 'hereaft', 'herebi', 'howev', 'hundr', 'inde', 'mani', 'meanwhil', 'moreov', 'nobodi', 'noon', 'noth', 'nowher', 'onc', 'onli', 'otherwis', 'ourselv', 'perhap', 'pleas', 'sever', 'sinc', 'sincer', 'sixti', 'someon', 'someth', 'sometim', 'somewher', 'themselv', 'thenc', 'thereaft', 'therebi', 'therefor', 'togeth', 'twelv', 'twenti', 'veri', 'whatev', 'whenc', 'whenev', 'wherea', 'whereaft', 'wherebi', 'wherev', 'whi', 'yourselv'])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接