c# - 在时间序列中查找开始和停止
问题描述
我想了解是否有办法使用 linq exp 查找给定时间序列的所有开始和停止窗口(由开始和结束值分隔)。我知道这可以通过正常循环来实现,但如果可能的话,我喜欢扩展我的知识。
数据存储在“TagData”(List<TagData>
)的有序列表中
class TagData
{
public DateTime Timestamp { get; set; }
public string Tag { get; set; }
public double Value { get; set; }
}
当数据的内容完美交替时,最简单的方法是:
timestamp | tag | value
2018-12-01 00:10:00.000 | extrg_01 | 1
2018-12-01 00:15:02.000 | extrg_01 | 0
2018-12-01 00:25:50.000 | extrg_01 | 1
2018-12-01 00:45:11.000 | extrg_01 | 0
此时给定初始值 = 1 和最终值 = 0,结果将是以下几行:
timestamp_start |timestamp_end | tag | nrOfSeconds
2018-12-01 00:10:00.000 |2018-12-01 00:15:02.000 | extrg_01 | 302
2018-12-01 00:25:50.000 |2018-12-01 00:45:01.000 | extrg_01 | 1161
但也可能有一些不需要考虑的“脏”数据:
timestamp | tag | value
2018-12-01 00:10:00.000 | extrg_01 | 1
2018-12-01 00:12:02.000 | extrg_01 | 1
2018-12-01 00:15:02.000 | extrg_01 | 0
2018-12-01 00:16:01.000 | extrg_01 | 0
2018-12-01 00:25:50.000 | extrg_01 | 1
2018-12-01 00:45:11.000 | extrg_01 | 0
在这种情况下,最终结果不应与第一个示例不同,因为不考虑定义的初始值(在这种情况下是 = 1)之后的所有值,同样,只有第一个最终值(在这种情况下是 = 0)将被考虑用于计算。
我忘记添加我正在尝试编辑的 linq 表达式以实现结果:不幸的是,我无法理解如何在此 .Zip 中添加 where 条件(如果可能的话)以查找特定值并尊重 a总是找到下一个可用值的时间条件。
var diffs = tagDataList.Skip(1)
.Zip(tagDataList,
(curr, prev) => new
{
CurrTag = curr.Tag,
CurrValue = curr.Value,
CurrDate = curr.Timestamp,
PrevDate = prev.Timestamp,
DiffToPrev = Math.Abs((curr.Timestamp - prev.Timestamp).TotalSeconds)
})
.ToList();
解决方案
可能有很多方法可以做到这一点。我会试一试:
我假设您希望单独处理不同的标签。这是我的方法:
- 按标签对条目进行分组。
- 对于每个组:
- 从列表的开头删除所有值为 0 的条目。
- 如果有两个或多个具有相同值的相邻条目,则只保留第一个。
- 现在我们有一个从 1 开始并在 1 和 0 之间交替的列表。
- 将 1 与 0 一起压缩以计算时间跨度。
- 最后将每组的所有结果展平
我使用了这个测试数据:
var list = new List<TagData> {
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:09:00.000"), Tag = "extrg_01", Value = 0 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:10:00.000"), Tag = "extrg_01", Value = 1 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:10:00.000"), Tag = "extrg_02", Value = 1 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:12:02.000"), Tag = "extrg_01", Value = 1 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:15:02.000"), Tag = "extrg_01", Value = 0 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:16:01.000"), Tag = "extrg_01", Value = 0 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:15:02.000"), Tag = "extrg_02", Value = 0 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:25:50.000"), Tag = "extrg_01", Value = 1 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:45:11.000"), Tag = "extrg_01", Value = 0 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:25:50.000"), Tag = "extrg_02", Value = 1 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:45:11.000"), Tag = "extrg_02", Value = 0 },
};
类定义:
class TagData
{
public DateTime Timestamp { get; set; }
public string Tag { get; set; }
public double Value { get; set; }
}
class TagSummary
{
public DateTime TimestampStart { get; set; }
public DateTime TimestampEnd { get; set; }
public string Tag { get; set; }
public TimeSpan TimeSpan => TimestampEnd - TimestampStart;
}
代码:
var summaries =
list.GroupBy(tagdata => tagdata.Tag) // Step (1)
.Select(group => // Step (2)
{
var data = group
.SkipWhile(tagdata => tagdata.Value == 0) // Step (2.1)
.Aggregate(new List<TagData>(), (acc, tagdata) => // Step (2.2)
{
if (acc.LastOrDefault()?.Value != tagdata.Value)
acc.Add(tagdata);
return acc;
});
var ones = data.Where(datatag => datatag.Value == 1);
var zeros = data.Where(datatag => datatag.Value == 0);
var result = ones.Zip(zeros, (startTag, endTag) => { // Step (2.3)
return new TagSummary { TimestampStart = startTag.Timestamp, TimestampEnd = endTag.Timestamp, Tag = startTag.Tag };
});
return result;
})
.SelectMany(x => x); // Step (3)
Console.WriteLine("timestamp_start | timestamp_end | tag | nrOfSeconds");
foreach (var summary in summaries)
Console.WriteLine($"{summary.TimestampStart:yyyy-MM-dd HH:mm:ss} | {summary.TimestampEnd:yyyy-MM-dd HH:mm:ss} | {summary.Tag,-8} | {summary.TimeSpan.TotalSeconds:0}");
输出与您指定的一样:
timestamp_start | timestamp_end | tag | nrOfSeconds
2018-12-01 00:10:00 | 2018-12-01 00:15:02 | extrg_01 | 302
2018-12-01 00:25:50 | 2018-12-01 00:45:11 | extrg_01 | 1161
2018-12-01 00:10:00 | 2018-12-01 00:15:02 | extrg_02 | 302
2018-12-01 00:25:50 | 2018-12-01 00:45:11 | extrg_02 | 1161
推荐阅读
- python - Plotly:使用 plotly.express 的“线条+标记”模式的交互式图形
- ios - React Native中类“艺术画笔”的重复接口定义
- html - 保证金:自动;即使在指定宽度后也不起作用?
- python-3.x - 当我创建一个 Python 函数来合并两个数据框并单独输入值时,它可以工作。但是当我做一个循环时,我得到一个关键错误
- java - C类实现了接口B,它扩展了接口A,你能说C实现了A吗?
- angular - 如何在打字稿(Angular)中数组的特定索引处向对象添加属性?
- javascript - JavaScript/HTML:为什么不显示结果?
- javascript - 如何使用firebase处理reactjs中的令牌过期并在axios拦截器中传递idToken?
- django - 我想在我的 django 项目中提供具有权限逻辑的静态文件
- postgresql - 删除 postgresql 中的引用值