为什么没有liblinear预测大多数类?

时间:2013-02-19 04:20:23

标签: java machine-learning classification libsvm

大多数机器学习分类器在遇到没有之前看到的功能的实例时,会将示例分类为训练数据中最常见的类。

liblinear-java似乎并非如此,我想知道为什么会这样。下面是一些示例代码,其中我构建了一个示例问题,其中有两个功能,并且训练数据的标签数量是0 1标签的4倍:

Problem problem = new Problem();
problem.l = 5;
problem.n = 2;
problem.x = new FeatureNode[][] {
  new FeatureNode[] { new FeatureNode(1, 1) },  
  new FeatureNode[] { new FeatureNode(1, 1) },  
  new FeatureNode[] { new FeatureNode(1, 1) },  
  new FeatureNode[] { new FeatureNode(1, 1) },  
  new FeatureNode[] { new FeatureNode(2, 1) },  
};
problem.y = new int[] {0, 0, 0, 0, 1};

Parameter parameter = new Parameter(SolverType.L2R_L2LOSS_SVC, 1.0, 0.01);
Model model = Linear.train(problem, parameter);

现在让我们对新功能3进行测试,该功能不在训练数据中。由于训练有素的模型对特征3一无所知,我原本预计预测的类将是0,这是训练数据中最常见的类。

FeatureNode[] instance = new FeatureNode[] { new FeatureNode(3, 1) };
int prediction = Linear.predict(model, instance);
System.err.println(prediction);

然而,最后一行打印出1。那是为什么?

1 个答案:

答案 0 :(得分:2)

我相信这是liblinear的命令行版本的“-B”(偏见)参数旨在修复的内容。如果直接创建FeatureNode,则该参数不可用,但它与在new FeatureNode(1, 1)的每个开头添加FeatureNode[]基本相同。如果我遵循这种方法,并在训练期间和分类期间添加额外的偏差功能,一切正常。这是代码的样子:

Problem problem = new Problem();
problem.l = 5;
problem.n = 3;
problem.x = new FeatureNode[][] {
  new FeatureNode[] { new FeatureNode(1, 1), new FeatureNode(2, 1) },  
  new FeatureNode[] { new FeatureNode(1, 1), new FeatureNode(2, 1) },  
  new FeatureNode[] { new FeatureNode(1, 1), new FeatureNode(2, 1) },  
  new FeatureNode[] { new FeatureNode(1, 1), new FeatureNode(2, 1) },  
  new FeatureNode[] { new FeatureNode(1, 1), new FeatureNode(3, 1) },  
};
problem.y = new int[] {0, 0, 0, 0, 1};

Parameter parameter = new Parameter(SolverType.L2R_L2LOSS_SVC, 1.0, 0.01);
Model model = Linear.train(problem, parameter);
FeatureNode[] instance = new FeatureNode[] { new FeatureNode(1, 1), new FeatureNode(4, 1) };
int prediction = Linear.predict(model, instance);

为了弄清楚为什么需要偏置功能,我稍微挖了一下liblinear-java代码。这是预测代码的样子:

for (int i = 0; i < nr_w; i++)
    dec_values[i] = 0;

for (FeatureNode lx : x) {
    int idx = lx.index;
    // the dimension of testing data may exceed that of training
    if (idx <= n) {
        for (int i = 0; i < nr_w; i++) {
            dec_values[i] += w[(idx - 1) * nr_w + i] * lx.value;
         }
    }
}

因此,在训练期间从未看到过这些特征的情况下,我们只得到一个全零的dec_values(决策值)数组,这意味着所有类都具有相同的概率。因此,在分类过程中看到的每个实例中至少有一个在训练过程中看到的特征是至关重要的。

添加具有常量值的“偏差”功能(例如1)可解决此问题,允许模型学习应用于任何新实例的默认权重。在上面的代码中,模型为偏见要素学习0.0869565217391306的权重,这意味着模型正确地学习了类0而不是类1