时间戳的平均值和标准偏差(时间在午夜左右)

机器算法验证 时间序列 标准差 意思是 循环统计
2022-04-03 06:16:32

我有很多带有时间戳的传感器数据,例如“2014-09-09 16:10:45”以及随附的传感器读数。为了深入了解这些,我想通过查看时间戳的时间部分的平均值和标准偏差来找到“异常”事件。我该如何处理午夜时间的环绕?

一个虚构的例子:想象一下人们在早上打开机器(功率传感器会注意到值增加)并在晚上关闭机器(减少值)影响功率读数。我想找到异常的传感器读数。这将在读数通常增加的时间段内减少传感器读数,并在读数通常减少的时间段内增加读数。

我的想法是提取时间戳的时间部分(例如 12:55:10),将其转换为秒(一天有 86400),然后除以读数的趋势(例如只看增加的读数)计算平均值和标准差。如果我然后将时间窗口从“一天中的平均秒数减去标准偏差”变为“一天中的平均秒数加上标准偏差”(可能使用标准偏差的两倍),我将有典型的时期和这段时间之外的每一个增加的读数窗口将是不寻常的。

问题:时间在午夜结束!实际上,00:15:00 的读数实际上非常接近 23:50:00,但在计算中却“相距甚远”。这肯定会扭曲统计数据,除非一切都发生在中午。有标准的做法来处理这个吗?你能给我一些想法吗?我现在完全被难住了。我很想留在 PostgresQL 中,但因为这不是必需的,所以我没有标记它。什么都有帮助!

下面是一些示例数据,每个传感器大约有 200-300 个读数。您可以看到,在此示例中,增加发生在早上。

"Timestamp as %Y-%m-%d %H:%M:%S";"Day of the year";"Second of the day";"Tendency of reading"
"2014-03-01 14:45:00";60;53100;-0.030
"2014-03-03 08:18:00";62;29880;0.150
"2014-03-03 14:17:00";62;51420;-0.120
"2014-03-03 16:37:00";62;59820;-0.030
"2014-03-04 08:11:00";63;29460;0.150
"2014-03-04 10:21:00";63;37260;-0.150
"2014-03-04 16:12:00";63;58320;-0.030
"2014-03-05 08:04:00";64;29040;0.150
"2014-03-05 14:42:00";64;52920;-0.060
"2014-03-05 17:27:00";64;62820;-0.030
"2014-03-06 08:29:00";65;30540;0.090
"2014-03-06 12:06:00";65;43560;-0.030
"2014-03-06 13:49:00";65;49740;-0.120
"2014-03-07 08:21:00";66;30060;0.150
"2014-03-07 10:27:00";66;37620;-0.030
"2014-03-07 11:27:00";66;41220;0.030
"2014-03-07 13:46:00";66;49560;-0.060
"2014-03-07 16:59:00";66;61140;-0.030
"2014-03-07 18:52:00";66;67920;-0.030
"2014-03-08 08:47:00";67;31620;0.120
2个回答

让我们使用您建议的简化:仅使用来自正读数的数据并忽略读数的值,因此我们只剩下一组循环数据。正如 whuber 建议的那样,您可以使用循环分散,可能乘以某个常数来确定应将多少数据视为异常值。一个比 Wikipedia 页面更容易理解的好文本是 Statistical Analysis of Circular data,作者 NI Fisher (1995)。

我将给出一些比 Wiki 页面更直接的公式,并给出一些示例代码。

分散度可以计算为(由于 Fisher (p.32-34)):

  1. 的估计值可以用θ={θ1,,θn}.θ¯

    • S=i=1nsin(θi) ,
    • C=i=1ncos(θi) ,
    • μ^=atan2(S,C)(见http://en.wikipedia.org/wiki/Atan2
  2. 计算R¯=S2+C2n

  3. 按照 wuber 的建议计算分散度。我不知道为什么,但维基百科的定义似乎与费舍尔略有不同。我将使用 Fisher 的:

    • δ^=1[(1/n)i=1ncos2(θiμ^)]2R¯2.
  4. 然后,选择一些常数 (1 可能很好,但您可以微调)。然后,区间由下式给出 c

    • [μ^cδ^,μ^+cδ^]

我知道你想避免使用 R,但只是为了展示如何在代码中计算它,这里有一些基本的 R 代码,它也会生成一个图:

n  <- 200
th <- runif(n, 0.5 * pi, 1.5 * pi)

plot(cos(th), sin(th), xlim=c(-1, 1), ylim = c(-1, 1))

S <- sum(sin(th))
C <- sum(cos(th))

mu_hat <- atan2(S, C)

R_bar  <- sqrt(S^2 + C^2) / n

delta_hat <- (1 - sum(cos(2 * (th-mu_hat)))/n) / (2 * R_bar^2)

constant  <- 0.8

CI <- mu_hat + c(-1, 1) * constant * delta_hat

lines(x = c(0, cos(CI[1])), 
      y = c(0, sin(CI[1])), col="green")

lines(x = c(0, cos(CI[2])), 
      y = c(0, sin(CI[2])), col="blue")

c=0.8 的截止值,来自 200 个样本的均匀半圆。

最后一点,使用读数值提供的附加信息可能仍然更好,而不仅仅是符号,因为它可以提供更好的估计。但是,仅使用符号的简化使问题更易于管理。如果有人有一个包含读数的好解决方案,我很想知道!

这可能有点愚蠢,但我只是将这些点绘制成一个圆盘:角度被认为是时间,我假设单位半径。该点云的质心角度是数据的平均角度,即尊重“午夜环绕”属性的平均时间。该值还具有最大化 von Mises 分布的位置参数的 MLE 的良好特性。

由于我们所有的点大致位于上午 5 点到下午 5 点之间,因此它们的平均值接近中午也就不足为奇了。

但是,至少目前,这是我所理解的所有循环统计数据!我希望我能给你更多的帮助,但我仍然对维基百科的文章感到困惑。

在此处输入图像描述

sec.radians <- 2*pi*sec/(60*60*24)

plot(cos(sec.radians), sin(sec.radians), xlim=c(-1, 1), ylim=c(-1, 1))

theta   <- seq(0, 2*pi, by=0.01)
lines(cos(theta), sin(theta), col="red", lty="dashed")

landmarks   <- c(2*pi, 3*pi/2, pi, pi/2)
text(0.5*cos(landmarks), 0.5*sin(landmarks), c("midnight", "6 a.m.", "noon", "6 p.m."))

centroid    <- data.frame(x=mean(cos(sec.radians)), y=mean(sin(sec.radians)))
points(centroid, col="purple", lwd=5)
theta.mean  <- atan2(centroid$y, centroid$x)