Jak wypełnić serwer NAS LOCF według czynników w ramce danych, w podziale na kraje
Mam następującą ramkę danych (uproszczoną) ze zmienną kraju jako czynnikiem i zmienna wartości ma brakujące wartości:
country value
AUT NA
AUT 5
AUT NA
AUT NA
GER NA
GER NA
GER 7
GER NA
GER NA
Powyższa ramka danych generuje:
data <- data.frame(country=c("AUT", "AUT", "AUT", "AUT", "GER", "GER", "GER", "GER", "GER"), value=c(NA, 5, NA, NA, NA, NA, 7, NA, NA))
Teraz chciałbym zastąpić wartości NA w każdym podzbiorze kraju metodą last observation carried forward (LOCF). Znam komendę na.locf
w pakiecie zoo. data <- na.locf(data)
dałoby mi następującą ramkę danych:
country value
AUT NA
AUT 5
AUT 5
AUT 5
GER 5
GER 5
GER 7
GER 7
GER 7
Jednakże, funkcja powinien być stosowany tylko na poszczególnych podzbiorach podzielonych przez państwo. Poniżej znajduje się wyjście, którego potrzebuję:
country value
AUT NA
AUT 5
AUT 5
AUT 5
GER NA
GER NA
GER 7
GER 7
GER 7
Nie mogę wymyślić łatwego sposobu na jego wdrożenie. Zanim zacząłem z for-loops, zastanawiałem się, czy ktoś ma jakiś pomysł, jak to rozwiązać.
Wielkie dzięki!!
7 answers
Oto ddply
rozwiązanie. Try this
library(plyr)
ddply(DF, .(country), na.locf)
country value
1 AUT <NA>
2 AUT 5
3 AUT 5
4 AUT 5
5 GER <NA>
6 GER <NA>
7 GER 7
8 GER 7
9 GER 7
Edit
Z pomocy ddply
znajdziesz to
.variables: variables to split data frame by,
as quoted variables, a formula or character vector.
Więc inne alternatywy, aby dostać to, co chcesz są:
ddply(DF, "country", na.locf)
ddply(DF, ~country, na.locf)
Zauważ, że zastąpienie .variables
przez DF$variable
jest niedozwolone, dlatego masz błąd podczas robienia tego.
DF
to Twoje dane.frame
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-29 08:45:20
Nowoczesną wersją rozwiązania ddply
jest użycie pakietu dplyr
:
library(dplyr)
DF %>%
group_by(county) %>%
mutate(value = na.locf(value, na.rm = F))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-21 23:07:42
Podziel data.frame
z by
i użyj na.locf
na podzbiorach:
do.call(rbind,by(data,data$country,na.locf))
Jeśli chcesz usunąć nazwy wierszy:
do.call(rbind,unname(by(data,data$country,na.locf)))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-29 16:50:16
Po prostu trzeba podzielić według kraju, a następnie zrobić albo A zoo:: na.locf () lub na.wypełnij, wypełnij w prawo. Oto przykład jawnie pokazujący składnię arg trójskładnikowej na.wypełnienie:
library(plyr)
library(zoo)
data <- data.frame(country=c("AUT", "AUT", "AUT", "AUT", "GER", "GER", "GER", "GER", "GER"), value=c(NA, 5, NA, NA, NA, NA, 7, NA, NA))
# The following is equivalent to na.locf
na.fill.right <- function(...) { na.fill(..., list(left=NA,interior=NA,right="extend")) }
ddply(data, .(country), na.fill.right)
country value
1 AUT <NA>
2 AUT 5
3 AUT 5
4 AUT 5
5 GER <NA>
6 GER <NA>
7 GER 7
8 GER 7
9 GER 7
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-21 00:18:17
Jeśli prędkość jest rozważana, to unstack
/stack
rozwiązanie jest około 4 do 6 razy szybsze niż inne w moim systemie, chociaż pociąga za sobą nieco dłuższą linię kodu: {]}
stack(lapply(unstack(data, value ~ country), na.locf, na.rm = FALSE))
Inne podejście to:
transform(data, value = ave(value, country, FUN = na.locf0))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-27 18:38:38
Sposobem tidyverse, aczkolwiek nie używającym locf, jest:
library(tidyverse)
data %>%
group_by(country) %>%
fill(value)
Source: local data frame [9 x 2]
Groups: country [2]
country value
(fctr) (dbl)
1 AUT NA
2 AUT 5
3 AUT 5
4 AUT 5
5 GER NA
6 GER NA
7 GER 7
8 GER 7
9 GER 7
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 02:54:53
Jestem trochę spóźniony na tę rozmowę, ale Oto data.table
sposób, który będzie znacznie szybszy dla większych zbiorów danych:
library(zoo)
library(data.table)
# Convert to data table
setDT(data)
data[, value := na.locf(value, na.rm = FALSE), by = country]
data
country value
1: AUT NA
2: AUT 5
3: AUT 5
4: AUT 5
5: GER NA
6: GER NA
7: GER 7
8: GER 7
9: GER 7
# And if you want to convert "data" back to a data frame...
setDF(data)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-27 16:21:51