2016-10-14 45 views
7

Mam ramkę danych uporządkowaną według malejącej kolejności.Zamień NA na poprzednią lub następną wartość, według grupy, używając dplyr

ps1 = data.frame(userID = c(21,21,21,22,22,22,23,23,23), 
      color = c(NA,'blue','red','blue',NA,NA,'red',NA,'gold'), 
      age = c('3yrs','2yrs',NA,NA,'3yrs',NA,NA,'4yrs',NA), 
      gender = c('F',NA,'M',NA,NA,'F','F',NA,'F') 
) 

życzę przypisać (wymienić) brak wartości z poprzednich wartości i zgrupowane przez identyfikator użytkownika W przypadku, gdy pierwszy rząd ID użytkownika jest NA następnie zastąpić przez następny zestaw wartości dla tej grupy id_użytkownika.

Próbuję użyć dplyr i zoo pakiety coś takiego ... ale jej nie działa

cleanedFUG <- filteredUserGroup %>% 
group_by(UserID) %>% 
mutate(Age1 = na.locf(Age), 
    Color1 = na.locf(Color), 
    Gender1 = na.locf(Gender)) 

muszę doprowadzić df tak:

     userID color age gender 
       1  21 blue 3yrs  F 
       2  21 blue 2yrs  F 
       3  21 red 2yrs  M 
       4  22 blue 3yrs  F 
       5  22 blue 3yrs  F 
       6  22 blue 3yrs  F 
       7  23 red 4yrs  F 
       8  23 red 4yrs  F 
       9  23 gold 4yrs  F 
+0

Zobacz, czy jest to pomocne. [Zastępowanie NA z ostatnią wartością inną niż NA] (http://stackoverflow.com/questions/7735647/replacing-nas-with-latest-non-na-value) lub [zastąp wartość NA wartością grupy] (http : //stackoverflow.com/questions/23583739/replace-na-value-w--group-value) –

+0

@Tarak cześć, jeśli jedna z odpowiedzi rozwiązuje twój problem, nie wahaj się oznaczyć go jako "zaakceptowany", więc inni ludzie też to widzą ... dzięki – agenis

Odpowiedz

17
require(tidyverse) #fill is part of tidyr 

ps1 %>% 
    group_by(userID) %>% 
    fill(color, age, gender) %>% #default direction down 
    fill(color, age, gender, .direction = "up") 

co daje:

Source: local data frame [9 x 4] 
Groups: userID [3] 

    userID color age gender 
    <dbl> <fctr> <fctr> <fctr> 
1  21 blue 3yrs  F 
2  21 blue 2yrs  F 
3  21 red 2yrs  M 
4  22 blue 3yrs  F 
5  22 blue 3yrs  F 
6  22 blue 3yrs  F 
7  23 red 4yrs  F 
8  23 red 4yrs  F 
9  23 gold 4yrs  F 
1

Korzystanie zoo::na.locf bezpośrednio na całość data.frame wypełni NA niezależnie od grup userID. grupowanie Pakiet dplyr zawiera niestety żadnego wpływu na na.locf funkcji, dlatego poszedłem z podziałem:

library(dplyr); library(zoo) 
ps1 %>% split(ps1$userID) %>% 
    lapply(function(x) {na.locf(na.locf(x), fromLast=T)}) %>% 
    do.call(rbind, .) 
####  userID color age gender 
#### 21.1  21 blue 3yrs  F 
#### 21.2  21 blue 2yrs  F 
#### 21.3  21 red 2yrs  M 
#### 22.4  22 blue 3yrs  F 
#### 22.5  22 blue 3yrs  F 
#### 22.6  22 blue 3yrs  F 
#### 23.7  23 red 4yrs  F 
#### 23.8  23 red 4yrs  F 
#### 23.9  23 gold 4yrs  F 

co robi jest to, że najpierw dzieli dane na 3 data.frames, potem przyłożyć pierwszą przepustkę z przypisania (w dół), następnie w górę za pomocą anonimowej funkcji w lapply, a ostatecznie użyjemy rbind, aby ponownie połączyć dane. Masz oczekiwany wynik.

+1

Możesz zamienić 'do.call()' na bardziej idiomatyczne 'bind_rows()' i 'split (ps1 $ userID)' z 'split (. $ userID)' –

+1

Kolejny alternatywa za pomocą 'purrr' może być również:' library (purrr); ps1%>% slice_rows ("userID")%>% by_slice (function (x) {na.locf (na.locf (x), fromLast = T)}, .collate = "rows") ' –

+1

@ StevenBeaupré nice! to zasługuje na nową odpowiedź ;-) – agenis

1

Korzystanie @agenis metodę z na.locf() połączeniu z purrr, można zrobić:

library(purrr) 
library(zoo) 

ps1 %>% 
    slice_rows("userID") %>% 
    by_slice(function(x) { 
    na.locf(na.locf(x), fromLast=T) }, 
    .collate = "rows")