[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的思想都是非常值得学习与使用的.以下 ...
随机推荐
- uva11235 FrequentValues (ST表)
既然他是非降的,那我们可以把这个序列每一位转化成到这位位置连续相同的个数,比如001111233444变成121234112123,然后一个区间内的最大值就是众数的位数.但有个问题,就是这个区间的左端 ...
- java JNative调用DLL中带引用类型的方法
DLL中的被调函数有两个参数,第二个参数是int64类型的引用类型,因此创建8byte的MemoryBlock: JNative n = null; try { n = new JNative( ...
- NOIP2017 列队——动态开点线段树
Description: Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n×m名学生,方阵的行数为 ...
- GROUP BY和 HAVING 及 统计函数 执行顺序等
[我理解:where是对最外层结果进行条件筛选,而having是对分组时分组中的数据进行 组内条件筛选,注意:只能进行筛选,不能进行统计或计算,所有统计或计算都要放在最外层的select 后面,无论是 ...
- kubernetes配置secret拉取私仓镜像
2017.05.10 19:48* 字数 390 阅读 5216评论 0喜欢 8 对于公司内部的项目, 我们不可能使用公有开放的镜像仓库, 一般情况可能会花钱买docker私仓服务, 或者说自己在服务 ...
- python爬虫requests过程中添加headers
浏览器中打开页面,以edge为例,点击“查看源”或F12 第一步:点击上图中“网络”标签,然后刷新或载入页面 第二步:在右侧“标头”下方的“请求标头”中的所有信息都是headers内容,添加到requ ...
- Dubbo学习笔记6:Dubbo增强SPI与SPI中扩展点自动包装的实现原理
在Dubbo整体架构分析中介绍了Dubbo中除了Service和Config层为API外,其他各层均为SPI,为SPI意味着下面各层都是组件化可以被替换的,也就是扩展性比较强,这也是Dubbo比较好的 ...
- Web性能优化系列(2):剖析页面绘制时间
本文由 伯乐在线 - J.c 翻译,sunbiaobiao 校稿.未经许可,禁止转载!英文出处:www.deanhume.com.欢迎加入翻译小组. 最近,我参加了在伦敦举办的Facebook移动开发 ...
- BFS的队列
按老师上课的话来总结,队列变化多端: 普通模板没有代价: 普通队列FIFO 01代价: 双端队列,单调队列 任意代价: 优先队列/堆,最短路SPFA/DIJKSTRA
- 利用itertools生成密码字典,多线程撞库破解rar压缩文件密码
脚本功能: 利用itertools生成密码字典(迭代器形式) 多线程并发从密码字典中取出密码进行验证 验证成功后把密码写入文件中保存 #!/usr/bin/env python # -*- codin ...