的R - 重新编码NA与因子的水平在分组数据

问题描述:

我有一个纵向结构的数据帧如下:的R - 重新编码NA与因子的水平在分组数据

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") 

我的标识符变量是oslaua和我的时间变量为waveold.la,ladclg.code是具有NA的因子变量。我的 目标包括通过与每个标识符(oslaua)关联的每个变量的级别重新编码我的NA。我试图使用的old.la的情况下做到这一点,以下:

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

我部分地得到我的目的,但也有一些问题,你可以看到:

> 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 

具体而言,的水平因素会改变它们的格式,并且在某些情况下观察记录错误(例如oslaua = E06000001 - 第3行)

我不明白为什么水平会改变它们的格式以及我如何保留它们的原始(字母数字)格式。此外,为什么一些观察记录没有正确记录。

任何建议来解决这些真的很感激。

谢谢!

下面是使用data.table

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

对于多个列的另一种选择

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] 

我们的最初的想法是

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

但由于某些原因,转换为factor每个组内得到具有在输出只为每一列单级一些怪异输出(使用v1.10.0)

+1

非常感谢@akrun,那正是我所需要的。当我申请我的解决方案时,我仍然不明白为什么它会改变这个因素的格式。 – Edu

+1

@Edu它变成了'character',但是在'df1'之后,你可以将列转换为'factor',即'df2 akrun

这应该为你工作:

library(zoo) 

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

它采用zoo的最后一个结转功能来代替NA的。它是安全的。在您的代码中,ifelse正在构建两个向量(一个用于测试解析为TRUE,另一个用于解析为FALSE的情况。为确保兼容性,似乎ifelse将这些向量都减少为最基本的常见类型。在因素的情况下,这是一个整数(运行typeof(df$old.la)

+0

这只适用于NA值永远不是它的第一组,否? – mpjdem

+0

你是对的。这可以通过使用'arrange'来缓解(最终迫使'NA'),但可能不是理想的解决方案。 akrun的解决方案也可以在'dplyr'框架中实现。 – Benjamin

+0

这可以通过使用'na.aggregate'而不是'na.locf'来解决。 –

或者,避免造成新的变数更优雅的解决方案将使用fill()tidyr

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

其中收益率:

> 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