为什么某个类特有的特征未被强烈预测为该类?

总结与问题

我正在使用liblinear 2.30 – 我注意到生产环境中存在类似的问题,因此我尝试通过简化的训练来隔离它,包含2个类,每个类一个训练文档,词汇表中5个特征的权重相同,以及一个仅包含一个特征的简单测试文档,该特征仅存在于类2中。

  • a) 特征值用于什么目的?

  • b) 我想了解为什么这个只包含一个特征的测试文档,该特征仅存在于一个类中,却未被强烈预测为该类?

  • c) 我并不期望每个特征有不同的值。将每个特征值从1增加到其他值是否有其他影响?我如何确定这个数字?

  • d) 我的更改是否会对其他更复杂的训练产生不良影响?

我尝试过的方法

下面你会找到与简单训练相关的数据(请关注特征5):

> cat train.txt1 1:1 2:1 3:12 2:1 4:1 5:1> train -s 0 -c 1 -p 0.1 -e 0.01 -B 0 train.txt model.biniter  1 act 3.353e-01 pre 3.333e-01 delta 6.715e-01 f 1.386e+00 |g| 1.000e+00 CG   1iter  2 act 4.825e-05 pre 4.824e-05 delta 6.715e-01 f 1.051e+00 |g| 1.182e-02 CG   1> cat model.binsolver_type L2R_LRnr_class 2label 1 2nr_feature 5bias 0w0.337414143653901600.3374141436539016-0.3374141436539016-0.33741414365390160

这是模型的输出:

solver_type L2R_LRnr_class 2label 1 2nr_feature 5bias 0w0.337414143653901600.3374141436539016-0.3374141436539016-0.337414143653901601 5:10

下面是我的模型预测结果:

> cat test.txt1 5:1> predict -b 1 test.txt model.bin test.outAccuracy = 0% (0/1)> cat test.outlabels 1 22 0.416438 0.583562

这里我有点惊讶,因为预测结果仅为[0.42, 0.58],而特征5仅存在于类2中。为什么呢?因此,我尝试将测试文档的特征值从1增加到10:

> cat newtest.txt1 5:10> predict -b 1 newtest.txt model.bin newtest.outAccuracy = 0% (0/1)> cat newtest.outlabels 1 22 0.0331135 0.966887

现在我得到了更好的预测结果[0.03, 0.97]。因此,我尝试重新编译我的训练数据,将所有特征设置为10:

> cat newtrain.txt1 1:10 2:10 3:102 2:10 4:10 5:10> train -s 0 -c 1 -p 0.1 -e 0.01 -B 0 newtrain.txt newmodel.biniter  1 act 1.104e+00 pre 9.804e-01 delta 2.508e-01 f 1.386e+00 |g| 1.000e+01 CG   1iter  2 act 1.381e-01 pre 1.140e-01 delta 2.508e-01 f 2.826e-01 |g| 2.272e+00 CG   1iter  3 act 2.627e-02 pre 2.269e-02 delta 2.508e-01 f 1.445e-01 |g| 6.847e-01 CG   1iter  4 act 2.121e-03 pre 1.994e-03 delta 2.508e-01 f 1.183e-01 |g| 1.553e-01 CG   1> cat newmodel.binsolver_type L2R_LRnr_class 2label 1 2nr_feature 5bias 0w0.1942051039536484600.19420510395364846-0.19420510395364846-0.194205103953648460> predict -b 1 newtest.txt newmodel.bin newtest.outAccuracy = 0% (0/1)> cat newtest.outlabels 1 22 0.125423 0.874577

再次预测结果对于类2仍然可以接受:0.87


回答:

a) 特征值用于什么目的?

每个n个特征的实例被视为n维空间中的一个点,并附有一个给定的标签,比如+1或-1(在你的例子中是1或2)。线性SVM试图找到最佳超平面,将这些实例分成两个集合,比如SetA和SetB。当SetA包含更多标记为+1的实例,而SetB包含更多标记为-1的实例时,超平面被认为比其他超平面更好,即更准确。最佳超平面被保存为模型。在你的情况下,超平面的公式为:

f(x)=w^T x

其中w是模型,例如在你的第一个案例中是(0.33741,0,0.33741,-0.33741,-0.33741)。

概率(对于LR)的公式为:

prob(x)=1/(1+exp(-y*f(x))

其中y=+1或-1。参见LIBLINEAR论文的附录L。

b) 我想了解为什么这个只包含一个特征的测试文档,该特征仅存在于一个类中,却未被强烈预测为该类?

不仅1 5:1给出了如[0.42,0.58]的弱概率,如果你预测2 2:1 4:1 5:1,你会得到[0.337417,0.662583],这似乎表明求解器对结果也不是很自信,即使输入与训练数据集完全相同。

根本原因在于f(x)的值,或者可以简单地看作x与超平面之间的距离。只有当距离无限大时(见prob(x)),才能100%确信x属于某个类别。

c) 我并不期望每个特征有不同的值。将每个特征值从1增加到其他值是否有其他影响?我如何确定这个数字?

TL;DR

放大训练集和测试集就像拥有更大的惩罚参数C(-c选项)。因为更大的C意味着对错误有更严格的惩罚,直观上说,求解器对预测更有信心。


放大训练集的每个特征就像拥有更小的C。具体来说,逻辑回归解决以下关于w的方程。

min 0.5 w^T w + C ∑i log(1+exp(−yi w^T xi)) 

LIBLINEAR论文的eq(3))

对于大多数实例,yi w^T xi是正的,且更大的xi意味着更小的∑i log(1+exp(−yi w^T xi))。因此效果有些类似于拥有更小的C,而更小的C意味着更小的|w|。

另一方面,放大测试集相当于拥有更大的|w|。因此,放大训练集和测试集的基本效果是

(1). 训练时拥有更小的|w|(2). 然后,测试时拥有更大的|w|

因为(2)的效果比(1)更显著,总体来说,放大训练集和测试集就像拥有更大的|w|,或者说拥有更大的C。

我们可以在数据集上运行,并将每个特征乘以10^12。在C=1的情况下,我们有模型和概率

> cat model.bin.m1e12.c1solver_type L2R_LRnr_class 2label 1 2nr_feature 5bias 0w3.0998430106024949e-12 0 3.0998430106024949e-12 -3.0998430106024949e-12 -3.0998430106024949e-12 0 > cat test.out.m1e12.c1labels 1 22 0.0431137 0.956886

接下来我们在原始数据集上运行。在C=10^12的情况下,我们有概率

> cat model.bin.m1.c1e12solver_type L2R_LRnr_class 2label 1 2nr_feature 5bias 0w3.0998430101989314 0 3.0998430101989314 -3.0998430101989314 -3.0998430101989314 0 > cat test.out.m1.c1e12labels 1 22 0.0431137 0.956886

因此,因为更大的C意味着对错误有更严格的惩罚,所以直观上求解器对预测更有信心。

d) 我的更改是否会对其他更复杂的训练产生不良影响?

从(c)我们知道你的更改就像拥有更大的C,这将导致更好的训练准确性。但几乎可以肯定,当C变得太大时,模型会过拟合训练集。结果,模型无法承受训练集中的噪声,测试准确性会表现得很差。

至于找到一个好的C,一个流行方法是通过交叉验证(-v选项)。


最后,

这可能有点跑题,但你可能想看看如何预处理文本数据。通常(例如,liblinear的作者在这里建议),对数据进行实例级归一化是很常见的做法。

对于文档分类,我们的经验表明,如果你将每个文档归一化为单位长度,那么不仅训练时间更短,而且性能也更好。

Related Posts

在MLens Pipeline中使用StandardScaler作为预处理器会生成分类警告

我在MLens Superlearner管道的交叉验证…

如何计算Sklearn中随机森林和极端随机树中各个树的投票?

我一直在用Rust语言构建自己的极端随机树(XT)分类…

如何将嵌套数组输入到SVM模型中

我的问题如下: 我有一个数组,其中包含对应于多个音频文…

Scikit-learn的cross_val_score抛出ValueError: `Layer.call`的第一个参数必须始终传递

我正在进行一个深度学习项目,并尝试按照教程中的方法使用…

运行时间估计:小鼠(MICE)插补?

我使用小鼠(MICE)插补方法来填充机器学习数据集中缺…

使用字符串和整数进行预测的DecisionTreeClassifier

我有一段代码从数据库中获取了一些数据,数据库部分并不重…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注