Как найти последние данные по переменной

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

cname       year   x1 x2 x3 x4
Afghanistan 2015   3  2  6  3
Afghanistan 2016   4  7  NA 9
Afghanistan 2017   5  NA NA NA  
Albania     2015   2  3  4  3
Albania     2016   2  4  NA NA
Albania     2017   4  NA 8  NA  
Algeria     2015   NA NA NA NA
Algeria     2016   NA NA NA NA
Algeria     2017   NA NA NA NA
...

Ответ, который я хотел бы получить

 cname          x1 x2 x3 x4
   Afghanistan   5  7  6  9
   Albania       4  4  8  3
   Algeria      NA NA NA NA
...

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

4 ответа

Вот решение с zoo а также dplyr:

library(zoo)
library(dplyr)
df <- read.table("clipboard", header=T)
df %>%
  group_by(cname) %>%
  arrange(year) %>%
  mutate_all(funs(na.locf(., na.rm = FALSE))) %>% 
  filter(year==max(year))

# A tibble: 3 x 6
# Groups:   cname [3]
  cname        year    x1    x2    x3    x4
  <fct>       <int> <int> <int> <int> <int>
1 Afghanistan  2017     5     7     6     9
2 Albania      2017     4     4     8     3
3 Algeria      2017    NA    NA    NA    NA

Вот идея через базу R, однако с использованием coalesce от dplyr "объединить" НС с не-НС, т.е.

sapply(split(df, df$cname), function(i) { d2 <- data.frame(t(i[order(i$year, decreasing = TRUE), -1])); 
                                          do.call(dplyr::coalesce, d2) })

который дает,

     Afghanistan Albania Algeria
[1,]         2017    2017    2017
[2,]           5       4      NA
[3,]           7       4      NA
[4,]           6       8      NA
[5,]           9       3      NA

Переместите приведенный выше результат, чтобы получить желаемый результат (или оберните его в data.frameили обрабатывать так, как вам нужно), т.е.

t(d3)
            [,1] [,2] [,3] [,4] [,5]
Afghanistan 2017    5    7    6    9
Albania     2017    4    4    8    3
Algeria     2017   NA   NA   NA   NA

ДАННЫЕ

dput(df)
structure(list(cname = c("Afghanistan", "Afghanistan", "Afghanistan", 
"Albania", "Albania", "Albania", "Algeria", "Algeria", "Algeria"
), year = c(2015L, 2016L, 2017L, 2015L, 2016L, 2017L, 2015L, 
2016L, 2017L), x1 = c(3L, 4L, 5L, 2L, 2L, 4L, NA, NA, NA), x2 = c(2L, 
7L, NA, 3L, 4L, NA, NA, NA, NA), x3 = c(6L, NA, NA, 4L, NA, 8L, 
NA, NA, NA), x4 = c(3L, 9L, NA, 3L, NA, NA, NA, NA, NA)), row.names = c(NA, 
-9L), class = "data.frame")

Вот dplyr/tidyr решение. Я группирую по имени, чтобы убедиться, что наблюдения упорядочены по годам, а затем использую tidyr::fill заменить NAс самыми последнимиNA значение выше, внутри групп.

Я бы также рекомендовал фильтровать, когда год равен максимальному году, то есть самому последнему году, а не жестко задавать год, который вы хотите сохранить. Таким образом, он хорошо масштабируется в случае, если у вас есть новые данные с годами, более поздними, чем 2017 год. То, как я их настроил, теперь фильтрует по последнему году в каждой стране; если, однако, вам нужно отфильтровать последний год для всех стран, добавьте вызов ungroup до фильтрации.

library(dplyr)
library(tidyr)

df %>%
  group_by(cname) %>%
  arrange(year) %>%
  fill(x1:x4) %>%
  filter(year == max(year)) %>%
  select(-year)
#> # A tibble: 3 x 5
#> # Groups:   cname [3]
#>   cname          x1    x2    x3    x4
#>   <chr>       <int> <int> <int> <int>
#> 1 Afghanistan     5     7     6     9
#> 2 Albania         4     4     8     3
#> 3 Algeria        NA    NA    NA    NA

Создано в 2018-11-26 пакетом представительства (v0.2.1)

Это работает на вашем примере, я не проверял другие возможности:

Обратите внимание, что d должен быть заказан cname а также year перед вызовом функции (как в вашем примере).

l <- split(d, d$cname) #  we split each in a list
l <- lapply(l, function(x) x[, -c(1,2)]) # remove non useful infos
#l <- split(d[, -c(1,2)], d$cname) # this avoids this second line

# this basically seeks for the last non NA value, otherwise uses NA if all are NA
ll <- lapply(l, function(x) {
  if (!all(is.na(x))) {
    sapply(x, function(y) last(y[!is.na(y)])) # inside each element in the list I search for last non-NA
  } else {
    NA
  }
})

t(as.data.frame(ll))
#             x1 x2 x3 x4
# Afghanistan  5  7  6  9
# Albania      4  4  8  3
# Algeria     NA NA NA NA

В основном я использовал list и искать последнее значение не NA. Я рекомендую напечатать каждый отрывок, чтобы увидеть, что происходит.

Это может превратиться в function:

my_function <- function(data) {
  l <- split(data, data$cname)
  l <- lapply(l, function(x) x[, -c(1,2)])

  ll <- lapply(l, function(x) {
    if (!all(is.na(x))) {
      sapply(x, function(y) last(y[!is.na(y)]))
    } else {
      NA
    }
  })

  t(as.data.frame(ll)) # return
}
my_function(d)
#             x1 x2 x3 x4
# Afghanistan  5  7  6  9
# Albania      4  4  8  3
# Algeria     NA NA NA NA

Используемые данные:

tt<-"cname       year   x1 x2 x3 x4
Afghanistan 2015   3  2  6  3
Afghanistan 2016   4  7  NA 9
Afghanistan 2017   5  NA NA NA  
Albania     2015   2  3  4  3
Albania     2016   2  4  NA NA
Albania     2017   4  NA 8  NA  
Algeria     2015   NA NA NA NA
Algeria     2016   NA NA NA NA
Algeria     2017   NA NA NA NA"

d <- read.table(text=tt, header = T)
Другие вопросы по тегам