TF-IDF 的纯 pandas 实现
Pure pandas implementation of TF-IDF
我想知道为什么我的 Pandas TF-IDF 实现显示的结果与 sklearn 实现略有不同。
这是我的实现:
text = ["aa bb cc dd ee", "bb cc dd dd"]
terms = [Counter(t.split(' ')) for t in text]
tf = pd.DataFrame(terms)
tf = tf.fillna(0)
num_docs = len(text)
idf = np.log(num_docs / tf[tf >= 1].count()) + 1
tf_idf = tf * idf
norm = np.sqrt((tf_idf ** 2).sum(axis=1))
norm_tf_idf = tf_idf.div(norm, axis=0)
>>> norm_tf_idf
aa bb cc dd ee
0 0.572929 0.338381 0.338381 0.338381 0.572929
1 0.000000 0.408248 0.408248 0.816497 0.000000
但是如果我使用 sklearn:
tf = TfidfVectorizer(smooth_idf=False, stop_words=None, sublinear_tf=True)
x = tf.fit_transform(text)
sk = pd.DataFrame(x.toarray())
sk.columns = tf.get_feature_names()
sk
>>> sk
aa bb cc dd ee
0 0.572929 0.338381 0.338381 0.338381 0.572929
1 0.000000 0.453295 0.453295 0.767495 0.000000
或者如果我们减去它们:
>>> norm_tf_idf - sk
aa bb cc dd ee
0 0.0 0.000000 0.000000 0.000000 0.0
1 0.0 -0.045046 -0.045046 0.049002 0.0
编辑:
我发现 sklearn idf 与我的 idf 不完全相同,但我们可以将其归因于浮点精度,我认为:
sklearn idf: [1.69314718 1. 1. 1. 1.69314718]
my idf: [1.693147 1.000000 1.000000 1.000000 1.693147]
即使我使用 sklearn idf,我仍然会得到不同的结果。
此外,如果我不规范化并使用 sklearn idf 值,则只有第二个文档 dd
的 TF-IDF 不同:
sk_tfv = TfidfVectorizer(smooth_idf=False, stop_words=None, token_pattern=r"(?u)\b\w+\b", sublinear_tf=True, norm=None)
x = sk_tf.fit_transform(text)
sk_tf_idf = pd.DataFrame(x.toarray())
...
idf = sk_tfv.idf_
tf_idf = tf * idf
>>> tf_idf - sk_tf_idf
aa bb cc dd ee
0 0.0 0.0 0.0 0.000000 0.0
1 0.0 0.0 0.0 0.306853 0.0
这意味着两件事:
1.问题是我的TF。然而,这很容易检查,但似乎并非如此。或者,
2. sklearn 不仅可以做 TF * IDF
,还可以做更多的事情,我必须研究一下。
我傻了。在深入了解 sklearn 源代码后,我注意到了 sublinear_tf
参数。将此参数设置为 True 后,术语频率将替换为 log(TF) + 1
并且恰好是我将此参数设置为 True
:)
要在 pandas 中实现次线性 TF,这应该可行:
tf[tf > 0] = np.log(tf[tf > 0] ) + 1
我想知道为什么我的 Pandas TF-IDF 实现显示的结果与 sklearn 实现略有不同。
这是我的实现:
text = ["aa bb cc dd ee", "bb cc dd dd"]
terms = [Counter(t.split(' ')) for t in text]
tf = pd.DataFrame(terms)
tf = tf.fillna(0)
num_docs = len(text)
idf = np.log(num_docs / tf[tf >= 1].count()) + 1
tf_idf = tf * idf
norm = np.sqrt((tf_idf ** 2).sum(axis=1))
norm_tf_idf = tf_idf.div(norm, axis=0)
>>> norm_tf_idf
aa bb cc dd ee
0 0.572929 0.338381 0.338381 0.338381 0.572929
1 0.000000 0.408248 0.408248 0.816497 0.000000
但是如果我使用 sklearn:
tf = TfidfVectorizer(smooth_idf=False, stop_words=None, sublinear_tf=True)
x = tf.fit_transform(text)
sk = pd.DataFrame(x.toarray())
sk.columns = tf.get_feature_names()
sk
>>> sk
aa bb cc dd ee
0 0.572929 0.338381 0.338381 0.338381 0.572929
1 0.000000 0.453295 0.453295 0.767495 0.000000
或者如果我们减去它们:
>>> norm_tf_idf - sk
aa bb cc dd ee
0 0.0 0.000000 0.000000 0.000000 0.0
1 0.0 -0.045046 -0.045046 0.049002 0.0
编辑:
我发现 sklearn idf 与我的 idf 不完全相同,但我们可以将其归因于浮点精度,我认为:
sklearn idf: [1.69314718 1. 1. 1. 1.69314718]
my idf: [1.693147 1.000000 1.000000 1.000000 1.693147]
即使我使用 sklearn idf,我仍然会得到不同的结果。
此外,如果我不规范化并使用 sklearn idf 值,则只有第二个文档 dd
的 TF-IDF 不同:
sk_tfv = TfidfVectorizer(smooth_idf=False, stop_words=None, token_pattern=r"(?u)\b\w+\b", sublinear_tf=True, norm=None)
x = sk_tf.fit_transform(text)
sk_tf_idf = pd.DataFrame(x.toarray())
...
idf = sk_tfv.idf_
tf_idf = tf * idf
>>> tf_idf - sk_tf_idf
aa bb cc dd ee
0 0.0 0.0 0.0 0.000000 0.0
1 0.0 0.0 0.0 0.306853 0.0
这意味着两件事:
1.问题是我的TF。然而,这很容易检查,但似乎并非如此。或者,
2. sklearn 不仅可以做 TF * IDF
,还可以做更多的事情,我必须研究一下。
我傻了。在深入了解 sklearn 源代码后,我注意到了 sublinear_tf
参数。将此参数设置为 True 后,术语频率将替换为 log(TF) + 1
并且恰好是我将此参数设置为 True
:)
要在 pandas 中实现次线性 TF,这应该可行:
tf[tf > 0] = np.log(tf[tf > 0] ) + 1