在R中对具有相同缺失值模式的列进行分组

时间:2016-03-19 19:59:40

标签: r

让我有一个具有缺失值(NA)的数据帧(df)

DF:

head1    head2  head3   head4  head5
-----    -----  -----   -----  -----
65       25     12      65     76
78       5      NA      12     NA
NA       NA     12      5      51
76       32     6       94     11
67       32     NA      1      NA

我想创建一个列表(list1),每个元素由具有相同NA模式的数据帧组成。

对于这个例子:

  • list1 [1]必须包含一个数据框(df1),列df $ head1和df $ head2
  • list1 [2]必须包含一个数据框(df2),列df $ head3和df $ head5
  • list1 [3]必须包含一个数据框(df3),列df $ head4

如何使用R创建这样的列表?我会很高兴得到任何帮助。非常感谢。

@akrun,我意识到你的代码适用于NA列不是每列常见的数据帧。但不适用于以下数据框架。

df1<-data.frame(head1=c(65,78,NA,76,67),
                head2=c(25,5,NA,32,32),
                head3=c(12,12,NA,6,NA),
                head4=c(65,12,5,94,1),
                head5=c(76,NA,51,11,NA)
)



i1 <- which(is.na(df1), arr.ind=TRUE)
l1 <- unique(split(i1[,2], i1[,1]))
i2 <- c(l1, setdiff(seq_along(df1), unlist(l1)))
l2 <- lapply(i2, function(i) df1[i]) 
l2[order(sapply(l2, function(x) colnames(x)[1]))] 

结果是:

[[1]]
  head1 head2 head3
1    65    25    12
2    78     5    12
3    NA    NA    NA
4    76    32     6
5    67    32    NA

[[2]]
  head3 head5
1    12    76
2    12    NA
3    NA    51
4     6    11
5    NA    NA

[[3]]
  head4
1    65
2    12
3     5
4    94
5     1

[[4]]
  head5
1    76
2    NA
3    51
4    11
5    NA

2 个答案:

答案 0 :(得分:1)

我们使用which获取NA元素的行/列索引并指定arr.ind=TRUE。我们split&#34; col&#34;通过&#34; row&#34;,获取索引的unique元素,如果有一些列缺失,即没有NA值,我们可以连接(c)到结尾list。然后,subset数据集使用索引循环listlapply(i2,..),我们可以order输出list(&#39; l2& #39;)按每个list元素中的第一个列名称。

i1 <- which(is.na(df1), arr.ind=TRUE)
l1 <- unique(split(i1[,2], i1[,1]))
i2 <- c(l1, setdiff(seq_along(df1), unlist(l1)))
l2 <- lapply(i2, function(i) df1[i]) 
l2[order(sapply(l2, function(x) colnames(x)[1]))]
#[[1]]
# head1 head2
#1    65    25
#2    78     5
#3    NA    NA
#4    76    32
#5    67    32

#[[2]]
#  head3 head5
#1    12    76
#2    NA    NA
#3    12    51
#4     6    11
#5    NA    NA

#[[3]]
#  head4
#1    65
#2    12
#3     5
#4    94
#5     1

答案 1 :(得分:1)

使用每列中的NA值索引,您可以将每列映射为“字符”值:

map = sapply(df1, function(X) paste(which(is.na(X)), collapse = ";"))
map
#head1 head2 head3 head4 head5 
#  "3"   "3" "3;5"    "" "2;5"

然后,相应地split列:

split.default(df1, match(map, unique(map)))
#> str(.Last.value)
#List of 4
# $ 1:'data.frame':      5 obs. of  2 variables:
#  ..$ head1: num [1:5] 65 78 NA 76 67
#  ..$ head2: num [1:5] 25 5 NA 32 32
# $ 2:'data.frame':      5 obs. of  1 variable:
#  ..$ head3: num [1:5] 12 12 NA 6 NA
# $ 3:'data.frame':      5 obs. of  1 variable:
#  ..$ head4: num [1:5] 65 12 5 94 1
# $ 4:'data.frame':      5 obs. of  1 variable:
#  ..$ head5: num [1:5] 76 NA 51 11 NA

对于实际尺寸的数据,性能似乎是可以忍受的:

set.seed(666)
DF = as.data.frame(matrix(sample(c(NA, 1:10), 115000 * 100, TRUE), 115000, 100))
DF = DF[, sample(ncol(DF), 140, TRUE)]

system.time({
    map = sapply(DF, function(X) paste(which(is.na(X)), collapse = ";"))  
    split.default(DF, match(map, unique(map)))
})
#   user  system elapsed 
#   1.64    0.00    1.67

...除非每列中有~60%NA个:

set.seed(911)
DF2 = as.data.frame(replicate(100, sample(c(NA, 1:2), 115000, TRUE, c(0.6, 0.2, 0.2)), simplify = FALSE))
DF2 = DF2[, sample(ncol(DF2), 140, TRUE)]

system.time({
    map = sapply(DF2, function(X) paste(which(is.na(X)), collapse = ";"))  
    split.default(DF2, match(map, unique(map)))
})
#   user  system elapsed 
#   8.70    0.09    8.99