博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[java] 数据处理
阅读量:6435 次
发布时间:2019-06-23

本文共 10057 字,大约阅读时间需要 33 分钟。


背景:

有一组30天内的温度与时间的数据,格式如下:

详细情况:共30天的8k+项数据,每天内有260+项,每个记录温度的时间精确到秒

任务就是想根据这样的数据找到规律,来完成给定具体的时间预测出此时的温度

处理思路:先把将数据用时序图表示出来,看看有什么样的规律

代码如下:

import java.awt.Font;import java.io.BufferedReader;import java.io.FileReader;import org.jfree.chart.ChartFactory;import org.jfree.chart.ChartPanel;import org.jfree.chart.JFreeChart;import org.jfree.chart.axis.DateAxis;import org.jfree.chart.axis.ValueAxis;import org.jfree.chart.plot.XYPlot;import org.jfree.data.time.Day;import org.jfree.data.time.Hour;import org.jfree.data.time.Minute;import org.jfree.data.time.Second;import org.jfree.data.time.TimeSeries;import org.jfree.data.time.TimeSeriesCollection;import org.jfree.data.xy.XYDataset;public class TimeSeriesChart {    ChartPanel frame1;      public TimeSeriesChart(){          XYDataset xydataset = createDataset();          JFreeChart jfreechart = ChartFactory.createTimeSeriesChart("temperature-time", "time", "temperature",xydataset, true, true, true);          XYPlot xyplot = (XYPlot) jfreechart.getPlot();          DateAxis dateaxis = (DateAxis) xyplot.getDomainAxis();          frame1=new ChartPanel(jfreechart,true);                 //水平底部标题        dateaxis.setLabelFont(new Font("黑体",Font.BOLD,14));        //垂直标题        dateaxis.setTickLabelFont(new Font("宋体",Font.BOLD,12));        //获取柱状         ValueAxis rangeAxis=xyplot.getRangeAxis();         rangeAxis.setLabelFont(new Font("黑体",Font.BOLD,15));          jfreechart.getLegend().setItemFont(new Font("黑体", Font.BOLD, 15));        //设置标题字体          jfreechart.getTitle().setFont(new Font("宋体",Font.BOLD,20));      }       private static XYDataset createDataset()    {        TimeSeries timeseries = new TimeSeries("温度随时间变化图");        String temperature = null;        String time = null;        try         {            BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\lichaoxing\\Desktop\\52001848#2018-07-01-00-00-00_2018-07-31-00-00-00.csv"));            reader.readLine();             String line = null;            //int i = 0;            while((line=reader.readLine())!=null)            {                  String item[] = line.split(",");//CSV格式文件为逗号分隔符文件,这里根据逗号切分                 temperature = item[2];//这就是你要的数据了                 time = item[4];                double value = Double.parseDouble(temperature);//如果是数值,可以转化为数值                 time = time.replace("\"", "");                String tmp_split1[] = time.split(" ");                String tmp_split2[] = tmp_split1[0].split("-");                String tmp_split3[] = tmp_split1[1].split(":");                                    //System.out.println(tmp_split1[0]);                System.out.println(tmp_split1[1]);                Day day = new Day(Integer.valueOf(tmp_split2[2]), Integer.valueOf(tmp_split2[1]), Integer.valueOf(tmp_split2[0]));                Hour hour = new Hour(Integer.valueOf(tmp_split3[0]), day);                Minute minute = new Minute(Integer.valueOf(tmp_split3[1]), hour);                Second second = new Second( Integer.valueOf(tmp_split3[2]) ,minute);                timeseries.add(second, value);

                  //if(i++ > 260)

                  //    break;

}            reader.close();        }        catch(Exception e)         {            e.printStackTrace();        }        TimeSeriesCollection timeseriescollection = new TimeSeriesCollection();          timeseriescollection.addSeries(timeseries);          return timeseriescollection;       }      public ChartPanel getChartPanel()    {          return frame1;                    }  }

 

import java.awt.GridLayout;  import javax.swing.JFrame; public class tmp {    public static void main(String[] args)throws Exception    {                JFrame frame=new JFrame("统计图");          frame.setLayout(new GridLayout(1,1,10,10));         /*添加折线图*/          frame.add(new TimeSeriesChart().getChartPanel());        frame.setBounds(50, 50, 800, 600);          frame.setVisible(true);               }}

 得到下面的时序图

分析:除了个别异样数据点外,看上去十分平滑,但是并不能具体看到每天的状况,介于每天温度变化基本一致,于是考虑在代码while中,添加提前终止条件(上边注释的代码),观察一天的情况

分析:现在这一天的数据看着就清晰很多了,可以大致认为数据是类正弦的,如果对于精确度要求不高,可以认为它就是一个具有周期的数据

于是考虑将含有一个谷底(极小值)的一段作为周期的一个,可以近似看作是二次函数,那现在就来拟合这个二次函数,拟合采用多项式拟合

方法就是:根据局部极小值连续出现两次求解周期(这两次的值及可能不同,不过也无所谓,只是用其来大概计算周期)

代码如下:

import java.io.BufferedReader;import java.io.File;import java.io.FileReader;import java.text.SimpleDateFormat;import java.util.Date;import org.apache.commons.math3.fitting.PolynomialCurveFitter;import org.apache.commons.math3.fitting.WeightedObservedPoints;public class predict_temperature {           private static String[] observed_data(double flag, BufferedReader reader) throws Exception    {        String line = null;        String[] i_want = new String[4];        if(flag > 0)        {            double tmp = 1000;            System.out.println(flag);            while((line=reader.readLine())!=null)            {                  String item[] = line.split(",");                 double value = Double.parseDouble(item[2]);                if(value <= tmp)                    tmp = value;                else                 {                    i_want[0] = item[0];                    i_want[1] = item[4].replace("\"", "");                    break;                }            }            while((line=reader.readLine())!=null)            {                  String item[] = line.split(",");                 double value = Double.parseDouble(item[2]);                if(value >= tmp)                    tmp = value;                else                     break;            }            while((line=reader.readLine())!=null)            {                  String item[] = line.split(",");                 double value = Double.parseDouble(item[2]);                if(value <= tmp)                    tmp = value;                else                {                    i_want[2] = item[0];                    i_want[3] = item[4].replace("\"", "");                    break;                }            }        }        else        {            double tmp = -1000;            while((line=reader.readLine())!=null)            {                  String item[] = line.split(",");                 double value = Double.parseDouble(item[2]);                if(value >= tmp)                    tmp = value;                else                 {                    i_want[0] = item[0];                    i_want[1] = item[4].replace("\"", "");                    break;                }            }            while((line=reader.readLine())!=null)            {                  String item[] = line.split(",");                 double value = Double.parseDouble(item[2]);                if(value <= tmp)                    tmp = value;                else                     break;            }            while((line=reader.readLine())!=null)            {                  String item[] = line.split(",");                 double value = Double.parseDouble(item[2]);                if(value >= tmp)                    tmp = value;                else                {                    i_want[2] = item[0];                    i_want[3] = item[4].replace("\"", "");                    break;                }            }        }        return i_want;            }        public static void main(String[] args) throws Exception    {                WeightedObservedPoints points = new WeightedObservedPoints();        String input_time = args[1] + " " + args[2];        File file = new File(args[0]);        double time_diff = 0;                BufferedReader reader = new BufferedReader(new FileReader(file));        reader.readLine();        reader.mark((int)file.length());                /*计算周期*/        double compare_item1 = Double.parseDouble(reader.readLine().split(",")[2]);        double compare_item2 = Double.parseDouble(reader.readLine().split(",")[2]);        String[] cycle_result = new String[4];        cycle_result = observed_data(compare_item1 - compare_item2, reader);        int start_num = Integer.parseInt(cycle_result[0]);        int end_num = Integer.parseInt(cycle_result[2]);        SimpleDateFormat tmp_day = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        Date start_now = tmp_day.parse(cycle_result[1]);        Date end_now = tmp_day.parse(cycle_result[3]);        /*计算周期*/        int cycle = end_num - start_num;        reader.reset();        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        SimpleDateFormat input_time_format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");        Date input_time_ = input_time_format.parse(input_time);        Date start_time = null;        int i = 0;        String line = null;        String time = null;        while((line=reader.readLine())!=null)        {              String item[] = line.split(",");             time = item[4];            double value = Double.parseDouble(item[2]);             time = time.replace("\"", "");            Date now = sdf.parse(time);            if(i == 0)                start_time = now;            double offset = (now.getTime() - start_time.getTime());            points.add(offset, value);            time_diff = (input_time_.getTime() - start_time.getTime()) % (end_now.getTime() - start_now.getTime());            if(i++ > cycle)                break;                        }        PolynomialCurveFitter fitter = PolynomialCurveFitter.create(2);        double[] result = fitter.fit(points.toList());        double result_time = result[2] * time_diff * time_diff + result[1]* time_diff + result[0];        System.out.println(result_time);        reader.close();    }}

这里我要解释一下  observed_data   方法

由于数据开始不知道是递增还是递减,可以先读取两个连续的温度用于判断此时是增还是减,就是下面这两行代码

double compare_item1 = Double.parseDouble(reader.readLine().split(",")[2]);double compare_item2 = Double.parseDouble(reader.readLine().split(",")[2]);

 

我这里的找周期方法思路很简单,就是先找到一个局部最低(高)点,记录此时的序号与时间

再继续沿着线向前走,下一个拐点肯定是局部最高(低)点,此时它是中间点,什么都不做

再继续的话,又到了一个局部最低(高)点,记录此时的序号与时间

现在:计算两次记录的差值,便可以知道周期点的个数,以及周期时间

对于预测,当然就可以根据预测时间与一天的起始时间差值模周期时间将其映射到第一个周期内,将余数代数拟合函数,求解近似值

到这,就可以预测温度了,比如配置时间参数

观测的真实值是:

预测结果为:

可以看出,结果还算可以(不过有些时间点的数据误差有在1-2之间的)


本节完......

转载于:https://www.cnblogs.com/xinglichao/p/9498358.html

你可能感兴趣的文章
SOCKET简单爬虫实现代码和使用方法
查看>>
跨域解决方案汇总
查看>>
In App Purchase
查看>>
js判断对象的类型的四种方式
查看>>
RPC框架的可靠性设计
查看>>
使用自选择创建团队
查看>>
基准测试(Benchmarks)不必消亡
查看>>
ceph 常用命令记录(完善中...)
查看>>
C# 7.3新特性一览
查看>>
用Chrome开发者工具调试一切
查看>>
简易mvvm库的设计实现
查看>>
AppDynamics把业务交易跟踪扩展到SAP环境
查看>>
[Three.js]Three.js中文文档-自定义混合方程常数
查看>>
Kafka 处理器客户端介绍
查看>>
通过分析这段代码的进化历程,或许能够加深您对JavaScript的作用域的理解
查看>>
创建对象(一):创建与继承
查看>>
深入浅出vue1.0:Vue 实例
查看>>
XML 实体扩展攻击
查看>>
浅谈 OneAPM 在 express 项目中的实践
查看>>
kubernetes节点选择器
查看>>