Вычислить среднее значение подмножества вектора только тогда, когда значения подмножества удовлетворяют условию в R?

#r #vector #average

Вопрос:

У меня есть дневная кривая x, и я пытаюсь приблизить средние пиковые и пиковые значения x: https://ibb.co/Fq1Byzk

Я определил дельта-порог таким образом, что, когда дельта ниже порогового значения, x будет находиться в пиковом или пиковом периоде. Я хочу получить среднее пиковое значение, где среднее значение только для значений в пределах x, где дельта Прямо сейчас он также усредняет выбросы.

 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 на одном графике? Кажется, я не могу расплавить или привязать() новую кривую с уменьшенным количеством точек данных с помощью x, так как мой столбец времени-POSIXCT.

Спасибо.

Комментарии:

1. Не могли бы вы объяснить, что я хочу получить среднее пиковое значение, где среднее значение только для значений в пределах x, где дельта < порог немного дальше? Например: Вы хотите включить в am список только значения x[1:t1,2] чьих delta < max_threshold ? О чем min_threshold ?

2. так, например, я хочу, чтобы мое среднее пиковое значение включало только значения с 10:00 до 14:00, потому что дельта, вычисленная между 10:00 и 14:00, меньше моего значения max_threshold ~0,002. Прямо сейчас мое среднее пиковое значение включает в себя все от t2 до t3. Я вычислил max_threshold и min_threshold, поскольку они предназначались для определения t2 и t3…но я не был уверен, как это сделать, поэтому я просто установил t2 и t3, добавив 1-2 часа из максимальной и минимальной дельт. В идеале t2 и t3 должны основываться именно на том, где значения дельты превышают максимальный и минимальный пороговые значения

3. Ваша дельта в 13:00 примерно -0.00118 . Это тоже < max_threshold «но < min_threshold «. Почему это должно быть включено? (Извините за глупые вопросы, но я еще не понял алгоритм…). В 14:00 delta есть < max_thr и > min_thr снова.

4. вы абсолютно правы. я пересмотрел вектор c выше, чтобы вместо этого показать абсолютное значение дельты. В основном я хочу усреднить x между t2 и t3 по индексам, где abs(дельта)

Ответ №1:

Это всего лишь частичное решение, так как оно ломается на второй день. Я назвал данные.фрейм 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)
  )
 

Сначала нам нужно изменить ваши существующие данные.фрейм, чтобы построить ваши средние значения. Основываясь на этом расчете, мы используем 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 изменяет это, теперь мы рассчитываем df[i 1,2] - df[i,2] для данного i . Моя идея здесь такова: использовать и то, и другое, delta_rev и delta_for позволяет нам взглянуть на предшествующие и последующие моменты. Это дает нам больше информации о соседях данной точки и полезно для определения принадлежности точки к группе (am, пик, pm).
  • Функция group_by -пытается создать группы на основе точки привязки. grp проверяет, есть ли точка данных < 0.15 max(delta) , grp2 создает уникальный номер группировки.

Есть несколько проблем:

  • На основе этого алгоритма может быть более трех групп.
  • Группа group_by находит другую группу между 15:00 и 20:00, мы ее отфильтровываем (это (abs(first(Crow_education_Omer) - last(Crow_education_Omer)) < max_tresh) -часть). Я не уверен, что это хорошее решение.
  • Как указано выше, это не возвращает разумный график для 6-го дня. Возможно, это df_obj[df_obj$average != 0, ] вызвано частью geom_point.

Комментарии:

1. Привет, не могли бы вы объяснить, что происходит в коде df_obj? Я не понимаю, что происходит после того, как x отфильтровывается только до 5-го дня. Что делают delta_for и delta_rev?

2. Я добавлю объяснение позже.

3. @Louise добавила несколько пояснений. Я упустил одну вещь: очевидно, я использовал много dplyr функций/синтаксиса. Надеюсь, ты будешь тверд в этом. Особенно создание delta » s «очень легко, dplyr и мы избегаем использования for цикла «а».