public static TimeSeriesValues Differentiate(TimeSeriesValues seq) { using (seq.Lock.GetReadLock()) { TimeSeriesValues ret = new TimeSeriesValues(seq.ColumnNames.Select(n => "diff " + n).ToArray()); for (int i = 0; i < seq.SequenceLength - 1; i++) { decimal preTime, postTime; if (!seq.TryGetTimeFromIndex(i, out preTime) || !seq.TryGetTimeFromIndex(i + 1, out postTime)) { continue; } decimal elapse = postTime - preTime; if (elapse > 0) { decimal?[] pre = seq[i]; decimal?[] post = seq[i + 1]; decimal?[] diff = new decimal?[seq.ColumnCount]; for (int j = 0; j < seq.ColumnCount; j++) { if (pre[j].HasValue && post[j].HasValue) { diff[j] = (post[j].Value - pre[j].Value) / elapse; } } ret[preTime] = diff; } } return(ret); } }
/// <summary> /// 指定されたパスのファイルからSequenceDataを作成します。拡張子は自動的に付加されます。 /// </summary> /// <param name="path"></param> /// <returns></returns> public static SequenceData RetrieveState(string path) { SequenceData ret = new SequenceData(); if (!File.Exists(path + DefaultExtensionForHeader)) { string ext = Path.GetExtension(path); if (ext == DefaultExtensionForHeader || ext == DefaultExtensionForValues || ext == DefaultExtensionForBorder) { path = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path)); if (!File.Exists(path + DefaultExtensionForHeader)) { return(null); } } else { return(null); } } string titlePath = string.Format("{0}{1}", path, DefaultExtensionForHeader); string sequencePath = string.Format("{0}{1}", path, DefaultExtensionForValues); string borderPath = string.Format("{0}{1}", path, DefaultExtensionForBorder); using (FileStream titleStream = new FileStream(titlePath, FileMode.Open)) { ret.RetrieveDataHeader(titleStream); } ret.Values = TimeSeriesValues.Deserialize(sequencePath); ret.Borders = LabelingBorders.Deserialize(borderPath); ret.IsDataChanged = false; return(ret); }
/// <summary> /// ラベル系列からデータを作成します /// </summary> /// <param name="labelSequence">ラベル系列</param> /// <param name="title">このデータに与えるタイトル</param> /// <param name="colorPalette">ラベル名からラベルの色を生成するディクショナリ</param> /// <returns></returns> public static SequenceData FromLabelSequence(ICSLabelSequence labelSequence, string title, IDictionary <string, Color> colorPalette) { if (labelSequence == null) { throw new ArgumentNullException("labelSequence", "'labelSequence' cannot be null"); } TimeSeriesValues newSeqeunce = new TimeSeriesValues(title); LabelingBorders newBorder = new LabelingBorders(); foreach (var label in labelSequence.EnumerateLabels()) { newSeqeunce[label.BeginTime] = new decimal?[] { label.BeginTime }; newBorder.SetBorder(label.BeginTime, label.LabelText); } newSeqeunce[labelSequence.Duration] = new decimal?[] { labelSequence.Duration }; newBorder.SetBorder(labelSequence.Duration, newBorder.DefaultName); if (colorPalette != null) { foreach (var pair in colorPalette) { newBorder.SetColor(pair.Key, pair.Value); } } SequenceData ret = new SequenceData(newSeqeunce, newBorder, title); ret.Type = SequenceType.Label; return(ret); }
/// <summary> /// コピーコンストラクタ /// </summary> /// <param name="original"></param> public TimeSeriesValues(TimeSeriesValues original) : this(original.ColumnNames) { foreach (var pair in original.Enumerate()) { this.SetValue(pair.Key, pair.Value); } }
/// <summary> /// データを指定するコンストラクタ /// </summary> /// <param name="sequence">時系列データ</param> /// <param name="border">ラベル境界情報</param> /// <param name="title">このデータの識別名</param> public SequenceData(TimeSeriesValues sequence, LabelingBorders border, string title) { _lockDisposable = new LockDisposable(_rwLock); this.Values = sequence; this.Borders = border; this.Title = title; this.Type = SequenceType.Numeric; this.IsDataChanged = false; }
public static TimeSeriesValues Gaussian(TimeSeriesValues seq, decimal stddev, int trialCount, decimal limitRatioToContainEmptyValue) { // stddev = time * sqrt(trial / 4) decimal time = stddev / (decimal)Math.Sqrt(0.25 * trialCount); TimeSeriesValues tmp = new TimeSeriesValues(seq); for (int i = 0; i < trialCount; i++) { tmp = TimeSmooth(tmp, time * 2, -time, limitRatioToContainEmptyValue); } return(tmp); }
public static TimeSeriesValues Deserialize(Stream stream) { CSVReader reader = new CSVReader(stream); TimeSeriesValues ret = null; int count = 0; while (!reader.EndOfStream) { count++; string[] row = reader.ReadValues(); if (row.Length == 0) { continue; } string trimmed = row[0].Trim(); if (trimmed.StartsWith("#")) { if (ret == null && trimmed.Substring(1).Trim().ToLower() == "name") { ret = new TimeSeriesValues(row.Skip(1).ToArray()); } continue; } decimal time; if (!decimal.TryParse(row[0], out time)) { throw new InvalidDataException("Invalid value at line " + count.ToString()); } decimal?[] values = new decimal?[row.Length - 1]; for (int i = 1; i < row.Length; i++) { decimal value; if (decimal.TryParse(row[i], out value)) { values[i - 1] = value; } } if (ret == null) { ret = new TimeSeriesValues(row.Length - 1); } ret[time] = values; } // ファイルが空ならばretはnull if (ret != null) { ret.TrimExcess(); } return(ret); }
public static TimeSeriesValues Aggregate(TimeSeriesValues seq, decimal?initialValue, Func <decimal?, decimal?, decimal?> aggregator, Func <decimal?, decimal?> finalizer) { using (seq.Lock.GetReadLock()) { TimeSeriesValues ret = new TimeSeriesValues(1); foreach (var pair in seq.Enumerate()) { decimal?aggregation = initialValue; foreach (var value in pair.Value) { aggregation = aggregator(aggregation, value); } ret[pair.Key] = new decimal?[] { finalizer(aggregation) }; } return(ret); } }
/* * public static TimeSeriesValueData Gaussian(TimeSeriesValueData seq, decimal stddev, decimal limitRatioToContainEmptyValue) { * TimeSeriesValueData tmp = new TimeSeriesValueData(seq.ColumnNames); * double dLimit = (double)limitRatioToContainEmptyValue; * double dStddev = (double)stddev; * foreach(var pair in seq.Enumerate()) { * double[] valueSum = new double[seq.ColumnCount]; * double[] timeSum = new double[seq.ColumnCount]; * double[] lackSum = new double[seq.ColumnCount]; * foreach(var row in seq.EnumerateRows(pair.Key - stddev * 3, pair.Key + stddev * 3)) { * double dDuration = (double)row.Duration(); * decimal centerTime = (row.BeginTime + row.EndTime) / 2; * double diffTime = (double)(centerTime - pair.Key); * double gauss = 1; * //(double)Math.Exp(-diffTime * diffTime / (2.0 * dStddev * dStddev)); * for(int i = 0; i < seq.ColumnCount; i++) { * double coef = dDuration * gauss; * timeSum[i] += coef; * if(row.Values[i].HasValue) { * valueSum[i] += (double)row.Values[i].Value * coef; * } else { * lackSum[i] += coef; * } * } * } * decimal?[] values = new decimal?[seq.ColumnCount]; * for(int i = 0; i < seq.ColumnCount; i++) { * if(timeSum[i] - lackSum[i] > 0 && lackSum[i] <= dLimit * timeSum[i]) { * try { * values[i] = (decimal)(valueSum[i] / (timeSum[i] - lackSum[i])); * } catch(ArithmeticException) { } * } * } * tmp[pair.Key] = values; * } * return tmp; * } */ public static TimeSeriesValues GetResampled(TimeSeriesValues seq, decimal interval) { using (seq.Lock.GetReadLock()) { decimal min = seq.BeginTime; decimal max = seq.EndTime; TimeSeriesValues ret = new TimeSeriesValues(seq.ColumnNames); for (decimal time = min; time < max + interval; time += interval) { var values = seq[time]; if (values != null) { ret[time] = values; } } return(ret); } }
public static TimeSeriesValues FrameMean(TimeSeriesValues seq, int meanLength) { using (seq.Lock.GetReadLock()) { if (meanLength <= 0) { throw new ArgumentOutOfRangeException("meanLength", "meanLength > 0"); } TimeSeriesValues ret = new TimeSeriesValues(seq.ColumnNames.Select(n => "mean " + n).ToArray()); for (int i = 0; i < seq.SequenceLength - meanLength; i++) { decimal?[] mean = new decimal?[seq.ColumnCount]; for (int j = 0; j < seq.ColumnCount; j++) { mean[j] = 0; } for (int j = 0; j < seq.ColumnCount; j++) { mean[j] = 0; for (int k = 0; k < meanLength; k++) { decimal?value = seq[i + k][j]; if (value.HasValue) { mean[j] += value.Value; } else { mean[j] = null; break; } } if (mean[j].HasValue) { mean[j] /= meanLength; } } decimal time; if (seq.TryGetTimeFromIndex(i, out time)) { ret.SetValue(time, mean); } } return(ret); } }
public static TimeSeriesValues OperateWith(TimeSeriesValues seq, TimeSeriesValues operand, Func <decimal?, decimal?, decimal?> operation) { if (operand == null) { throw new ArgumentNullException("operand", "'operand' cannot be null"); } int count = Math.Min(seq.ColumnCount, operand.ColumnCount); TimeSeriesValues ret = new TimeSeriesValues(seq.ColumnNames.Take(count).ToArray()); using (IEnumerator <KeyValuePair <decimal, decimal?[]> > one = seq.Enumerate().GetEnumerator()) using (IEnumerator <KeyValuePair <decimal, decimal?[]> > another = operand.Enumerate().GetEnumerator()) { bool oneAlive = one.MoveNext(); bool anotherAlive = another.MoveNext(); while (oneAlive && anotherAlive) { decimal?[] values = new decimal?[count]; for (int i = 0; i < count; i++) { if (one.Current.Value[i].HasValue && another.Current.Value[i].HasValue) { values[i] = operation(one.Current.Value[i].Value, another.Current.Value[i].Value); } } // 後にある時刻のところに値を入れる // 前にある方を進める if (one.Current.Key < another.Current.Key) { ret.SetValue(another.Current.Key, values); oneAlive = one.MoveNext(); } else { ret.SetValue(one.Current.Key, values); anotherAlive = another.MoveNext(); } } } return(ret); }
public static TimeSeriesValues AverageFlat(TimeSeriesValues seq, bool keepEmpty) { using (seq.Lock.GetReadLock()) { TimeSeriesValues ret = new TimeSeriesValues(seq.ColumnNames.Select(n => "avg " + n).ToArray()); decimal?[] tmp1 = new decimal?[seq.ColumnCount]; int[] counts = new int[seq.ColumnCount]; for (int i = 0; i < seq.ColumnCount; i++) { counts[i] = 0; } for (int i = 0; i < seq.ColumnCount; i++) { tmp1[i] = 0; } try { foreach (var pair in seq.Enumerate()) { for (int i = 0; i < pair.Value.Length; i++) { if (pair.Value[i].HasValue) { tmp1[i] += pair.Value[i].Value; counts[i]++; } } } for (int i = 0; i < seq.ColumnCount; i++) { if (counts[i] == 0) { tmp1[i] = null; } else { tmp1[i] /= counts[i]; } } } catch (OverflowException) { // doubleで集計してdecimalにキャスト double?[] tmp2 = new double?[seq.ColumnCount]; for (int i = 0; i < seq.ColumnCount; i++) { tmp2[i] = 0; } for (int i = 0; i < seq.ColumnCount; i++) { counts[i] = 0; } foreach (var pair in seq.Enumerate()) { for (int i = 0; i < pair.Value.Length; i++) { if (pair.Value[i].HasValue) { tmp2[i] += (double)pair.Value[i].Value; counts[i]++; } } } for (int i = 0; i < seq.ColumnCount; i++) { if (counts[i] == 0) { tmp1[i] = null; } else { try { tmp1[i] = (decimal)(tmp2[i] / counts[i]); } catch (OverflowException) { tmp1[i] = null; } } } } foreach (var pair in seq.Enumerate()) { decimal?[] tmp3 = new decimal?[seq.ColumnCount]; for (int i = 0; i < seq.ColumnCount; i++) { if (pair.Value[i].HasValue || !keepEmpty) { tmp3[i] = tmp1[i]; } } ret[pair.Key] = tmp3; } return(ret); } }
/// <summary> /// シーケンスの移動平均を求めます /// </summary> /// <param name="seq">シーケンス</param> /// <param name="smoothSpan">移動平均を取る時間範囲</param> /// <param name="timeOffset">出力の時間のオフセット.0で時間範囲の終了点の時間,smoothSpanの値で時間範囲の開始点の時間のところに出力される</param> /// <param name="limitRatioToContainEmptyValue">データの欠損があっても値を出力する限界率(0~1)</param> /// <returns></returns> public static TimeSeriesValues TimeSmooth(TimeSeriesValues seq, decimal smoothSpan, decimal timeOffset, decimal limitRatioToContainEmptyValue) { using (seq.Lock.GetReadLock()) { if (smoothSpan < 0) { throw new ArgumentOutOfRangeException("time", "'time' cannot be negative"); } TimeSeriesValues ret = new TimeSeriesValues(seq.ColumnNames); int[] nullCount = new int[seq.ColumnCount]; decimal[] sum = new decimal[seq.ColumnCount]; int count = 0; int beginIndex = 0; for (int endIndex = 0; endIndex < seq.SequenceLength; endIndex++) { decimal endTime; if (!seq.TryGetTimeFromIndex(endIndex, out endTime)) { continue; } for (int j = 0; j < seq.ColumnCount; j++) { if (seq[endIndex][j].HasValue) { sum[j] += seq[endIndex][j].Value; } else { nullCount[j]++; } } count++; decimal beginTime; while (beginIndex < endIndex && seq.TryGetTimeFromIndex(beginIndex, out beginTime)) { if (beginTime > endTime - smoothSpan) { break; } for (int j = 0; j < seq.ColumnCount; j++) { if (seq[beginIndex][j].HasValue) { sum[j] -= seq[beginIndex][j].Value; } else { nullCount[j]--; } } count--; beginIndex++; } Debug.Assert(nullCount.Max() <= count); Debug.Assert(count > 0); decimal?[] values = new decimal?[seq.ColumnCount]; for (int j = 0; j < seq.ColumnCount; j++) { decimal rate = (decimal)nullCount[j] / count; int validCount = count - nullCount[j]; if (rate <= limitRatioToContainEmptyValue && validCount > 0) { values[j] = sum[j] / validCount; } else { values[j] = null; } } ret[endTime + timeOffset] = values; } return(ret); } }
public static TimeSeriesValues AbsoluteLength(TimeSeriesValues seq) { return(Aggregate(seq, 0M, (a, n) => (a.HasValue && n.HasValue) ? (decimal?)(a.Value + n.Value * n.Value) : null, a => a.HasValue ? (decimal?)Math.Sqrt((double)a.Value) : null)); }
public void SetItemsFromSequenceValues(TimeSeriesValues values) { this.SetItems(values.ColumnNames); }
/// <summary> /// ストリームからデータを復元します /// </summary> /// <param name="reader"></param> /// <returns></returns> public static SequenceData Deserialize(XmlReader reader) { SequenceData ret = null; reader.ReadStartElement(typeof(SequenceData).Name); byte[] titleBytes = null, sequenceBytes = null; LabelingBorders border = null; string tmp; MemoryStream tmpStream; StreamWriter tmpWriter; for (reader.MoveToContent(); reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.None; reader.MoveToContent()) { if (reader.IsEmptyElement) { reader.Skip(); continue; } switch (reader.Name) { case "Title": tmp = reader.ReadElementContentAsString(); tmpStream = new MemoryStream(); tmpWriter = new StreamWriter(tmpStream); tmpWriter.Write(tmp); tmpWriter.Flush(); titleBytes = tmpStream.ToArray(); break; case "Sequence": tmp = reader.ReadElementContentAsString(); tmpStream = new MemoryStream(); tmpWriter = new StreamWriter(tmpStream); tmpWriter.Write(tmp); tmpWriter.Flush(); sequenceBytes = tmpStream.ToArray(); break; case "Border": reader.ReadStartElement(); border = LabelingBorders.Deserialize(reader.ReadSubtree()); for (reader.MoveToContent(); reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.None; reader.MoveToContent()) { reader.Skip(); } reader.ReadEndElement(); break; default: reader.Skip(); break; } } reader.ReadEndElement(); if (titleBytes != null && sequenceBytes != null && border != null) { ret = new SequenceData(); ret.Borders = border; using (MemoryStream stream2 = new MemoryStream(sequenceBytes)) { ret.Values = TimeSeriesValues.Deserialize(stream2); } using (MemoryStream stream2 = new MemoryStream(titleBytes)) { ret.RetrieveDataHeader(stream2); } } return(ret); }