2016-06-09 11 views
8

Questo è un esempio dei miei dati da CSV. Contiene ~ 10 colonne.Sostituisci NA con occorrenza precedente

Product_id Product_Weight Product_Name Shop_Name ... 
[1] A    10    xxxx   Walmart 
[2] B    12    yyyy   Target 
[3] C    11    zzzz   Target 
[4] A    NA    xxxx   Walmart 
[5] C    NA    zzzz   Target 

desidero riempire NA di nella riga 4 e 5 con 10 e 11 rispettivamente (poiché il peso del prodotto di A e C sono già noti dalla fila 1 e 3). Voglio che il frame di dati finale per essere come questo

Product_id Product_Weight Product_Name Shop_Name ... 
[1] A    10    xxxx   Walmart 
[2] B    12    yyyy   Target 
[3] C    11    zzzz   Target 
[4] A    10    xxxx   Walmart 
[5] C    11    zzzz   Target 

Qual è il modo migliore per farlo in R?

+0

Questi pesi sono sempre impostati in modo che una combinazione Product_id - Product_name restituisca lo stesso peso? – lmo

+0

@lmo Sì, lo sono. – Avis

+0

Un'altra domanda su come sostituire NA: http://stackoverflow.com/questions/32694313/handle-continous-missing-values-in-time-series-data – Jaap

risposta

5

Un'altra opzione con dplyr e tidyr:

library(dplyr); library(tidyr); 
df %>% group_by(Product_id) %>% fill(Product_Weight) 

Source: local data frame [5 x 4] 
Groups: Product_id [3] 

    Product_id Product_Weight Product_Name Shop_Name 
     (fctr)   (int)  (fctr) (fctr) 
1   A    10   xxxx Walmart 
2   A    10   xxxx Walmart 
3   B    12   yyyy Target 
4   C    11   zzzz Target 
5   C    11   zzzz Target 

Il risultato è ordinato per Product_id.

+0

può dplyr farlo senza riordino? – rawr

9

Anche se la domanda posta per la "occorrenza precedente" questo avrebbe lo svantaggio che se il primo Product_Weight in qualsiasi Product_id stati NA allora potrebbe non essere compilati, anche se sapevamo che il Product_Weight da un successivo Product_id così invece di utilizzare nell'occorrenza precedente prendiamo la media di tutti i non-NA con lo stesso Product_id. Poiché questi dovrebbero essere tutti uguali, il loro significato è il loro valore comune.

Se davvero si vuole l'occorrenza precedente utilizzare la funzione Prev dove:

Prev <- function(x) na.locf(x, na.rm = FALSE) 

al posto di na.aggregate in (1) e (3) e non utilizzare (2).

I seguenti soluzioni presentano i vantaggi che tutti:

  • mantengono l'ordine dell'ingresso

  • lavoro anche se il primo Product_Weight in qualsiasi Product_id è NA

  • non

    modificare l'input

La prima soluzione ha l'ulteriore vantaggio di essere solo una riga di codice (più una dichiarazione library) e la seconda soluzione ha il vantaggio aggiuntivo di non utilizzare alcun pacchetto.

1) zoo :: na.aggregate Usiamo na.aggregate nel pacchetto zoo (che sostituisce tutti AN con la media del non-AN) e applicarlo Product_Weight separatamente per ciascun Product_id.

library(zoo) 
transform(DF, Product_Weight = ave(Product_Weight, Product_id, FUN = na.aggregate)) 

dando:

Product_id Product_Weight Product_Name Shop_Name 
1   A    10   xxxx Walmart 
2   B    12   yyyy Target 
3   C    11   zzzz Target 
4   A    10   xxxx Walmart 
5   C    11   zzzz Target 

2) Nessun pacchetto In alternativa utilizzare Mean al posto di na.aggregate dove Mean è definito come:

Mean <- function(x) replace(x, is.na(x), mean(x, na.rm = TRUE)) 

3) dplyr/Zoo Add numeri di riga, raggruppare per Product_id, compilare il NAS come nelle soluzioni note utilizzando sia na.aggregate come quella sottostante oppure Mean, organizzare ritorna l'ordine originale e rimuovere i numeri di riga:

library(dplyr) 
library(zoo) 

DF %>% 
    mutate(row = row_number()) %>% 
    group_by(Product_id) %>% 
    mutate(Product_Weight = na.aggregate(Product_Weight)) %>% 
    ungroup() %>% 
    arrange(row) %>% 
    select(-row) 

Nota: Questo è stato utilizzato per l'ingresso DF:

Lines <- " Product_id Product_Weight Product_Name Shop_Name 
    A    10    xxxx   Walmart 
    B    12    yyyy   Target 
    C    11    zzzz   Target 
    A    NA    xxxx   Walmart 
    C    NA    zzzz   Target" 
DF <- read.table(text = Lines, header = TRUE) 
2

Ecco la soluzione con i comandi di base R:

# create lookup table with item and weight combinations 
lookup<-unique(df[complete.cases(df[ ,1:2]),]) 

#  find the NAs needing replacement: which(is.na(df$weight)) 
#  find index in lookup tabe:match(df$a[which(is.na(df$weight)) 
#  subset: df$weight[which(is.na(df$weight)) 
df$weight[which(is.na(df$weight))]<-lookup$weight[match(df$Product_id[which(is.na(df$weight))], lookup$Product_id)] 

Molto probabilmente non è efficiente come la soluzione dplyr/tidyr di cui sopra.