【问题标题】:Calculate average of a subset of a vector only when subset values meet a condition in R?仅当子集值满足R中的条件时才计算向量子集的平均值?
【发布时间】:2021-10-12 16:57:17
【问题描述】:

我有一条每日曲线 x,我试图逼近 x 的平均峰值和非峰值: https://ibb.co/Fq1Byzk

我已经定义了一个 delta 阈值,这样当 delta 低于阈值时,x 将处于非高峰期或高峰期。我想获得平均峰值,其中平均值仅是 delta

delta <- matrix(0,24,ncol=1)

for (i in 2:24){
  # i-th element is the i-th hour per day
  delta[i] = x[i,2]-x[i-1,2]
}

# Find hour at which max and min daily values occur
max_threshold = 0.15*max(delta)
min_threshold = 0.15*min(delta)
c <- abs(delta) < max_threshold

t1 <- which(delta>max_threshold)[1]-1 # t1: time index at end of off-peak
t2 <- which.max(delta) + 1 # t2 is time of initial peak
t3 <- which.min(delta)-2 # t3 is time of end peak
t4 <- which.min(delta) # t4 time index of evening off-peak

am <- mean(x[1:t1,2]) # average morning off-peak value
peak <- mean(x[t2:t3,2]) #average peak value
pm <- mean(x[t4:24,2]) # average evening off-peak value
> dput(x)
structure(list(time = structure(c(1451952000, 1451955600, 1451959200, 
1451962800, 1451966400, 1451970000, 1451973600, 1451977200, 1451980800, 
1451984400, 1451988000, 1451991600, 1451995200, 1451998800, 1452002400, 
1452006000, 1452009600, 1452013200, 1452016800, 1452020400, 1452024000, 
1452027600, 1452031200, 1452034800, 1452038400, 1452042000, 1452045600, 
1452049200, 1452052800, 1452056400, 1452060000, 1452063600, 1452067200, 
1452070800, 1452074400, 1452078000, 1452081600, 1452085200, 1452088800, 
1452092400, 1452096000, 1452099600, 1452103200, 1452106800, 1452110400, 
1452114000, 1452117600, 1452121200), class = c("POSIXct", "POSIXt"
), tzone = "UTC"), Crow_education_Omer = c(0.019186330898848, 
0.0192706664192825, 0.0182164724138513, 0.018174304653634, 0.019355001939717, 
0.0197345117816722, 0.023951287803397, 0.0323848398468467, 0.0343245568168401, 
0.0378244809148717, 0.0393003525224754, 0.0403545465279066, 0.0405232175687756, 
0.0393425202826927, 0.0398907011655169, 0.0377401453944372, 0.0344932278577091, 
0.0317101556833707, 0.0304872906370705, 0.0297282709531601, 0.0287584124681633, 
0.0252584883701317, 0.0196080085010205, 0.0197345117816722, 0.0194815052203687, 
0.0196080085010205, 0.0184273112149375, 0.0184694789751548, 0.0191441631386307, 
0.019692344021455, 0.025469327171218, 0.0352522475416196, 0.0376136421137855, 
0.0403967142881239, 0.0435592963044175, 0.0433484575033313, 0.0430532831818105, 
0.042968947661376, 0.043306289743114, 0.044655658070066, 0.0424207667785518, 
0.0416195793344241, 0.0382883262772615, 0.03769797763422, 0.0330173562501054, 
0.0281680638251219, 0.0234452746807901, 0.0225597517162278)), row.names = 97:144, class = "data.frame")

另外,我如何能够在同一张图上同时绘制新的简化曲线和原始曲线 x?由于我的时间列是 POSIXCT,因此我似乎无法使用 x 减少数据点数量来融化或 rbind() 新曲线。

谢谢。

【问题讨论】:

  • 您能否解释一下我想获得平均峰值,其中平均值仅是 x 内的值,其中 delta 稍微远一点?例如:您只想在am 中包含x[1:t1,2] 的值,其delta &lt; max_threshold? min_threshold呢?
  • 例如,我希望我的平均峰值仅包括从上午 10:00 到 14:00 的值,因为在 10:00 到 14:00 之间计算的增量小于我的 max_threshold 值 ~ 0.002。现在我的平均峰值包括从 t2 到 t3 的所有内容。我计算了 max_threshold 和 min_threshold,因为它们旨在确定 t2 和 t3 ......但我不确定如何做到这一点,所以我只是根据从最大和最小增量添加 1-2 小时来设置 t2 和 t3。理想情况下,t2 和 t3 将基于增量值超过最大和最小阈值的确切位置
  • 您在13:00 的增量约为-0.00118。那是&lt; max_threshold,也是&lt; min_threshold。为什么要包括这个? (很抱歉提出愚蠢的问题,但我还没有得到算法......)。在14:00 delta 是&lt; max_thr 和&gt; min_thr。
  • 你是绝对正确的。我已经修改了上面的 c 向量以显示 delta 的绝对值。基本上我想在 abs(delta) 的索引处平均 t2 和 t3 之间的 x

标签: r vector average


【解决方案1】:

这只是部分解决方案,因为它会在第二天出现故障。我将 data.frame 命名为 df 而不是 x。

library(ggplot2)
library(dplyr)
library(lubridate)

df_obj <- df %>% 
  group_by(day = day(time)) %>%  # group by days
  filter(day == 5) %>%           # filter for day 5
  mutate(
    delta_rev = Crow_education_Omer - lag(
      Crow_education_Omer, 
      default = first(Crow_education_Omer)
      ), # delta between day n and n-1
    delta_for = lead(
      Crow_education_Omer, 
      default = last(Crow_education_Omer)
      ) - Crow_education_Omer, # delta between day n-1 and n
    max_tresh  = 0.15 * max(delta_rev)
    )  %>%
  group_by(grp   = 1 - (abs(delta_rev) < 0.15 * max(delta_rev) | abs(delta_for) < 0.15 * max(delta_for)),
           grp2 = cumsum(grp != lag(grp, default = 0))
  ) %>% 
  mutate(
    average = mean(Crow_education_Omer) * 
      (1 - grp) * 
      (abs(first(Crow_education_Omer) - last(Crow_education_Omer)) < max_tresh)
  )

首先,我们需要修改您现有的 data.frame 以建立您的平均值。基于此计算,我们使用ggplot2 进行绘图:

df_obj %>% 
  ggplot(aes(x = time, y = Crow_education_Omer)) +
  geom_point() +
  geom_line(aes(color = "sample")) +
  geom_line(data = df_obj[df_obj$average != 0, ], aes(x = time, y = average, color = "average")) +
  xlab("Time") +
  ylab("Value")

返回

但是对于day 6,这不能按预期工作:更改为filter(day == 6) 并再次绘制返回

这不是预期的结果。将阈值更改为0.33 * max(delta) 并再次绘制创建

因此,也许您可​​以在此代码的基础上创建一个正确且有效的解决方案。祝你好运!

几个解释:

  • 我们建立了delta_rev 和delta_for。 delta_rev 等于您的 delta,因此对于给定的行/数据点 i,我们计算 df[i,2] - df[i-1,2]。
  • delta_for 改变了这一点,现在我们为给定的i 计算 df[i + 1,2] - df[i,2]。我的想法是:同时使用delta_rev 和delta_for 可以让我们查看前面和后面的点。这为我们提供了有关给定点的邻居的更多信息,并且有助于确定该点是否属于一个组(am、peak、pm)。
  • group_by-函数尝试根据阈值建立组。 grp 检查,如果数据点是 &lt; 0.15 max(delta),grp2 会创建一个唯一的分组编号。

有几个问题:

  • 基于此算法,可以有三个以上的组。
  • group_by 在 15:00 到 20:00 之间找到另一个组,我们将其过滤掉(即(abs(first(Crow_education_Omer) - last(Crow_education_Omer)) &lt; max_tresh)-部分)。我不确定这是否是一个好的解决方案。
  • 如上所述,这不会返回合理的第 6 天图。也许 geom_point 的 df_obj[df_obj$average != 0, ]-part 会导致这种情况。

【讨论】:

  • 您好,您能解释一下 df_obj 代码中发生了什么吗?我不明白在 x 仅过滤到第 5 天后发生了什么。 delta_for 和 delta_rev 在做什么?
  • 我稍后会添加解释。
  • @Louise 添加了一些解释。我错过了一件事:显然我使用了很多dplyr-function/syntax。希望你对此坚定。特别是使用dplyr 创建delta 非常容易,我们避免使用for-loop。
猜你喜欢
  • 1970-01-01
  • 2012-03-09
  • 1970-01-01
  • 2022-11-24
  • 2017-07-02
  • 2019-01-27
  • 1970-01-01
  • 1970-01-01
  • 2016-03-13
相关资源
最近更新 更多