TfidfVectorizer 给予停用词高权重
TfidfVectorizer gives high weight to stop words
给定以下代码:
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
import urllib.request # the lib that handles the url stuff
from bs4 import BeautifulSoup
import unicodedata
def remove_control_characters(s):
base = ""
for ch in s:
if unicodedata.category(ch)[0]!="C":
base = base + ch.lower()
else:
base = base + " "
return base
moby_dick_url='http://www.gutenberg.org/files/2701/2701-0.txt'
soul_of_japan = 'http://www.gutenberg.org/files/12096/12096-0.txt'
def extract_body(url):
with urllib.request.urlopen(url) as s:
data = BeautifulSoup(s).body()[0].string
stripped = remove_control_characters(data)
return stripped
moby = extract_body(moby_dick_url)
bushido = extract_body(soul_of_japan)
corpus = [moby,bushido]
vectorizer = TfidfVectorizer(use_idf=False, smooth_idf=True)
tf_idf = vectorizer.fit_transform(corpus)
df_tfidf = pd.DataFrame(tf_idf.toarray(), columns=vectorizer.get_feature_names(), index=["Moby", "Bushido"])
df_tfidf[["the", "whale"]]
我希望 "whale" 在 "Moby Dick" 中获得相对较高的 tf-idf,但在 "Bushido: The Soul of Japan" 中获得较低的分数,并且 "the" 获得两者得分都低。然而,我却恰恰相反。计算的结果是:
| | the | whale |
|-------|-----------|----------|
|Moby | 0.707171 | 0.083146 |
|Bushido| 0.650069 | 0.000000 |
这对我来说毫无意义。谁能指出我在思考或编码方面的错误?
您观察到这一点有两个原因。
首先是因为您传递给 Tfidf Vectorizer 的参数。你应该做 TfidfVectorizer(use_idf=True, ...)
,因为它是 tfidf 的 idf 部分(记住 tf-idf 是词频和逆文档频率的乘积)会惩罚出现在所有文档中的单词。通过设置 TfidfVectorizer(use_idf=False, ..)
,你只是在考虑术语频率部分,这显然会导致停用词具有更大的分数
第二个是因为你的数据。假设你修复了上面的代码问题,你的语料库还是非常非常小,只有两个文档。这意味着出现在两本书中的任何单词都会以同样的方式受到惩罚。 "courage" 可能会出现在两本书中,就像 "the" 一样,因此如果它们都出现在您语料库的每个文档中,它们的 idf 值将相同,导致停用词再次具有更大的分数,因为他们较大的词频
给定以下代码:
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
import urllib.request # the lib that handles the url stuff
from bs4 import BeautifulSoup
import unicodedata
def remove_control_characters(s):
base = ""
for ch in s:
if unicodedata.category(ch)[0]!="C":
base = base + ch.lower()
else:
base = base + " "
return base
moby_dick_url='http://www.gutenberg.org/files/2701/2701-0.txt'
soul_of_japan = 'http://www.gutenberg.org/files/12096/12096-0.txt'
def extract_body(url):
with urllib.request.urlopen(url) as s:
data = BeautifulSoup(s).body()[0].string
stripped = remove_control_characters(data)
return stripped
moby = extract_body(moby_dick_url)
bushido = extract_body(soul_of_japan)
corpus = [moby,bushido]
vectorizer = TfidfVectorizer(use_idf=False, smooth_idf=True)
tf_idf = vectorizer.fit_transform(corpus)
df_tfidf = pd.DataFrame(tf_idf.toarray(), columns=vectorizer.get_feature_names(), index=["Moby", "Bushido"])
df_tfidf[["the", "whale"]]
我希望 "whale" 在 "Moby Dick" 中获得相对较高的 tf-idf,但在 "Bushido: The Soul of Japan" 中获得较低的分数,并且 "the" 获得两者得分都低。然而,我却恰恰相反。计算的结果是:
| | the | whale |
|-------|-----------|----------|
|Moby | 0.707171 | 0.083146 |
|Bushido| 0.650069 | 0.000000 |
这对我来说毫无意义。谁能指出我在思考或编码方面的错误?
您观察到这一点有两个原因。
首先是因为您传递给 Tfidf Vectorizer 的参数。你应该做
TfidfVectorizer(use_idf=True, ...)
,因为它是 tfidf 的 idf 部分(记住 tf-idf 是词频和逆文档频率的乘积)会惩罚出现在所有文档中的单词。通过设置TfidfVectorizer(use_idf=False, ..)
,你只是在考虑术语频率部分,这显然会导致停用词具有更大的分数第二个是因为你的数据。假设你修复了上面的代码问题,你的语料库还是非常非常小,只有两个文档。这意味着出现在两本书中的任何单词都会以同样的方式受到惩罚。 "courage" 可能会出现在两本书中,就像 "the" 一样,因此如果它们都出现在您语料库的每个文档中,它们的 idf 值将相同,导致停用词再次具有更大的分数,因为他们较大的词频