2017-11-17 34 views
8

Mam ramki danych jak tenwypełnienia kolumny z poprzedniej kolumny jeśli NA

df <- data.frame(v1 = 10:14, v2 = c(NA, 1, NA, 3, 6), v3 = c(1, NA, NA, 9, 4)) 

    v1 v2 v3 
1 10 NA 1 
2 11 1 NA 
3 12 NA NA 
4 13 3 9 
5 14 6 4 

Teraz chcę, aby wypełnić NAS z wartością poprzedniej kolumnie, więc wygląda to tak:

v1 v2 v3 
1 10 10 1 
2 11 1 1 
3 12 12 12 
4 13 3 9 
5 14 6 4 

wiem jak to zrobić ręcznie, tak:

df$v2 <- ifelse(is.na(df$v2), df$v1, df$v2) 

Jak mogę zautomatyzować to dla pełnej ramki danych z wielu kolumn?

Odpowiedz

8

Można to zrobić z fill z tidyr:

library(dplyr) 
library(tidyr) 

data.frame(t(df)) %>% 
    fill(., names(.)) %>% 
    t() 

Wynik:

v1 v2 v3 
X1 10 10 1 
X2 11 1 1 
X3 12 12 12 
X4 13 3 9 
X5 14 6 4 

Uwaga:

Zasadniczo transponowane df wypełnione każdą kolumnę w dół, a następnie transponowane go z powrotem do pierwotnej orientacji

6
for (i in 2:ncol(df)) 
    df[,i] = ifelse(is.na(df[,i]), df[,i-1],df[,i]) 

Spowoduje to propagację wartości w poprzek kolumn NA. Jeśli tego nie chcesz, po prostu odwróć kolejność indeksów w deklaracji pętli for.

4

Można użyć apply jednak pamiętać, że wyjście będzie macierzą

t(apply(df, 1, function(x){ 
    replace(x, is.na(x), x[cumsum(!is.na(x))][is.na(x)]) 
})) 
#  v1 v2 v3 
#[1,] 10 10 1 
#[2,] 11 1 1 
#[3,] 12 12 12 
#[4,] 13 3 9 
#[5,] 14 6 4 
6

Inną opcją korzystania Reduce z ifelse:

df[] <- Reduce(function(x, y) ifelse(is.na(y), x, y), df, accumulate = TRUE) 

df 
# v1 v2 v3 
#1 10 10 1 
#2 11 1 1 
#3 12 12 12 
#4 13 3 9 
#5 14 6 4 
4

Korzystając zoona.locf

data.frame(t(apply(df,1,function(x) na.locf(x)))) 
    v1 v2 v3 
1 10 10 1 
2 11 1 1 
3 12 12 12 
4 13 3 9 
5 14 6 4 
+1

'na.locf' może być stosowany do całego ramka danych naraz, więc 'na.locf (df, na.rm = FALSE)' zadziała. (W tym konkretnym przypadku 'na.rm = FALSE' nie robi nic innego, tylko jeśli wiodące wiersze były wszystkie NA, to zachowałoby je.) –

+0

@ G.Grothendieck uczyć się, dzięki :-) – Wen

Powiązane problemy