/*
* Copyright 2015, Yahoo Inc.
* Copyrights licensed under the GPL License.
* See the accompanying LICENSE file for terms.
*/
// data structure for time series data
package com.yahoo.egads.data;
import java.io.Serializable;
import java.util.ArrayList;
import org.json.JSONObject;
import org.json.JSONStringer;
public class TimeSeries implements JsonAble, Serializable {
// inner class ////////////////////////////////////////////////
public static class Entry implements JsonAble, Serializable {
public long time = 0;
public float value = 0;
public long logicalIndex = 0;
public Entry() {
}
public Entry(long time_arg, float value_arg) {
time = time_arg;
value = value_arg;
}
public Entry(TimeSeries.Entry e) {
time = e.time;
logicalIndex = e.logicalIndex;
value = e.value;
}
public void toJson(JSONStringer json_out) throws Exception {
JsonEncoder.toJson(this, json_out);
}
public void fromJson(JSONObject json_obj) throws Exception {
JsonEncoder.fromJson(this, json_obj);
}
public boolean equals(Object other_obj) {
if (!(other_obj instanceof Entry)) {
return false;
}
Entry other = (Entry) other_obj;
if (time != other.time) {
return false;
}
if (value != other.value) {
return false;
}
if (logicalIndex != other.logicalIndex) {
return false;
}
return true;
}
}
public static class DataSequence extends ArrayList implements Serializable {
private static final long serialVersionUID = 1L;
public DataSequence() {
super();
}
public DataSequence(long from, long to, long period) throws Exception {
super();
if (to < from) {
throw new Exception("The start time should be before the end time.");
}
for (long i = from; i <= to; i += period) {
this.add(new Entry(i, 0));
}
}
public DataSequence(int initialCapacity) {
super(initialCapacity);
}
public DataSequence(float[] values) {
super();
for (int i = 0; i < values.length; ++i) {
this.add(new Entry(i, values[i]));
}
}
public DataSequence(float value) {
super();
this.add(new Entry(0, value));
}
public DataSequence(Long[] times, Float[] values) throws Exception {
super();
if (times.length != values.length) {
throw new Exception("Length mismatch!");
}
for (int i = 0; i < values.length; ++i) {
if (i > 0 && times[i] < times[i - 1]) {
throw new Exception("time=" + times[i] + " at index=" + i + " out of order");
}
this.add(new Entry(times[i], values[i]));
}
}
public DataSequence(long time, float value) {
super();
this.add(new Entry(time, value));
}
public void setLogicalIndices(long firstTimeStamp, long period) {
for (TimeSeries.Entry entry : this) {
entry.logicalIndex = (entry.time - firstTimeStamp) / period;
}
}
public Float[] getValues() {
Float[] fArray = new Float[this.size()];
for (int i = 0; i < this.size(); i++) {
fArray[i] = this.get(i).value;
}
return fArray;
}
public Long[] getTimes() {
Long[] lArray = new Long[this.size()];
for (int i = 0; i < this.size(); i++) {
lArray[i] = (long) this.get(i).time;
}
return lArray;
}
public void setTimeStamps(long firstTimeStamp, long period) {
for (TimeSeries.Entry entry : this) {
entry.time = entry.logicalIndex * period + firstTimeStamp;
}
}
public boolean equals(Object other_obj) {
if (!(other_obj instanceof DataSequence)) {
return false;
}
DataSequence other = (DataSequence) other_obj;
if (!super.equals(other)) {
return false;
}
return true;
}
}
// member data ////////////////////////////////////////////////
public DataSequence data = new DataSequence();
public MetricMeta meta = new MetricMeta();
// construction ////////////////////////////////////////////////
public TimeSeries() {
}
public TimeSeries(float[] values) {
for (int i = 0; i < values.length; ++i) {
data.add(new Entry(i, values[i]));
}
}
public TimeSeries(float value) {
data.add(new Entry(0, value));
}
public TimeSeries(long[] times, float[] values) throws Exception {
if (times.length != values.length) {
throw new Exception("Length mismatch!");
}
for (int i = 0; i < values.length; ++i) {
if (i > 0 && times[i] < times[i - 1]) {
throw new Exception("time=" + times[i] + " at index=" + i + " out of order");
}
data.add(new Entry(times[i], values[i]));
}
}
// Aggregates time-series based on the specified frequency.
public DataSequence aggregate(int frequency) {
DataSequence ldata = new DataSequence();
for (int i = 0; i < data.size(); i += frequency) {
Float aggr = (float) 0.0;
Long time = data.get(i).time;
int count = 0;
for (int j = i; j < Math.min(data.size(), (i + frequency)); j++) {
aggr += (float) data.get(j).value;
count++;
}
aggr = aggr / (float) count;
ldata.add(new Entry(time, aggr));
}
return ldata;
}
public TimeSeries(long time, float value) {
data.add(new Entry(time, value));
}
// methods: data access ////////////////////////////////////////////////
public void append(long time, float value) throws Exception {
if (size() > 0 && time < lastTime()) {
throw new Exception("time=" + time + " at index=" + size() + " out of order");
}
data.add(new Entry(time, value));
}
public int size() {
return data.size();
}
public long startTime() {
return data.get(0).time;
}
public long lastTime() {
return data.get(data.size() - 1).time;
}
public long time(int index) {
return data.get(index).time;
}
public float value(int index) {
return data.get(index).value;
}
public long // may return 0 if size < 2
minimumPeriod() {
if (size() < 2) {
return 0;
}
long minPeriod = -1;
for (int i = 1; i < size(); ++i) {
long period = time(i) - time(i - 1);
if (minPeriod == -1 || period < minPeriod) {
minPeriod = period;
}
}
return minPeriod;
}
protected class PeriodAndCount implements Serializable {
public long period = 0;
public int count = 0;
public PeriodAndCount(long period_arg, int count_arg) {
period = period_arg;
count = count_arg;
}
}
// may return 0 if size < 2
public long mostFrequentPeriod() {
if (size() < 2) {
return 0;
}
ArrayList periods = new ArrayList();
// for each time...
for (int i = 1; i < size(); ++i) {
// increment period count
long period = time(i) - time(i - 1);
boolean found = false;
for (int p = 0; p < periods.size(); ++p) {
PeriodAndCount pc = periods.get(p);
if (pc.period == period) {
found = true;
++pc.count;
}
}
if (!found) {
periods.add(new PeriodAndCount(period, 1));
}
}
// find most frequent period
int maxCount = 0;
long maxPeriod = 0;
for (int p = 0; p < periods.size(); ++p) {
PeriodAndCount pc = periods.get(p);
if (pc.count > maxCount) {
maxCount = pc.count;
maxPeriod = pc.period;
}
}
return maxPeriod;
}
// display ////////////////////////////////////////////////
public String toString() {
StringBuffer str = new StringBuffer();
for (int i = 0; i < data.size(); ++i) {
if (i > 0) {
str.append(",");
}
str.append("[" + time(i) + ":" + value(i) + "]");
}
return str.toString();
}
public void toJson(JSONStringer json_out) throws Exception {
JsonEncoder.toJson(this, json_out);
}
public void fromJson(JSONObject json_obj) throws Exception {
JsonEncoder.fromJson(this, json_obj);
}
public boolean equals(Object other_obj) {
if (!(other_obj instanceof TimeSeries)) {
return false;
}
TimeSeries other = (TimeSeries) other_obj;
if (!MetricMeta.equals(data, other.data)) {
return false;
}
if (!MetricMeta.equals(meta, other.meta)) {
return false;
}
return true;
}
}
Ads help maintain this website.