Извлечение последнего значения не-NA во фрейм данных на основе группировки - PullRequest
0 голосов
/ 05 марта 2019

У меня есть фрейм данных, который выглядит следующим образом:

 Year   Day  ID   V1  V2 .... 
 2003   35  1102  3   6
 2003   35  1103  5   NA
 2003   35  1104  8   100
 .....
 2003   40  1102  NA  8
 2003   40  1103  NA  10
 2003   40  1104  9   NA
 .....
 .....
 2018   49  1104  5   NA
 .....
 2018   50  1102  3   6
 2018   50  1103  7   NA
 2018   50  1104  NA  100

Я хотел бы построить фрейм данных, который извлекает для каждой комбинации года и идентификатора самое последнее (высокое значение дляКолонка дня) значение, отличное от NA, в V1, V2 ... Исходя из вышеуказанного набора данных, для года = 2018 и ID = 1104, я хотел бы извлечь V1 = 5 (в день = 49) и V2 = 100 (вкл.День = 50).Если все значения для этой комбинации года и идентификатора равны NA, я бы хотел вернуть NA.

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

Мы можем создать функцию, которая дает нам последнее значение не-NA на основе Day для каждого Vn столбца

get_last_non_NA_value <- function(x) {
   x[which.max(cumsum(!is.na(x)))]
}

, а затем применять эту функцию для каждого Year и * 1007.*

library(dplyr)

df %>%
  group_by(Year, ID) %>%
  summarise_at(vars(V1:V2), funs(get_last_non_NA_value(.[order(Day)])))


#    Year  ID    V1    V2
#  <int> <int> <int> <int>
#1  2003  1102     3     8
#2  2003  1103     5    10
#3  2003  1104     9   100
#4  2018  1102     3     6
#5  2018  1103     7    NA
#6  2018  1104     5   100

РЕДАКТИРОВАТЬ

Если мы также хотим извлечь соответствующие Day для каждого значения, мы можем изменить функцию так, чтобы она возвращала оба значения какстрока с разделителями-запятыми

get_last_non_NA_value <- function(x, y) {
   ind <- which.max(cumsum(!is.na(x[order(y)])))
   paste(x[ind], y[ind], sep = ",")
}

, а затем используйте cSplit для разделения значений, разделенных запятыми, на разные столбцы.

library(dplyr)
library(splitstackshape)
cols <- c("V1", "V2")

df %>%
 group_by(Year, ID) %>%
 summarise_at(cols, funs(get_last_non_NA_value(., Day))) %>%
 cSplit(cols) %>%
 rename_at(vars(contains("_1")), funs(sub("_1", "_last_value", .))) %>%
 rename_at(vars(contains("_2")), funs(sub("_2", "_days", .)))


#   Year   ID V1_last_value V1_days V2_last_value V2_days
#1: 2003 1102             3      35             8      40
#2: 2003 1103             5      35            10      40
#3: 2003 1104             9      40           100      35
#4: 2018 1102             3      50             6      50
#5: 2018 1103             7      50            NA      50
#6: 2018 1104             5      49           100      50

Обратите внимание, что часть rename_at переименовывает столбцы, чтобы лучше понять, какое значение она содержит, вы можете пропустить эту часть, если вы не заинтересованы в переименовании столбцов.

данные

df <- structure(list(Year = c(2003L, 2003L, 2003L, 2003L, 2003L, 2003L, 
2018L, 2018L, 2018L, 2018L), Day = c(35L, 35L, 35L, 40L, 40L, 
40L, 49L, 50L, 50L, 50L), ID = c(1102L, 1103L, 1104L, 1102L, 
1103L, 1104L, 1104L, 1102L, 1103L, 1104L), V1 = c(3L, 5L, 8L, 
NA, NA, 9L, 5L, 3L, 7L, NA), V2 = c(6L, NA, 100L, 8L, 10L, NA, 
NA, 6L, NA, 100L)), .Names = c("Year", "Day", "ID", "V1", "V2"
), class = "data.frame", row.names = c(NA, -10L))
0 голосов
/ 05 марта 2019

Вы можете использовать dplyr Предполагая, что вы хотите максимум для V1 и V2

library(dplyr)
df %>%
    group_by(Year, ID) %>%
    summarise(Day = max(Day, na.rm = TRUE),
              V1 = max(V1, na.rm = TRUE),
              V2 = max(V2, na.rm = TRUE))

Если для V1 и V2 вы хотите сначала не-NA, то

df %>%
    group_by(Year, ID) %>%
    summarise(Day = max(Day, na.rm = TRUE),
              V1 = first(setdiff(V1, NA)),
              V2 = first(setdiff(V1, NA)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...