2016-12-07 3 views
1

I ont une trame de données avec une structure longitudinale comme suit:R - Recode NA avec des niveaux d'un facteur de données groupées

df = structure(list(oslaua = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 
2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L), .Label = c("E06000001", "E06000002", 
"E06000003", "E06000004"), class = "factor"), wave = structure(c(1L, 
2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L), .Label = c("0", 
"1", "2", "3"), class = "factor"), old.la = structure(c(1L, 1L, 
NA, 1L, 2L, 2L, 2L, NA, 3L, 3L, 3L, 3L, 4L, 4L, NA), .Label = c("00EB", 
"00EC", "00EE", "00EF"), class = "factor"), la = structure(c(1L, 
1L, NA, 1L, 2L, 2L, 2L, NA, 3L, 3L, 3L, 3L, 4L, 4L, NA), .Label = c("Hartlepool UA", 
"Middlesbrough UA", "Redcar and Cleveland UA", "Stockton-on-Tees UA" 
), class = "factor"), dclg.code = structure(c(1L, 1L, NA, 1L, 
4L, 4L, 4L, NA, 3L, 3L, 3L, 3L, 2L, 2L, NA), .Label = c("H0724", 
"H0738", "V0728", "W0734"), class = "factor"), novo_entries = c(24L, 
4L, 0L, 1L, 35L, 15L, 1L, 0L, 49L, 7L, 2L, 2L, 40L, 14L, 0L)), .Names = c("oslaua", 
"wave", "old.la", "la", "dclg.code", "novo_entries"), row.names = c(NA, 
15L), class = "data.frame") 

Ma variable d'identificateur est oslaua et ma variable de temps est wave. old.la, la et dclg.code sont des variables de facteur qui ont NA. Mon objectif consiste à recoder mon NA par le niveau de chaque variable associée à chaque identifiant (oslaua). Je l'ai essayé de le faire dans le cas de old.la en utilisant les éléments suivants:

df = df %>% group_by(oslaua) %>% mutate(old.la.1 = ifelse(is.na(old.la), unique(old.la), old.la)) %>% as.data.frame() 

Je reçois en partie mon but mais il y a des questions que vous pouvez voir:

> df 
     oslaua wave old.la      la dclg.code novo_entries old.la.1 
1 E06000001 0 00EB   Hartlepool UA  H0724   24  1 
2 E06000001 1 00EB   Hartlepool UA  H0724   4  1 
3 E06000001 2 <NA>     <NA>  <NA>   0  2 
4 E06000001 3 00EB   Hartlepool UA  H0724   1  1 
5 E06000002 0 00EC  Middlesbrough UA  W0734   35  2 
6 E06000002 1 00EC  Middlesbrough UA  W0734   15  2 
7 E06000002 2 00EC  Middlesbrough UA  W0734   1  2 
8 E06000002 3 <NA>     <NA>  <NA>   0  2 
9 E06000003 0 00EE Redcar and Cleveland UA  V0728   49  3 
10 E06000003 1 00EE Redcar and Cleveland UA  V0728   7  3 
11 E06000003 2 00EE Redcar and Cleveland UA  V0728   2  3 
12 E06000003 3 00EE Redcar and Cleveland UA  V0728   2  3 
13 E06000004 0 00EF  Stockton-on-Tees UA  H0738   40  4 
14 E06000004 1 00EF  Stockton-on-Tees UA  H0738   14  4 
15 E06000004 2 <NA>     <NA>  <NA>   0  4 

Concrètement, les niveaux de la les facteurs changent leur format et aussi dans certains cas les observations sont recodées à tort (par exemple oslaua = E06000001 - ligne 3)

Je ne comprends pas pourquoi les niveaux changent de format et comment je pourrais garder leur format original (alphanumérique). Aussi, pourquoi certaines observations ne sont pas recodées correctement.

Toute suggestion pour y remédier est très appréciée.

Merci!

Répondre

3

Voici une autre option à l'aide data.table

library(data.table) 
setDT(df)[, old.la1 := levels(droplevels(old.la)), by = oslaua] 

Pour plusieurs colonnes

nm1 <- c("old.la", "la", "dclg.code") 
df1 <- setDT(df)[, lapply(.SD, function(x) levels(droplevels(x))[1]) , 
     by = oslaua, .SDcols = nm1][df, on = "oslaua"] 
df1[, !grepl("i\\.", names(df1)), with = FALSE] 

Notre idée initiale était

setDT(df)[, (nm1) := lapply(.SD, function(x) 
    factor(levels(droplevels(x)))) , by = oslaua, .SDcols = nm1] 

Mais pour une raison quelconque, la conversion à l'intérieur de chaque groupe factor obtient une sortie bizarre ayant un seul niveau pour chaque colonne dans la sortie (en utilisant v1.10.0)

+1

Merci beaucoup @akrun, c'est exactement ce dont j'ai besoin. Je ne comprends toujours pas pourquoi cela a changé le format du facteur lorsque j'ai appliqué ma solution. – Edu

+1

@Edu Il a changé en 'character', mais après le' df1', vous pouvez reconvertir les colonnes en 'factor', c'est-à-dire' df2 <- df1 [,! Grepl ("i \\.", Noms (df1)), avec = FALSE]; df2 [, (nm1): = lapply (.SD, facteur), .SDcols = nm1] ' – akrun

1

Cela devrait fonctionner pour vous:

library(zoo) 

df %>% 
    group_by(oslaua) %>% 
    mutate(old.la.1 = na.locf(old.la)) 

Il utilise dernier reporté fonction de zoo pour remplacer des AN. C'est type sûr. Dans votre code, ifelse construit deux vecteurs (un pour le cas où le test se résout à TRUE, l'autre pour quand il résout à FALSE.) Pour assurer la compatibilité, il semble que ifelse réduit chacun de ceux au type commun le plus basique. dans le cas des facteurs, c'est un entier (dirigé typeof(df$old.la).

+0

Cela ne fonctionne que si la valeur NA n'est jamais le premier de son groupe, non? – mpjdem

+0

Vous avez raison. Cela pourrait être atténué en utilisant 'arrange' (forçant' NA' à la fin), mais probablement pas la solution idéale. La solution d'akrun pourrait également être implémentée dans le framework 'dplyr'. – Benjamin

+0

Cela pourrait être corrigé en utilisant 'na.aggregate' au lieu de' na.locf'. –

0

Alternativement, une solution plus élégante qui évite la création de nouvelles variables utiliserait fill() de tidyr:

data = data %>% group_by(oslaua) %>% fill(old.la, la, dclg.code) 
data 

Ce qui donne:

> data 
Source: local data frame [15 x 6] 
Groups: oslaua [4] 

     oslaua wave old.la      la dclg.code novo_entries 
     <fctr> <fctr> <fctr>     <fctr> <fctr>  <int> 
1 E06000001  0 00EB   Hartlepool UA  H0724   24 
2 E06000001  1 00EB   Hartlepool UA  H0724   4 
3 E06000001  2 00EB   Hartlepool UA  H0724   0 
4 E06000001  3 00EB   Hartlepool UA  H0724   1 
5 E06000002  0 00EC  Middlesbrough UA  W0734   35 
6 E06000002  1 00EC  Middlesbrough UA  W0734   15 
7 E06000002  2 00EC  Middlesbrough UA  W0734   1 
8 E06000002  3 00EC  Middlesbrough UA  W0734   0 
9 E06000003  0 00EE Redcar and Cleveland UA  V0728   49 
10 E06000003  1 00EE Redcar and Cleveland UA  V0728   7 
11 E06000003  2 00EE Redcar and Cleveland UA  V0728   2 
12 E06000003  3 00EE Redcar and Cleveland UA  V0728   2 
13 E06000004  0 00EF  Stockton-on-Tees UA  H0738   40 
14 E06000004  1 00EF  Stockton-on-Tees UA  H0738   14 
15 E06000004  2 00EF  Stockton-on-Tees UA  H0738   0