|
|
|
@ -1,196 +1,71 @@
|
|
|
|
|
package com.sztzjy.marketing.util.algorithm;
|
|
|
|
|
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
|
|
|
|
|
import org.ujmp.core.DenseMatrix;
|
|
|
|
|
import org.ujmp.core.Matrix;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 参考:https://blog.csdn.net/weixin_45040801/article/details/102542209
|
|
|
|
|
* https://blog.csdn.net/ccblogger/article/details/81739200
|
|
|
|
|
* */
|
|
|
|
|
public class LogisticRegression {
|
|
|
|
|
private double[] weights;
|
|
|
|
|
private double bias;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 训练逻辑回归模型
|
|
|
|
|
*
|
|
|
|
|
* @param data 输入的特征数据
|
|
|
|
|
* @param classValues 目标类别值
|
|
|
|
|
* @return 训练得到的模型参数
|
|
|
|
|
*/
|
|
|
|
|
public static double[] train(double[][] data, double[] classValues) {
|
|
|
|
|
|
|
|
|
|
if (data != null && classValues != null && data.length == classValues.length) {
|
|
|
|
|
// 期望矩阵
|
|
|
|
|
// Matrix matrWeights = DenseMatrix.Factory.zeros(data[0].length + 1, 1);
|
|
|
|
|
Matrix matrWeights = DenseMatrix.Factory.zeros(data[0].length, 1);
|
|
|
|
|
System.out.println("data[0].length + 1========"+data[0].length + 1);
|
|
|
|
|
// 数据矩阵
|
|
|
|
|
// Matrix matrData = DenseMatrix.Factory.zeros(data.length, data[0].length + 1);
|
|
|
|
|
Matrix matrData = DenseMatrix.Factory.zeros(data.length, data[0].length);
|
|
|
|
|
// 标志矩阵
|
|
|
|
|
Matrix matrLable = DenseMatrix.Factory.zeros(data.length, 1);
|
|
|
|
|
// 训练速率矩阵
|
|
|
|
|
// Matrix matrRate = DenseMatrix.Factory.zeros(data[0].length + 1,data.length);
|
|
|
|
|
// 统计difference的总体失误的辅助矩阵
|
|
|
|
|
Matrix matrDiffUtil = DenseMatrix.Factory.zeros(data[0].length,data.length);
|
|
|
|
|
for(int i=0;i<data.length;i++){
|
|
|
|
|
for(int j=0;j<data[0].length;j++) {
|
|
|
|
|
matrDiffUtil.setAsDouble(1, j, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
System.out.println("matrDiffUtil="+matrDiffUtil);
|
|
|
|
|
/**
|
|
|
|
|
* 行数应该和期望矩阵一致列数
|
|
|
|
|
* 列数应该和标志矩阵一致
|
|
|
|
|
* */
|
|
|
|
|
|
|
|
|
|
// System.out.println("matrRate======="+matrRate);
|
|
|
|
|
// 设置训练速率矩阵
|
|
|
|
|
// for(int i=0;i<data[0].length + 1;i++){
|
|
|
|
|
// for(int j=0;j<data.length;j++){
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
public LogisticRegression(int numFeatures) {
|
|
|
|
|
weights = new double[numFeatures];
|
|
|
|
|
bias = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void fit(double[][] X, double[] y, double learningRate, int numIterations) {
|
|
|
|
|
int numSamples = X.length;
|
|
|
|
|
int numFeatures = X[0].length;
|
|
|
|
|
|
|
|
|
|
for (int iter = 0; iter < numIterations; iter++) {
|
|
|
|
|
double[] gradientWeights = new double[numFeatures];
|
|
|
|
|
double gradientBias = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < data.length; i++) {
|
|
|
|
|
// matrData.setAsDouble(1.0, i, 0);
|
|
|
|
|
// 初始化标志矩阵
|
|
|
|
|
matrLable.setAsDouble(classValues[i], i, 0);
|
|
|
|
|
for (int j = 0; j < data[0].length; j++) {
|
|
|
|
|
// 初始化数据矩阵
|
|
|
|
|
// matrData.setAsDouble(data[i][j], i, j + 1);
|
|
|
|
|
matrData.setAsDouble(data[i][j], i, j);
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
// 初始化期望矩阵
|
|
|
|
|
// matrWeights.setAsDouble(1.0, j+1, 0);
|
|
|
|
|
matrWeights.setAsDouble(1.0, j, 0);
|
|
|
|
|
for (int i = 0; i < numSamples; i++) {
|
|
|
|
|
double dotProduct = dotProduct(X[i], weights) + bias;
|
|
|
|
|
double prediction = sigmoid(dotProduct);
|
|
|
|
|
double error = y[i] - prediction;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
for (int j = 0; j < numFeatures; j++) {
|
|
|
|
|
gradientWeights[j] += error * X[i][j];
|
|
|
|
|
}
|
|
|
|
|
gradientBias += error;
|
|
|
|
|
}
|
|
|
|
|
// matrWeights.setAsDouble(-0.5, data[0].length, 0);
|
|
|
|
|
|
|
|
|
|
// matrRate = matrData.transpose().times(0.9);
|
|
|
|
|
|
|
|
|
|
// System.out.println("matrRate============"+matrRate);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double step = 0.011;
|
|
|
|
|
int maxCycle = 5000000;
|
|
|
|
|
// int maxCycle = 5;
|
|
|
|
|
|
|
|
|
|
System.out.println("matrData======"+matrData);
|
|
|
|
|
System.out.println("matrWeights"+matrWeights);
|
|
|
|
|
System.out.println("matrLable"+matrLable);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 使用梯度下降法的思想:
|
|
|
|
|
* 矩阵运算,参考:https://blog.csdn.net/lionel_fengj/article/details/53400715
|
|
|
|
|
*
|
|
|
|
|
* */
|
|
|
|
|
for (int i = 0; i < maxCycle; i++) {
|
|
|
|
|
// 将想要函数转换为sigmoid函数并得到的值
|
|
|
|
|
Matrix h = sigmoid(matrData.mtimes(matrWeights));
|
|
|
|
|
// System.out.println("h=="+h);
|
|
|
|
|
// 求出预期和真实的差值
|
|
|
|
|
Matrix difference = matrLable.minus(h);
|
|
|
|
|
// System.out.println("difference "+difference);
|
|
|
|
|
// matrData转置后和difference相乘,得到预期和真实差值的每一个值
|
|
|
|
|
// 公式:@0 = @0 - ax(y0-y),可以参考:https://blog.csdn.net/ccblogger/article/details/81739200
|
|
|
|
|
matrWeights = matrWeights.plus(matrData.transpose().mtimes(difference).times(step));
|
|
|
|
|
// matrWeights = matrWeights.plus(matrRate.mtimes(difference).times(step));
|
|
|
|
|
// matrWeights = matrWeights.plus(matrDiffUtil.mtimes(difference).times(step));
|
|
|
|
|
for (int j = 0; j < numFeatures; j++) {
|
|
|
|
|
weights[j] += learningRate * gradientWeights[j] / numSamples;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double[] rtn = new double[(int) matrWeights.getRowCount()];
|
|
|
|
|
for (long i = 0; i < matrWeights.getRowCount(); i++) {
|
|
|
|
|
rtn[(int) i] = matrWeights.getAsDouble(i, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rtn;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bias += learningRate * gradientBias / numSamples;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 对矩阵进行sigmoid函数运算
|
|
|
|
|
*
|
|
|
|
|
* @param sourceMatrix 输入的矩阵
|
|
|
|
|
* @return 经过sigmoid函数运算后的矩阵
|
|
|
|
|
*/
|
|
|
|
|
public static Matrix sigmoid(Matrix sourceMatrix) {
|
|
|
|
|
Matrix rtn = DenseMatrix.Factory.zeros(sourceMatrix.getRowCount(), sourceMatrix.getColumnCount());
|
|
|
|
|
for (int i = 0; i < sourceMatrix.getRowCount(); i++) {
|
|
|
|
|
for (int j = 0; j < sourceMatrix.getColumnCount(); j++) {
|
|
|
|
|
rtn.setAsDouble(sigmoid(sourceMatrix.getAsDouble(i, j)), i, j);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rtn;
|
|
|
|
|
public double predict(double[] x) {
|
|
|
|
|
double dotProduct = dotProduct(x, weights) + bias;
|
|
|
|
|
return sigmoid(dotProduct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* sigmoid函数
|
|
|
|
|
*
|
|
|
|
|
* @param source 输入的值
|
|
|
|
|
* @return sigmoid函数运算后的结果
|
|
|
|
|
*/
|
|
|
|
|
public static double sigmoid(double source) {
|
|
|
|
|
return 1.0 / (1 + Math.exp(-1 * source));
|
|
|
|
|
private double sigmoid(double x) {
|
|
|
|
|
return 1 / (1 + Math.exp(-x));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 测试预测值:
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 预测给定特征数据的逻辑回归值
|
|
|
|
|
*
|
|
|
|
|
* @param sourceData 输入的特征数据
|
|
|
|
|
* @param model 训练得到的模型参数
|
|
|
|
|
* @return 预测的逻辑回归值
|
|
|
|
|
*/
|
|
|
|
|
public static double getValue(double[] sourceData, double[] model) {
|
|
|
|
|
// double logisticRegressionValue = model[0];
|
|
|
|
|
double logisticRegressionValue = 0;
|
|
|
|
|
for (int i = 0; i < sourceData.length; i++) {
|
|
|
|
|
// logisticRegressionValue = logisticRegressionValue + sourceData[i] * model[i + 1];
|
|
|
|
|
logisticRegressionValue = logisticRegressionValue + sourceData[i] * model[i];
|
|
|
|
|
private double dotProduct(double[] x, double[] y) {
|
|
|
|
|
double sum = 0;
|
|
|
|
|
for (int i = 0; i < x.length; i++) {
|
|
|
|
|
sum += x[i] * y[i];
|
|
|
|
|
}
|
|
|
|
|
logisticRegressionValue = sigmoid(logisticRegressionValue);
|
|
|
|
|
|
|
|
|
|
return logisticRegressionValue;
|
|
|
|
|
return sum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
double[][] X = {{1, 1}, {1, 2}, {2, 1}, {2, 3}};
|
|
|
|
|
double[] y = {0, 0, 0, 1};
|
|
|
|
|
|
|
|
|
|
LogisticRegression model = new LogisticRegression(2);
|
|
|
|
|
model.fit(X, y, 0.01, 10000);
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
double[][] sourceData = new double[][]{{-1, 1}, {0, 1}, {1, -1}, {1, 0}, {0, 0.1}, {0, -0.1}, {-1, -1.1}, {1, 0.9}};
|
|
|
|
|
double[] classValue = new double[]{1, 1, 0, 0, 1, 0, 0, 0};
|
|
|
|
|
double[] modle = LogisticRegression.train(sourceData, classValue);
|
|
|
|
|
// double logicValue = LogisticRegression.getValue(new double[] { 0, 0 }, modle);
|
|
|
|
|
double logicValue0 = LogisticRegression.getValue(new double[]{-1, 1}, modle);
|
|
|
|
|
double logicValue1 = LogisticRegression.getValue(new double[]{0, 1}, modle);
|
|
|
|
|
double logicValue2 = LogisticRegression.getValue(new double[]{1, -1}, modle);//3.1812246935599485E-60无限趋近于0
|
|
|
|
|
double logicValue3 = LogisticRegression.getValue(new double[]{1, 0}, modle);//3.091713602147872E-30无限趋近于0
|
|
|
|
|
double logicValue4 = LogisticRegression.getValue(new double[]{0, 0.1}, modle);//3.091713602147872E-30无限趋近于0
|
|
|
|
|
double logicValue5 = LogisticRegression.getValue(new double[]{0, -0.1}, modle);//3.091713602147872E-30无限趋近于0
|
|
|
|
|
System.out.println("---model---");
|
|
|
|
|
for (int i = 0; i < modle.length; i++) {
|
|
|
|
|
System.out.println(modle[i]);
|
|
|
|
|
}
|
|
|
|
|
System.out.println("-----------");
|
|
|
|
|
// System.out.println(logicValue);
|
|
|
|
|
System.out.println(logicValue0);
|
|
|
|
|
System.out.println(logicValue1);
|
|
|
|
|
System.out.println(logicValue2);
|
|
|
|
|
System.out.println(logicValue3);
|
|
|
|
|
System.out.println(logicValue4);
|
|
|
|
|
System.out.println(logicValue5);
|
|
|
|
|
}
|
|
|
|
|
System.out.println("Weights: " + Arrays.toString(model.weights));
|
|
|
|
|
System.out.println("Bias: " + model.bias);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
double[] newSample = {1, 2};
|
|
|
|
|
double prediction = model.predict(newSample);
|
|
|
|
|
System.out.println("Prediction for " + Arrays.toString(newSample) + ": " + prediction);
|
|
|
|
|
}
|
|
|
|
|
}
|