朴素高斯仅预测概率 returns 0 或 1
Naive Gaussian predict probability only returns 0 or 1
我从 scikit sklearn 训练了 GaussianNB 模型。当我调用方法 classifier.predict_proba
时,它仅对新数据 returns 1 或 0。预期 return 预测正确与否的置信度百分比。我怀疑它能否对以前从未见过的新数据有 100% 的信心。我已经在多个不同的输入上对其进行了测试。我使用 CountVectorizer 和 TfidfTransformer 进行文本编码。
编码:
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
count_vect = CountVectorizer()
tfidf_transformer = TfidfTransformer()
X_train_counts = count_vect.fit_transform(X_train_word)
X_train = tfidf_transformer.fit_transform(X_train_counts).toarray()
print(X_train)
X_test_counts = count_vect.transform(X_test_word)
X_test = tfidf_transformer.transform(X_test_counts).toarray()
print(X_test)
模型:(我的准确率为 91%)
from sklearn.naive_bayes import GaussianNB
classifier = GaussianNB()
classifier.fit(X_train, y_train)
# Predict Class
y_pred = classifier.predict(X_test)
# Accuracy
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, y_pred)
print(accuracy)
最后,当我使用 predict_proba 方法时:
y_pred = classifier.predict_proba(X_test)
print(y_pred)
我得到如下输出:
[[0. 1.]
[1. 0.]
[0. 1.]
...
[1. 0.]
[1. 0.]
[1. 0.]]
新数据的 100% 准确度没有多大意义。除了在 y_test
上,我已经在其他输入上对其进行了测试,它仍然 return 相同。如有任何帮助,我们将不胜感激!
编辑评论:
.predict_log_proba()
的回复更奇怪:
[[ 0.00000000e+00 -6.95947375e+09]
[-4.83948755e+09 0.00000000e+00]
[ 0.00000000e+00 -1.26497690e+10]
...
[ 0.00000000e+00 -6.97191054e+09]
[ 0.00000000e+00 -2.25589894e+09]
[ 0.00000000e+00 -2.93089863e+09]]
让我在 public 20 newsgroups dataset 上重现您的结果。为简单起见,我将只使用两组和 30 个观察值:
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.preprocessing import FunctionTransformer
from sklearn.naive_bayes import GaussianNB
from sklearn.pipeline import make_pipeline
cats = ['alt.atheism', 'sci.space']
newsgroups_train = fetch_20newsgroups(subset='train', categories=cats)
newsgroups_test = fetch_20newsgroups(subset='test', categories=cats)
# deliberately create a very small training set
X_small, y_small = newsgroups_train['data'][:30], newsgroups_train['target'][:30]
print(y_small)
# [0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 1 0 0 0 0 0 1 0 1]
现在让我们训练一个模型。我将使用管道将所有算法堆叠在一个处理器中:
model = make_pipeline(
CountVectorizer(),
TfidfTransformer(),
FunctionTransformer(lambda x: x.todense(), accept_sparse=True),
GaussianNB()
)
model.fit(X_small, y_small);
print(model.predict_proba(newsgroups_test['data']))
# [[1. 0.]
# [0. 1.]
# [1. 0.]
print((model.predict(X_small) == y_small).mean())
# 1.0
print((model.predict(newsgroups_test['data']) == newsgroups_test['target']).mean())
# 0.847124824684432
print(model.predict_proba(newsgroups_test['data']).max(axis=1).mean())
# 0.9994305488454233
事实上,并非所有的预测概率都是0或1,但大多数是。预测的平均预测概率 class 为 99.94%,因此该模型平均而言对其预测非常有信心。
我们看到在训练集上的准确率是完美的,但是在测试集上的准确率只有 84.7%。所以看起来我们的GaussianNB是overfitting——也就是说,它太依赖于训练数据集了。是的,如果特征 space 很大,即使使用像 NB 这样简单的算法也是可能的。并且使用 CountVectorizer,词汇表中的每个词都是一个单独的特征,所有可能的词的数量相当大。所以我们的模型过度拟合,这就是为什么它会产生由零和一组成的过度自信的预测。
而且,像往常一样,我们可以使用正则化 来对抗过度拟合。使用 GaussianNB,正则化模型的最简单方法是将参数 var_smoothing
设置为某个相对较大的正值(默认情况下,它是 10^-8
)。根据我的经验,我建议值在 0.01 到 1 的范围内。这里我将其设置为 0.3。这意味着最多样化特征(即在 class 之间分布最均匀的词)的 30% 方差将添加到所有其他特征。
model2 = make_pipeline(
CountVectorizer(),
TfidfTransformer(),
FunctionTransformer(lambda x: x.todense(), accept_sparse=True),
GaussianNB(var_smoothing=0.3)
)
model2.fit(X_small, y_small);
print(model2.predict_proba(newsgroups_test['data']))
# [[1.00000000e+00 6.95414544e-11]
# [2.55262953e-02 9.74473705e-01]
# [9.97333826e-01 2.66617361e-03]
print((model2.predict(X_small) == y_small).mean())
# 1.0
print((model2.predict(newsgroups_test['data']) == newsgroups_test['target']).mean())
# 0.8821879382889201
print(model2.predict_proba(newsgroups_test['data']).max(axis=1).mean())
# 0.9657781853646639
我们可以看到,在添加正则化之后,我们模型的预测变得不那么自信了:平均置信度是 96.57%,而不是 99.94%。而且,在测试集上的准确率也有所提高,因为这种过度自信导致模型做出了一些错误的预测。
这些错误预测的逻辑可以说明如下。在没有正则化的情况下,模型完全依赖于训练集中单词的频率。当它看起来像文本“死于 X 射线的概率”,模型认为“我在有关无神论的文本中只看到过‘死亡’这个词 ,所以这个 必须 是一篇关于无神论的文章”。但这是一篇关于 space 的文本,更正则化的模型在其结论中不会那么确定,并且仍然会保留一些小但非零的概率,即带有“垂死”一词的文本是关于其他主题的比无神论。
所以这里的教训是:无论你使用什么学习算法,找出如何对其进行正则化,并仔细调整正则化参数。
我从 scikit sklearn 训练了 GaussianNB 模型。当我调用方法 classifier.predict_proba
时,它仅对新数据 returns 1 或 0。预期 return 预测正确与否的置信度百分比。我怀疑它能否对以前从未见过的新数据有 100% 的信心。我已经在多个不同的输入上对其进行了测试。我使用 CountVectorizer 和 TfidfTransformer 进行文本编码。
编码:
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
count_vect = CountVectorizer()
tfidf_transformer = TfidfTransformer()
X_train_counts = count_vect.fit_transform(X_train_word)
X_train = tfidf_transformer.fit_transform(X_train_counts).toarray()
print(X_train)
X_test_counts = count_vect.transform(X_test_word)
X_test = tfidf_transformer.transform(X_test_counts).toarray()
print(X_test)
模型:(我的准确率为 91%)
from sklearn.naive_bayes import GaussianNB
classifier = GaussianNB()
classifier.fit(X_train, y_train)
# Predict Class
y_pred = classifier.predict(X_test)
# Accuracy
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, y_pred)
print(accuracy)
最后,当我使用 predict_proba 方法时:
y_pred = classifier.predict_proba(X_test)
print(y_pred)
我得到如下输出:
[[0. 1.]
[1. 0.]
[0. 1.]
...
[1. 0.]
[1. 0.]
[1. 0.]]
新数据的 100% 准确度没有多大意义。除了在 y_test
上,我已经在其他输入上对其进行了测试,它仍然 return 相同。如有任何帮助,我们将不胜感激!
编辑评论:
.predict_log_proba()
的回复更奇怪:
[[ 0.00000000e+00 -6.95947375e+09]
[-4.83948755e+09 0.00000000e+00]
[ 0.00000000e+00 -1.26497690e+10]
...
[ 0.00000000e+00 -6.97191054e+09]
[ 0.00000000e+00 -2.25589894e+09]
[ 0.00000000e+00 -2.93089863e+09]]
让我在 public 20 newsgroups dataset 上重现您的结果。为简单起见,我将只使用两组和 30 个观察值:
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.preprocessing import FunctionTransformer
from sklearn.naive_bayes import GaussianNB
from sklearn.pipeline import make_pipeline
cats = ['alt.atheism', 'sci.space']
newsgroups_train = fetch_20newsgroups(subset='train', categories=cats)
newsgroups_test = fetch_20newsgroups(subset='test', categories=cats)
# deliberately create a very small training set
X_small, y_small = newsgroups_train['data'][:30], newsgroups_train['target'][:30]
print(y_small)
# [0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 1 0 0 0 0 0 1 0 1]
现在让我们训练一个模型。我将使用管道将所有算法堆叠在一个处理器中:
model = make_pipeline(
CountVectorizer(),
TfidfTransformer(),
FunctionTransformer(lambda x: x.todense(), accept_sparse=True),
GaussianNB()
)
model.fit(X_small, y_small);
print(model.predict_proba(newsgroups_test['data']))
# [[1. 0.]
# [0. 1.]
# [1. 0.]
print((model.predict(X_small) == y_small).mean())
# 1.0
print((model.predict(newsgroups_test['data']) == newsgroups_test['target']).mean())
# 0.847124824684432
print(model.predict_proba(newsgroups_test['data']).max(axis=1).mean())
# 0.9994305488454233
事实上,并非所有的预测概率都是0或1,但大多数是。预测的平均预测概率 class 为 99.94%,因此该模型平均而言对其预测非常有信心。
我们看到在训练集上的准确率是完美的,但是在测试集上的准确率只有 84.7%。所以看起来我们的GaussianNB是overfitting——也就是说,它太依赖于训练数据集了。是的,如果特征 space 很大,即使使用像 NB 这样简单的算法也是可能的。并且使用 CountVectorizer,词汇表中的每个词都是一个单独的特征,所有可能的词的数量相当大。所以我们的模型过度拟合,这就是为什么它会产生由零和一组成的过度自信的预测。
而且,像往常一样,我们可以使用正则化 来对抗过度拟合。使用 GaussianNB,正则化模型的最简单方法是将参数 var_smoothing
设置为某个相对较大的正值(默认情况下,它是 10^-8
)。根据我的经验,我建议值在 0.01 到 1 的范围内。这里我将其设置为 0.3。这意味着最多样化特征(即在 class 之间分布最均匀的词)的 30% 方差将添加到所有其他特征。
model2 = make_pipeline(
CountVectorizer(),
TfidfTransformer(),
FunctionTransformer(lambda x: x.todense(), accept_sparse=True),
GaussianNB(var_smoothing=0.3)
)
model2.fit(X_small, y_small);
print(model2.predict_proba(newsgroups_test['data']))
# [[1.00000000e+00 6.95414544e-11]
# [2.55262953e-02 9.74473705e-01]
# [9.97333826e-01 2.66617361e-03]
print((model2.predict(X_small) == y_small).mean())
# 1.0
print((model2.predict(newsgroups_test['data']) == newsgroups_test['target']).mean())
# 0.8821879382889201
print(model2.predict_proba(newsgroups_test['data']).max(axis=1).mean())
# 0.9657781853646639
我们可以看到,在添加正则化之后,我们模型的预测变得不那么自信了:平均置信度是 96.57%,而不是 99.94%。而且,在测试集上的准确率也有所提高,因为这种过度自信导致模型做出了一些错误的预测。
这些错误预测的逻辑可以说明如下。在没有正则化的情况下,模型完全依赖于训练集中单词的频率。当它看起来像文本“死于 X 射线的概率”,模型认为“我在有关无神论的文本中只看到过‘死亡’这个词 ,所以这个 必须 是一篇关于无神论的文章”。但这是一篇关于 space 的文本,更正则化的模型在其结论中不会那么确定,并且仍然会保留一些小但非零的概率,即带有“垂死”一词的文本是关于其他主题的比无神论。
所以这里的教训是:无论你使用什么学习算法,找出如何对其进行正则化,并仔细调整正则化参数。