[java] 数据处理
背景:
有一组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之间的)
本节完......
[java] 数据处理的更多相关文章
- Java数据处理
对于形如“(TYPE=SITA##)&&(((CTYP=FPL##)||(CTYP=CHG##)||(CTYP=CNL##)||(CTYP=DLA##)||(CTYP=DL##)||( ...
- JAVA数据处理的常用技术
背景 在实际开发中,数据的处理有五种:获取.传输.存储.分析.转换.每种各对应一些常用的技术. 序列化和反序列化 序列化是将对象的信息转换为可传输或可存储形式的过程.反序列化就是反过来让这些可传输的. ...
- Java数据处理,Map中数据转double并取小数点后两位
BigDecimal order = (BigDecimal) map.get("finishrat"); double d = (order == null ? 0 : orde ...
- Java架构师之路 Spring学习笔记(一) Spring介绍
前言 这是一篇原创的Spring学习笔记.主要记录我学习Spring4.0的过程.本人有四年的Java Web开发经验,最近在面试中遇到面试官总会问一些简单但我不会的Java问题,让我觉得有必要重新审 ...
- Java编程实战宝典PDF (中文版带书签)
Java编程实战宝典PDF 目录 第1篇 Java基础知识入门第1章 Java的开发运行环境( 教学视频:57分钟)1.1 Java运行原理与Java虚拟机1.1.1 Java运行原理简述1.1.2 ...
- Spring框架快速入门之简介
Spring是java平台上的一个开源应用框架.它的第一个版本是由Rod Johnson写出来的.Rod在他的Expert One-On- One Java EE Design and Develop ...
- 转:eval(data)和eval("("+data+")")
http://www.w3school.com.cn/jsref/jsref_eval.asp JavaScript eval() 函数:eval() 函数可计算某个字符串,并执行其中的的 JavaS ...
- Hadoop MapReduce编程 API入门系列之Crime数据分析(二十五)(未完)
不多说,直接上代码. 一共12列,我们只需提取有用的列:第二列(犯罪类型).第四列(一周的哪一天).第五列(具体时间)和第七列(犯罪场所). 思路分析 基于项目的需求,我们通过以下几步完成: 1.首先 ...
- Spring学习【Spring概述】
从本文開始,我们就要一起学习Spring框架,首先不得不说Spring框架是一个优秀的开源框架. 当中採用IoC原理实现的基于Java Beans的配置管理和AOP的思想都是非常值得学习与使用的.以下 ...
随机推荐
- bzoj1018/luogu4246 堵塞的交通 (线段树)
对于一个区间四个角的点,可以用线段树记下来它们两两的联通情况 区间[l,r]通过两个子区间[l,m],[m+1,r]来更新,相当于合并[l,m],[m+1,r],用(m,m+1)这条边来合并 查询a, ...
- nowcoder106I Neat Tree (单调栈)
Richard神犇出给nowcoder的题 用单调栈找到每个点它向右和向左的第一个大于或小于它的位置,然后它作为最大值/最小值的区间就要在这个范围里,那么它的贡献就是这个区间长度乘一乘再减一减 注意一 ...
- 【uoj428】普通的计数题
Portal --> uoj428 Solution 不会胖子的一个log正解qwq只能怂怂滴写分治了qwq 首先就是一个我想不到的转化qwq 我们将第\(i\)次操作加入的数看成一个编 ...
- Java中如何遍历Map对象
方法一:使用map.entrySet()来遍历.这是最常见的并且在大多数情况下也是最可取的遍历方式.在键值都需要的时候使用. Map<String,String> map = new Ha ...
- VUE.JS 窗口发生变化时,获取当前窗口的高度。
VUE.JS # 窗口发生变化时,获取当前窗口的高度. mounted () { const that = this; window.onresize = () => { return (() ...
- gtest简介及简单使用
本文摘自 gtest简介及简单使用 ,在此感谢作者的分享. 具体使用教程 _______________________________________________________________ ...
- Qt error ------ qRegisterMetaType() 跨线程信号与槽的形参携带
Qt提示: QObject::connect: Cannot queue arguments of type 'FrequencySpectrum' (Make sure 'FrequencySpec ...
- element-ui合并行:span-method
objectSpanMethod({ row, column, rowIndex, columnIndex }) { if (columnIndex === 0) { if (rowIndex % 2 ...
- POJ - 1094 Sorting It All Out(拓扑排序)
https://vjudge.net/problem/POJ-1094 题意 对于N个大写字母,给定它们的一些关系,要求判断出经过多少个关系之后可以确定它们的排序或者排序存在冲突,或者所有的偏序关系用 ...
- 用Java构建一个简单的WebSocket聊天项目之新增HTTP接口调度
采用框架 我们整个Demo基本不需要大家花费太多时间,就可以实现以下的功能. 用户token登录校验 自我聊天 点对点聊天 群聊 获取在线用户数与用户标签列表 发送系统通知 首先,我们需要介绍一下我们 ...