рассчитать среднее значение для двух последних столбцов, которые различаются по всем предметам - PullRequest
0 голосов
/ 01 ноября 2018

Я начинающий R, и это мой первый пост здесь. Я борюсь с проблемой и буду рада вашему совету. По сути, у меня есть набор данных с 3 наборами столбцов, которые мне нужно манипулировать в целом, чтобы получить желаемый результат, который является средним из двух самых последних наблюдений (и что эти наблюдения должны произойти после даты отсечки, скажем, 3 / 15/2018), которые имеют высокое качество, но что делает его сложным, так это то, что соответствующие столбцы, которые входят в среднее значение, отличаются для всех случаев.

  • Первый набор столбцов данных связан с количеством наблюдений, которое имеет каждый случай, поэтому у субъекта есть 2 наблюдения, у субъекта 2 - 3 и т. Д.

  • Второй набор столбцов описывает качество данных для каждого из этих наблюдений. Так, например, субъект 1 имеет два хороших наблюдения, тогда как субъект 2 имеет 1 плохое качество данных для первого наблюдения и хорошее качество данных для двух последних, а субъект 3 имеет 3 наблюдения хорошего качества и одно наблюдение (obs_3), которое имеет плохое качество данных.

  • Третий набор столбцов указывает даты наблюдений.

      subject_id obs_1 obs_2 obs_3 obs_4 obs_1_dq obs_2_dq obs_3_dq obs_4_dq obs_1_date obs_2_date obs_3_date obs_4_date desired.average
    1          1     5     6    NA    NA     TRUE     TRUE       NA       NA 2018-02-01 2018-03-16       <NA>       <NA>              NA
    2          2     6     8    11    NA    FALSE     TRUE     TRUE       NA 2018-02-18 2018-03-16 2018-04-10       <NA>             9.5
    3          3     7     9    12    15     TRUE     TRUE    FALSE     TRUE 2018-02-15 2018-03-18 2018-04-02 2018-04-10            12.0
    4          4     3     4     8    15     TRUE     TRUE     TRUE     TRUE 2018-02-16 2018-03-08 2018-03-10 2018-03-15              NA
    

Чтобы рассчитать среднее из двух последних наблюдений, которые имеют хорошее качество данных:

  1. Сначала я должен решить, какие наблюдения хорошего качества,

  2. Затем вычислите среднее (и оно должно составлять в среднем 2 наблюдения), которые происходят после 3/15, и они должны быть двумя самыми последними наблюдениями.

Ниже приведен мой примерный набор данных. Я пытался сделать это вручную в Excel, и это было действительно кропотливо. Я надеюсь сделать это в R и буду очень признателен за ваши отзывы. Спасибо!

Here is my sample dataset: 
> dput(head(df,5))

structure(list(subject_id = c(1, 2, 3, 4), obs_1 = c(5, 6, 7, 
3), obs_2 = c(6, 8, 9, 4), obs_3 = c(NA, 11, 12, 8), obs_4 = c(NA, 
NA, 15, 15), obs_1_dq = c(TRUE, FALSE, TRUE, TRUE), obs_2_dq = c(TRUE, 
TRUE, TRUE, TRUE), obs_3_dq = c(NA, TRUE, FALSE, TRUE), obs_4_dq =    
c(NA, 
NA, TRUE, TRUE), obs_1_date = structure(c(17563, 17580, 17577, 
17578), class = "Date"), obs_2_date = structure(c(17606, 17606, 
17608, 17598), class = "Date"), obs_3_date = structure(c(NA, 
17631, 17623, 17600), class = "Date"), obs_4_date = structure(c(NA, 
NA, 17631, 17605), class = "Date"), desired.average = c(NA, 9.5, 
12, NA)), .Names = c("subject_id", "obs_1", "obs_2", "obs_3", 
"obs_4", "obs_1_dq", "obs_2_dq", "obs_3_dq", "obs_4_dq", "obs_1_date", 
"obs_2_date", "obs_3_date", "obs_4_date", "desired.average"), row.names   
= c(NA, 
4L), class = "data.frame")

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Это также должно работать, и хотя оно немного многословно, оно не зависит от индексов столбцов, поэтому должно быть устойчивым:

library(dplyr)
library(tidyr)

num_date <- as.numeric(as.Date("2018-03-15"))

df <- df[,-ncol(df)]

df_join <- df %>%
  gather(Obs, value, 2:ncol(df)) %>%
  mutate(
    nr = as.numeric(gsub("[^\\d]", "", Obs, perl = TRUE))
  ) %>%
  group_by(subject_id, nr) %>%
  filter(!(is.na(value) | (grepl("_dq", Obs) & value == 0) | any(value[grepl("_date", Obs)] <= num_date))) %>%
  ungroup() %>%
  group_by(subject_id, Obs) %>%
  filter(!row_number() < (max(row_number() - 1))) %>%
  ungroup() %>%
  group_by(subject_id) %>%
  mutate(
    desired.average = mean(value[grepl("_date|_dq", Obs) == FALSE], na.rm = TRUE)
  ) %>%
  filter(!max(row_number()) == 3) %>%
  distinct(subject_id, desired.average)

df <- left_join(df, df_join)

Результат:

  subject_id obs_1 obs_2 obs_3 obs_4 obs_1_dq obs_2_dq obs_3_dq obs_4_dq obs_1_date obs_2_date
1          1     5     6    NA    NA     TRUE     TRUE       NA       NA 2018-02-01 2018-03-16
2          2     6     8    11    NA    FALSE     TRUE     TRUE       NA 2018-02-18 2018-03-16
3          3     7     9    12    15     TRUE     TRUE    FALSE     TRUE 2018-02-15 2018-03-18
4          4     3     4     8    15     TRUE     TRUE     TRUE     TRUE 2018-02-16 2018-03-08
  obs_3_date obs_4_date desired.average
1       <NA>       <NA>              NA
2 2018-04-10       <NA>             9.5
3 2018-04-02 2018-04-10            12.0
4 2018-03-10 2018-03-15              NA
0 голосов
/ 01 ноября 2018

Посмотрите, работает ли это для вас. Код кратко аннотирован.

df=structure(list(subject_id = c(1, 2, 3, 4), obs_1 = c(5, 6, 7, 
3), obs_2 = c(6, 8, 9, 4), obs_3 = c(NA, 11, 12, 8), obs_4 = c(NA, 
NA, 15, 15), obs_1_dq = c(TRUE, FALSE, TRUE, TRUE), obs_2_dq = c(TRUE, 
TRUE, TRUE, TRUE), obs_3_dq = c(NA, TRUE, FALSE, TRUE), obs_4_dq =    
c(NA, NA, TRUE, TRUE), obs_1_date = structure(c(17563, 17580, 17577, 
17578), class = "Date"), obs_2_date = structure(c(17606, 17606, 
17608, 17598), class = "Date"), obs_3_date = structure(c(NA, 
17631, 17623, 17600), class = "Date"), obs_4_date = structure(c(NA, 
NA, 17631, 17605), class = "Date"), desired.average = c(NA, 9.5, 
12, NA)), .Names = c("subject_id", "obs_1", "obs_2", "obs_3", 
"obs_4", "obs_1_dq", "obs_2_dq", "obs_3_dq", "obs_4_dq", "obs_1_date", 
"obs_2_date", "obs_3_date", "obs_4_date", "desired.average"), row.names   
= c(NA, 4L), class = "data.frame")

# separate each section
obs=df[,2:5]
dq=df[, 6:9]
dt=sapply(df[, 10:13], as.numeric) # for easier calculations
# remove bad quality
obs[dq==F]=NA
# remove dates before 2018-3-15
obs[dt - as.numeric(as.Date("2018-03-15")) <= 0] = NA
# only leave two most recent dates
dt[is.na(obs)]=NA
dt=t(apply(dt,1,function(x){x[x<max(x[x!=max(x, na.rm=T)],na.rm=T)]=NA;x}))
obs[is.na(dt)]=NA
# average
df$avg=apply(obs,1,function(x)ifelse(sum(!is.na(x))>=2, mean(x,na.rm=T), NA))
df

редактирует: Пояснение

dt=t(apply(dt,1, function(x){x[x<max(x[x!=max(x, na.rm=T)],na.rm=T)]=NA;x}))

Я думаю, это может быть немного запутанным для x[x<max(x[x!=max(x, na.rm=T)],na.rm=T)]=NA. Значение na.rm=T означает удаление NA значений. max(x[x!=max(x)]) означает второе по величине число. Так что x[x < 2nd_largest_num]=NA просто удалил любое число, кроме самого большого и второго по величине. Затем эта функция применяется к кадру данных построчно. Окончательный результат - dt содержит только два самых больших числа в каждой строке (самая последняя дата в числовом формате). Все «отброшенные» значения (NA в dt) будут удалены из obs в следующей строке obs[is.na(dt)]=NA. После всего этого obs содержит только два последних значения в каждой строке.

...