用Java中的梯度下降实现Logistic回归

时间:2015-03-03 04:51:25

标签: java machine-learning logistic-regression gradient-descent

我在Java中使用Gradient Descent实现了Logistic回归。它似乎不能很好地工作(它没有正确分类记录; y = 1的概率很多。)我不知道我的实现是否正确。我已经多次通过代码,我无法找到任何错误。我一直在关注Andrew Ng关于课程时代机器学习的教程。我的Java实现有3个类。即:

  1. DataSet.java:读取数据集
  2. Instance.java:有两个成员:1。double [] x和2. double label
  3. Logistic.java:这是使用Gradient Descent实现Logistic回归的主类。
  4. 这是我的成本函数:

    J(Θ)=( - 1 / m)[Σ m i = 1 y (i) log (h Θ(x (i)))+(1 - y (i))log(1 - h Θ< / sub>(x (i)))]

    对于上面的Cost函数,这是我的Gradient Descent算法:

    重复(

    Θ j :=Θ j - αΣ m i = 1 < / sub>(h Θ(x (i)) - y (i))x (i) <子>Ĵ

    (同时更新所有Θ j

    import java.io.FileNotFoundException;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    
    public class Logistic {
    
        /** the learning rate */
        private double alpha;
    
        /** the weight to learn */
        private double[] theta;
    
        /** the number of iterations */
        private int ITERATIONS = 3000;
    
        public Logistic(int n) {
            this.alpha = 0.0001;
            theta = new double[n];
        }
    
        private double sigmoid(double z) {
            return (1 / (1 + Math.exp(-z)));
        }
    
        public void train(List<Instance> instances) {
    
        double[] temp = new double[3];
    
        //Gradient Descent algorithm for minimizing theta
        for(int i=1;i<=ITERATIONS;i++)
        {
           for(int j=0;j<3;j++)
           {      
            temp[j]=theta[j] - (alpha * sum(j,instances));
           }
    
           //simulataneous updates of theta  
           for(int j=0;j<3;j++)
           {
             theta[j] = temp[j];
           }
            System.out.println(Arrays.toString(theta));
        }
    
        }
    
        private double sum(int j,List<Instance> instances)
        {
            double[] x;
            double prediction,sum=0,y;
    
    
           for(int i=0;i<instances.size();i++)
           {
              x = instances.get(i).getX();
              y = instances.get(i).getLabel();
              prediction = classify(x);
              sum+=((prediction - y) * x[j]);
           }
             return (sum/instances.size());
    
        }
    
        private double classify(double[] x) {
            double logit = .0;
            for (int i=0; i<theta.length;i++)  {
                logit += (theta[i] * x[i]);
            }
            return sigmoid(logit);
        }
    
    
        public static void main(String... args) throws FileNotFoundException {
    
          //DataSet is a class with a static method readDataSet which reads the dataset
          // Instance is a class with two members: double[] x, double label y
          // x contains the features and y is the label.
    
            List<Instance> instances = DataSet.readDataSet("data.txt");
          // 3 : number of theta parameters corresponding to the features x 
          // x0 is always 1   
            Logistic logistic = new Logistic(3);
            logistic.train(instances);
    
            //Test data
            double[]x = new double[3];
            x[0]=1;
            x[1]=45;
            x[2] = 85;
    
            System.out.println("Prob: "+logistic.classify(x));
    
    
        }
    }
    

    谁能告诉我我做错了什么? 提前致谢! :)

1 个答案:

答案 0 :(得分:0)

在研究逻辑回归时,我花了一些时间详细检查您的代码。

TLDR

实际上,看来算法是正确的。

我认为,您之所以会误报或误报太多是因为您选择了超参数。

该模型训练不足,因此假设不符合要求。

详细信息

我必须创建DataSetInstance类,因为您没有发布它们,并基于冷冻疗法数据集建立了训练数据集和测试数据集。 参见http://archive.ics.uci.edu/ml/datasets/Cryotherapy+Dataset+

然后,使用相同的精确代码(用于逻辑回归部分),通过选择0.001的alpha速率和100000的多次迭代,我得到了{{1 }}占测试数据集的百分比,还不错。

我试图通过手动调整这些超级参数来获得更高的精度,但无法获得任何更好的结果。

这是我想,现在可以增强实现正则化。

梯度下降公式

在Ng的有关成本函数和梯度下降的视频中,省略80.64516129032258一词是正确的。 可能的解释是1/m项包含在1/m项中。 也许这只是一个疏忽。 请在6时53分看到https://www.youtube.com/watch?v=TTdcc21Ko9A&index=36&list=PLLssT5z_DsK-h9vYZkQkYNWcItqhlRJLN&t=6m53s

但是,如果您观看Andrew Ng的有关正则化和逻辑回归的视频,您会注意到alpha一词显然出现在公式中。 请在2分19秒看到https://www.youtube.com/watch?v=IXPgm1e0IOo&index=42&list=PLLssT5z_DsK-h9vYZkQkYNWcItqhlRJLN&t=2m19s