Как найти последние данные по переменной
Я хотел бы знать, как извлечь данные по самой последней дате путем кодирования.
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)