java 通过线性算法预测未来数据

一、工具类

import com.siwei.energy.optimization.pojo.dto.NumberDTO;

/**
 * @author 咸鱼搬运工
 */
public class LinearRegressionUtil {

	private static final int MAX_POINTS = 10;

	private double E;

	/**
	 * Print the computed sums.
	 * 获取数据点数
	 *
	 * @param line the regression line
	 */
	private static void printSums(RegressionLine line) {
		System.out.println("\n数据点个数 n = " + line.getDataPointCount());
		System.out.println("\nSum x  = " + line.getSumX());
		System.out.println("Sum y  = " + line.getSumY());
		System.out.println("Sum xx = " + line.getSumXX());
		System.out.println("Sum xy = " + line.getSumXY());
		System.out.println("Sum yy = " + line.getSumYY());

	}

	/**
	 * Print the regression line function.
	 *
	 * @param line the regression line
	 */
	public static NumberDTO printLine(RegressionLine line) {
		//回归线公式
		String formula = "y = " + line.getA1() + "x + " + line.getA0();
		//误差
		double mistake = line.getR();
		System.out.println(formula);
		System.out.println(mistake);
		return new NumberDTO().setNumA(line.getA1()).setNumB(line.getA0());
	}
}

二、实现

import cn.hutool.core.collection.CollUtil;
import com.siwei.energy.constant.EnergyConstant;
import com.siwei.energy.optimization.pojo.dto.DateDTO;
import com.siwei.energy.optimization.pojo.dto.NumberDTO;
import com.siwei.energy.optimization.pojo.dto.QueryDTO;
import com.siwei.energy.optimization.pojo.po.DataPoint;
import com.siwei.energy.optimization.pojo.vo.EnergyPredictVO;
import com.siwei.energy.optimization.service.EnergyOptimizationService;
import com.siwei.energy.utils.LinearRegressionUtil;
import com.siwei.energy.utils.RegressionLine;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 能源优化
 *
 * @Author: yangJing
 * @Date: 2022-06-15 09:53
 */
@Service
public class EnergyOptimizationServiceImpl implements EnergyOptimizationService {

    @Override
    @SneakyThrows
    public List<EnergyPredictVO> energyPredict(QueryDTO query) {
        //获取时间区间
        DateDTO futureDate = getOldDate(query.getDateType());
        // 获取公式系数 y = -5.6x + 146.0
        // 模拟假数据
        // 获取所有数据
        List<EnergyPredictVO> list = constructFakeData();
        if (CollUtil.isNotEmpty(list)) {
            RegressionLine energyPredicts = calculateLinearFormula(list);
            NumberDTO numberDTO = LinearRegressionUtil.printLine(energyPredicts);
            // 处理已经存在的数据
            Integer num = 0;
            for (EnergyPredictVO e : list) {
                num++;
                float predict = numberDTO.getNumA() * num + numberDTO.getNumB();
                e.setPredictPower((float) (Math.round(predict * 100)) / 100);
            }
            // 天数
            Integer count = futureDate.getCount();
            // 预测未来的数据
            List<EnergyPredictVO> collect = list.stream().sorted(Comparator.comparing(EnergyPredictVO::getDate).reversed()).collect(Collectors.toList());
            ArrayList<EnergyPredictVO> temps = new ArrayList<>();
            // 获取时间最大的对象
            if (CollUtil.isNotEmpty(collect)) {
                EnergyPredictVO energyPredictVO = collect.stream().findFirst().orElse(null);
                String date = energyPredictVO.getDate();
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                Date f = simpleDateFormat.parse(date);
                // 时间天数
                int temp = 0;
                for (int i = list.size() + 1; i <= count; i++) {
                    temp++;
                    Date tempDate = new Date(f.getTime() + 1000L * 60 * 60 * 24 * temp);
                    // 预测值
                    float predict = numberDTO.getNumA() * i + numberDTO.getNumB();
                    temps.add(new EnergyPredictVO().setDate(simpleDateFormat.format(tempDate)).setPredictPower((float) (Math.round(predict * 100)) / 100));
                }
            }
            list.addAll(temps);
        }
        return list;
    }

    /**
     * 计算线性公式
     *
     * @param
     * @return
     */
    private RegressionLine calculateLinearFormula(List<EnergyPredictVO> list) {
        float count = 0;
        RegressionLine line = new RegressionLine();
        for (EnergyPredictVO e : list) {
            count++;
            line.addDataPoint(new DataPoint(count, Float.parseFloat(e.getActualPower().toString())));
        }
        return line;
    }

    /**
     * 假数据
     *
     * @param
     * @return
     */
    private List<EnergyPredictVO> constructFakeData() {
        ArrayList<EnergyPredictVO> list = new ArrayList<>();
        EnergyPredictVO e = new EnergyPredictVO().setActualPower(BigDecimal.valueOf(10.215)).setTargetPower(BigDecimal.valueOf(10)).setDate("2022-06-10");
        EnergyPredictVO e1 = new EnergyPredictVO().setActualPower(BigDecimal.valueOf(20.326)).setTargetPower(BigDecimal.valueOf(120)).setDate("2022-06-11");
        EnergyPredictVO e2 = new EnergyPredictVO().setActualPower(BigDecimal.valueOf(30.15)).setTargetPower(BigDecimal.valueOf(143)).setDate("2022-06-12");
        EnergyPredictVO e3 = new EnergyPredictVO().setActualPower(BigDecimal.valueOf(40.13)).setTargetPower(BigDecimal.valueOf(130)).setDate("2022-06-13");
        EnergyPredictVO e4 = new EnergyPredictVO().setActualPower(BigDecimal.valueOf(30.524)).setTargetPower(BigDecimal.valueOf(125)).setDate("2022-06-14");
        EnergyPredictVO e5 = new EnergyPredictVO().setActualPower(BigDecimal.valueOf(60.26)).setTargetPower(BigDecimal.valueOf(126)).setDate("2022-06-15");
        EnergyPredictVO e6 = new EnergyPredictVO().setActualPower(BigDecimal.valueOf(70.441)).setTargetPower(BigDecimal.valueOf(122)).setDate("2022-06-16");
        list.add(e);
        list.add(e1);
        list.add(e2);
        list.add(e3);
        list.add(e4);
        list.add(e5);
        list.add(e6);
        return list;
    }

    /**
     * 获取起始时间时间
     *
     * @param type 年月日类型
     * @return
     */
    private DateDTO getOldDate(String type) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        String endTime;
        String startTime;
        Integer count;
        if (EnergyConstant.Time.DAY.equals(type)) {
            // 前后六天
            calendar.add(Calendar.DATE, -6);
            startTime = sdf.format(calendar.getTime());
            calendar.add(Calendar.DATE, 12);
            endTime = sdf.format(calendar.getTime());
            count = EnergyConstant.Time.DAY_COUNT;
        } else if (EnergyConstant.Time.MONTH.equals(type)) {
            //前后三个月
            calendar.add(Calendar.DATE, -3);
            startTime = sdf.format(calendar.getTime());
            calendar.add(Calendar.DATE, 6);
            endTime = sdf.format(calendar.getTime());
            count = EnergyConstant.Time.MONTH_COUNT;
        } else {
            // 前后两年
            calendar.add(Calendar.DATE, -2);
            startTime = sdf.format(calendar.getTime());
            calendar.add(Calendar.DATE, 4);
            endTime = sdf.format(calendar.getTime());
            count = EnergyConstant.Time.YEAR_COUNT;
        }
        return new DateDTO().setStartTime(startTime).setEndTime(endTime).setCount(count);
    }
}

三、业务参数

@Data
@Accessors(chain = true)
public class DateDTO {
    private String startTime;
    private String endTime;
    private Integer count;
}
@Data

@ApiModel("时间类型dto")
public class QueryDTO {
    /**
     * 日月年
     */
    @NotBlank(message = "年月日类型不能为空!")
    @ApiModelProperty(value = "年月日类型:day,mouth,year")
    private String dateType;

}

@Data
@Accessors(chain = true)
public class EnergyPredictVO {
    /**
     * 日期
     */
    private String date;
    /**
     * 实际电耗
     */
    private BigDecimal actualPower;
    /**
     * 目标电耗
     */
    private BigDecimal targetPower;
    /**
     * 预测电耗
     */
    private Float predictPower;
}

public interface EnergyConstant {
    /**
     * 时间
     */
    interface Time{
        //24小小时转化分钟
        Integer ALL_DAY = 1440;
        Integer DAY_COUNT = 12;
        Integer MONTH_COUNT = 6;
        Integer YEAR_COUNT = 4;
        //日
        String DAY = "day";
        //月
        String MONTH = "month";
        //年
        String YEAR = "year";
    }
}


四、公式参数

@Data
@Accessors(chain = true)
public class NumberDTO {
    /**
     * 系数一
     */
    private Float numA;
    /**
     * 系数二
     */
    private Float numB;
}

public class DataPoint {
    /** the x value */
    public float x;

    /** the y value */
    public float y;

    /**
     * Constructor.
     *
     * @param x
     *            the x value
     * @param y
     *            the y value
     */
    public DataPoint(float x, float y) {
        this.x = x;
        this.y = y;
    }

}

public class RegressionLine {
    /**
     * sum of x
     */
    private double sumX;

    /**
     * sum of y
     */
    private double sumY;

    /**
     * sum of x*x
     */
    private double sumXX;

    /**
     * sum of x*y
     */
    private double sumXY;

    /**
     * sum of y*y
     */
    private double sumYY;

    /**
     * sum of yi-y
     */
    private double sumDeltaY;

    /**
     * sum of sumDeltaY^2
     */
    private double sumDeltaY2;

    /**
     * 误差
     */
    private double sse;

    private double sst;

    private double E;

    private String[] xy;

    private ArrayList listX;

    private ArrayList listY;

    private int XMin, XMax, YMin, YMax;

    /**
     * line coefficient a0
     */
    private float a0;

    /**
     * line coefficient a1
     */
    private float a1;

    /**
     * number of data points
     */
    private int pn;

    /**
     * true if coefficients valid
     */
    private boolean coefsValid;

    /**
     * Constructor.
     */
    public RegressionLine() {
        XMax = 0;
        YMax = 0;
        pn = 0;
        xy = new String[2];
        listX = new ArrayList();
        listY = new ArrayList();
    }

    /**
     * Constructor.
     *
     * @param data the array of data points
     */
    public RegressionLine(DataPoint data[]) {
        pn = 0;
        xy = new String[2];
        listX = new ArrayList();
        listY = new ArrayList();
        for (int i = 0; i < data.length; ++i) {
            addDataPoint(data[i]);
        }
    }

    /**
     * Return the current number of data points.
     *
     * @return the count
     */
    public int getDataPointCount() {
        return pn;
    }

    /**
     * Return the coefficient a0.
     *
     * @return the value of a0
     */
    public float getA0() {
        validateCoefficients();
        return a0;
    }

    /**
     * Return the coefficient a1.
     *
     * @return the value of a1
     */
    public float getA1() {
        validateCoefficients();
        return a1;
    }

    /**
     * Return the sum of the x values.
     *
     * @return the sum
     */
    public double getSumX() {
        return sumX;
    }

    /**
     * Return the sum of the y values.
     *
     * @return the sum
     */
    public double getSumY() {
        return sumY;
    }

    /**
     * Return the sum of the x*x values.
     *
     * @return the sum
     */
    public double getSumXX() {
        return sumXX;
    }

    /**
     * Return the sum of the x*y values.
     *
     * @return the sum
     */
    public double getSumXY() {
        return sumXY;
    }

    public double getSumYY() {
        return sumYY;
    }

    public int getXMin() {
        return XMin;
    }

    public int getXMax() {
        return XMax;
    }

    public int getYMin() {
        return YMin;
    }

    public int getYMax() {
        return YMax;
    }

    /**
     * Add a new data point: Update the sums.
     *
     * @param dataPoint the new data point
     */
    public void addDataPoint(DataPoint dataPoint) {
        sumX += dataPoint.x;
        sumY += dataPoint.y;
        sumXX += dataPoint.x * dataPoint.x;
        sumXY += dataPoint.x * dataPoint.y;
        sumYY += dataPoint.y * dataPoint.y;

        if (dataPoint.x > XMax) {
            XMax = (int) dataPoint.x;
        }
        if (dataPoint.y > YMax) {
            YMax = (int) dataPoint.y;
        }

        // 把每个点的具体坐标存入ArrayList中,备用

        xy[0] = (int) dataPoint.x + "";
        xy[1] = (int) dataPoint.y + "";
        if (dataPoint.x != 0 && dataPoint.y != 0) {
            System.out.print(xy[0] + ",");
            System.out.println(xy[1]);

            try {
                // System.out.println("n:"+n);
                listX.add(pn, xy[0]);
                listY.add(pn, xy[1]);
            } catch (Exception e) {
                e.printStackTrace();
            }

            /*
             * System.out.println("N:" + n); System.out.println("ArrayList
             * listX:"+ listX.get(n)); System.out.println("ArrayList listY:"+
             * listY.get(n));
             */
        }
        ++pn;
        coefsValid = false;
    }

    /**
     * Return the value of the regression line function at x. (Implementation of
     * Evaluatable.)
     *
     * @param x the value of x
     * @return the value of the function at x
     */
    public float at(int x) {
        if (pn < 2)
            return Float.NaN;

        validateCoefficients();
        return a0 + a1 * x;
    }

    /**
     * Reset.
     */
    public void reset() {
        pn = 0;
        sumX = sumY = sumXX = sumXY = 0;
        coefsValid = false;
    }

    /**
     * Validate the coefficients. 计算方程系数 y=ax+b 中的a
     */
    private void validateCoefficients() {
        if (coefsValid) {
            return;
        }

        if (pn >= 2) {
            float xBar = (float) sumX / pn;
            float yBar = (float) sumY / pn;

            a1 = (float) ((pn * sumXY - sumX * sumY) / (pn * sumXX - sumX
                    * sumX));
            a0 = (float) (yBar - a1 * xBar);
        } else {
            a0 = a1 = Float.NaN;
        }

        coefsValid = true;
    }

    /**
     * 返回误差
     */
    public double getR() {
        // 遍历这个list并计算分母
        for (int i = 0; i < pn - 1; i++) {
            float Yi = (float) Integer.parseInt(listY.get(i).toString());
            float Y = at(Integer.parseInt(listX.get(i).toString()));
            float deltaY = Yi - Y;
            float deltaY2 = deltaY * deltaY;
            /*
             * System.out.println("Yi:" + Yi); System.out.println("Y:" + Y);
             * System.out.println("deltaY:" + deltaY);
             * System.out.println("deltaY2:" + deltaY2);
             */

            sumDeltaY2 += deltaY2;
            // System.out.println("sumDeltaY2:" + sumDeltaY2);

        }

        sst = sumYY - (sumY * sumY) / pn;
        // System.out.println("sst:" + sst);
        E = 1 - sumDeltaY2 / sst;

        return round(E, 4);
    }

    // 用于实现精确的四舍五入
    public double round(double v, int scale) {

        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }

        BigDecimal b = new BigDecimal(Double.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();

    }

    public float round(float v, int scale) {

        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }

        BigDecimal b = new BigDecimal(Double.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).floatValue();

    }

}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
1、下载并安装mysql,将脚本执行至数据库中; 2、配置java环境,使用jdk8,配置环境变量,下载IntelliJ IDEA 2019.2.4,该工具为java代码编译器 3、下载Maven,配置至环境变量(百度搜索很多),将构建器为Maven,类库配置成阿里库(方法:百度搜索很多很多) 4、将工程导入后,在application-local.yml文件中配置数据库 5、在logback-prod.xml文件中配置log日志 6、配置完毕后,即可启动 访问地址:http://localhost:8082/anime/login.html 用户名:admin 密码:admin V:china1866 1、 登录 2、 首页 3、 权限管理-用户管理 4、 权限管理-添加用户数据 5、 交通数据管理-查看交通数据 6、 交通数据管理-添加交通数据 7、 交通预测-交通数据预测 脚本: CREATE TABLE `traffic_data_t` ( `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '序列', `trafficId` VARCHAR(50) NULL DEFAULT NULL COMMENT '交通数据编号', `trafficContent` VARCHAR(50) NULL DEFAULT NULL COMMENT '交通状况', `trafficSection` VARCHAR(200) NULL DEFAULT NULL COMMENT '交通路段', `trafficMan` VARCHAR(200) NULL DEFAULT NULL COMMENT '上报人', `trafficDate` VARCHAR(200) NULL DEFAULT NULL COMMENT '上报时间', `status` VARCHAR(200) NULL DEFAULT NULL COMMENT '交通状态', PRIMARY KEY (`id`) ) COMMENT='交通数据表' COLLATE='utf8_general_ci' ENGINE=InnoDB AUTO_INCREMENT=44 ; CREATE TABLE `sys_user_t` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `role_id` INT(11) NULL DEFAULT NULL COMMENT '角色ID', `user_id` VARCHAR(50) NOT NULL COMMENT '用户ID', `user_name` VARCHAR(100) NOT NULL COMMENT '用户名', `status` INT(11) NOT NULL COMMENT '是否有效0:false\\\\1:true', `create_date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, `create_by` VARCHAR(100) NULL DEFAULT NULL, `last_update_date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, `last_update_by` VARCHAR(100) NULL DEFAULT NULL, `password` VARCHAR(128) NOT NULL, `tenantcode` VARCHAR(50) NOT NULL, `diskId` VARCHAR(500) NULL DEFAULT NULL, `remarks` VARCHAR(500) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) COMMENT='系统用户表' COLLATE='utf8_general_ci' ENGINE=InnoDB AUTO_INCREMENT=51 ; CREATE TABLE `sys_role_t` ( `role_id` INT(11) NOT NULL COMMENT '角色ID', `role_name` VARCHAR(200) NOT NULL COMMENT '权限名称', `status` INT(11) NOT NULL COMMENT '是否有效0:true\\\\1:false', `create_date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, `create_by` VARCHAR(100) NULL DEFAULT NULL, `last_update_date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, `last_update_by` VARCHAR(100) NULL DEFAULT NULL ) COMMENT='系统角色表' COLLATE='utf8_general_ci' ENGINE=InnoDB ; CREATE TABLE `sys_menu_t` ( `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '序列', `parent_id` VARCHAR(50) NOT NULL COMMENT '父节点ID', `menu_id` VARCHAR(50) NOT NULL COMMENT '菜单ID', `menu_name` VARCHAR(200) NOT NULL COMMENT '菜单名称', `menu_url` VARCHAR(200) NULL DEFAULT NULL COMMENT '菜单URL', `status` INT(11) NOT NULL COMMENT '有效(0有效,1失效)', `create_date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, `create_by` VARCHAR(200) NULL DEFAULT NULL, `last_update_date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, `last_update_by` VARCHAR(200) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) COMMENT='菜单表' COLLATE='utf8_general_ci' ENGINE=InnoDB AUTO_INCREMENT=33 ; CREATE TABLE `sys_menu_role_relation_t` ( `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '序列', `menu_id` VARCHAR(50) NOT NULL COMMENT '菜单ID', `role_id` VARCHAR(50) NOT NULL COMMENT '角色ID', `status` INT(11) NOT NULL COMMENT '有效(0有效,1失效)', `create_date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, `create_by` VARCHAR(200) NULL DEFAULT NULL, `last_update_date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, `last_update_by` VARCHAR(200) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) COMMENT='角色与菜单关系表' COLLATE='utf8_general_ci' ENGINE=InnoDB AUTO_INCREMENT=51 ;
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值