如何在将训练语料库传递给 sklearn 中的 TfidfVectorizer 之前应用自定义词干分析器?
How to apply a custom stemmer before passing the training corpus to TfidfVectorizer in sklearn?
这是我的代码,我有一个句子,我想在将它传递给 TfidfVectorizer 以最终获得句子的 tf-idf 表示之前对其进行标记化和词干化:
from sklearn.feature_extraction.text import TfidfVectorizer
import nltk
from nltk.stem.snowball import SnowballStemmer
stemmer_ita = SnowballStemmer("italian")
def tokenizer_stemmer_ita(text):
return [stemmer_ita.stem(word) for word in text.split()]
def sentence_tokenizer_stemmer(text):
return " ".join([stemmer_ita.stem(word) for word in text.split()])
X_train = ['il libro è sul tavolo']
X_train = [sentence_tokenizer_stemmer(text) for text in X_train]
tfidf = TfidfVectorizer(preprocessor=None, tokenizer=None, use_idf=True, stop_words=None, ngram_range=(1,2))
X_train = tfidf.fit_transform(X_train)
# let's see the features
print (tfidf.get_feature_names())
我得到输出:
['il', 'il libr', 'libr', 'libr sul', 'sul', 'sul tavol', 'tavol']
如果我更改参数
tokenizer=None
至:
tokenizer=tokenizer_stemmer_ita
我评论这行:
X_train = [sentence_tokenizer_stemmer(text) for text in X_train]
我希望得到相同的结果,但结果不同:
['il', 'il libr', 'libr', 'libr è', 'sul', 'sul tavol', 'tavol', 'è', 'è sul']
为什么?我是否正确实施了外部词干分析器?看起来,至少,停用词(“è”)在第一个 运行 中被删除,即使 stop_words=None.
[编辑]
正如 Vivek 所建议的那样,问题似乎是默认的令牌模式,当 tokenizer = None 时无论如何都会应用它。因此,如果在 tokenizer_stemmer_ita:
的开头添加这两行
token_pattern = re.compile(u'(?u)\b\w\w+\b')
text = " ".join( token_pattern.findall(text) )
我应该得到正确的行为,实际上我在上面的简单示例中得到了正确的行为,但对于另一个示例:
X_train = ['0.05%.\n\nVedete?']
我不知道,这两个输出是不同的:
['05', '05 ved', 'ved']
和
['05', '05 vedete', 'vedete']
为什么?在这种情况下,问号似乎是问题所在,没有它输出是相同的。
[编辑2]
看来我必须先阻止然后应用正则表达式,在这种情况下两个输出是相同的。
那是因为 TfidfVectorizer 中使用了默认分词器模式 token_pattern
:
token_pattern : string
Regular expression denoting what constitutes a “token”, only used if analyzer == 'word'. The default regexp selects tokens of 2 or more
alphanumeric characters (punctuation is completely ignored and always
treated as a token separator).
所以字符è
没有被选中。
import re
token_pattern = re.compile(u'(?u)\b\w\w+\b')
print token_pattern.findall('il libro è sul tavolo')
# Output
# ['il', 'libro', 'sul', 'tavolo']
当分词器为 None 时,将使用此默认值 token_pattern
,如您所见。
这是我的代码,我有一个句子,我想在将它传递给 TfidfVectorizer 以最终获得句子的 tf-idf 表示之前对其进行标记化和词干化:
from sklearn.feature_extraction.text import TfidfVectorizer
import nltk
from nltk.stem.snowball import SnowballStemmer
stemmer_ita = SnowballStemmer("italian")
def tokenizer_stemmer_ita(text):
return [stemmer_ita.stem(word) for word in text.split()]
def sentence_tokenizer_stemmer(text):
return " ".join([stemmer_ita.stem(word) for word in text.split()])
X_train = ['il libro è sul tavolo']
X_train = [sentence_tokenizer_stemmer(text) for text in X_train]
tfidf = TfidfVectorizer(preprocessor=None, tokenizer=None, use_idf=True, stop_words=None, ngram_range=(1,2))
X_train = tfidf.fit_transform(X_train)
# let's see the features
print (tfidf.get_feature_names())
我得到输出:
['il', 'il libr', 'libr', 'libr sul', 'sul', 'sul tavol', 'tavol']
如果我更改参数
tokenizer=None
至:
tokenizer=tokenizer_stemmer_ita
我评论这行:
X_train = [sentence_tokenizer_stemmer(text) for text in X_train]
我希望得到相同的结果,但结果不同:
['il', 'il libr', 'libr', 'libr è', 'sul', 'sul tavol', 'tavol', 'è', 'è sul']
为什么?我是否正确实施了外部词干分析器?看起来,至少,停用词(“è”)在第一个 运行 中被删除,即使 stop_words=None.
[编辑] 正如 Vivek 所建议的那样,问题似乎是默认的令牌模式,当 tokenizer = None 时无论如何都会应用它。因此,如果在 tokenizer_stemmer_ita:
的开头添加这两行token_pattern = re.compile(u'(?u)\b\w\w+\b')
text = " ".join( token_pattern.findall(text) )
我应该得到正确的行为,实际上我在上面的简单示例中得到了正确的行为,但对于另一个示例:
X_train = ['0.05%.\n\nVedete?']
我不知道,这两个输出是不同的:
['05', '05 ved', 'ved']
和
['05', '05 vedete', 'vedete']
为什么?在这种情况下,问号似乎是问题所在,没有它输出是相同的。
[编辑2] 看来我必须先阻止然后应用正则表达式,在这种情况下两个输出是相同的。
那是因为 TfidfVectorizer 中使用了默认分词器模式 token_pattern
:
token_pattern : string
Regular expression denoting what constitutes a “token”, only used if analyzer == 'word'. The default regexp selects tokens of 2 or more alphanumeric characters (punctuation is completely ignored and always treated as a token separator).
所以字符è
没有被选中。
import re
token_pattern = re.compile(u'(?u)\b\w\w+\b')
print token_pattern.findall('il libro è sul tavolo')
# Output
# ['il', 'libro', 'sul', 'tavolo']
当分词器为 None 时,将使用此默认值 token_pattern
,如您所见。