【问题标题】:Grouping columns with same missing value patterns in R在R中对具有相同缺失值模式的列进行分组
【发布时间】:2016-03-21 00:13:56
【问题描述】:

让我有这样一个数据框(df) 缺少值(NA)

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] 必须由具有 df$head1 和 df$head2 列的数据框 (df1) 组成
  • list1[2] 必须由具有 df$head3 和 df$head5 列的数据框 (df2) 组成
  • list1[3] 必须由具有列 df$head4 的数据框 (df3) 组成

如何使用 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

【问题讨论】:

  • 好的阿克伦。但是,我的第一个例子似乎不是一个真实的例子。在这种情况下,是否最好在不同的主题中询问这个新示例?
  • 第一个例子似乎很简单。我认为你可以有很多组合,即将每一列与许多其他列进行比较将是这里的场景(除非我没有记错)。是的,我的解决方案假设会有共同的元素。
  • 你的“data.frame”的dim是什么? is.na(df1) 为每一列返回一个二进制变量。因此,您可以将其用作到 split 列的映射。 IE。 split.default(df1, (t(is.na(df1)) %*% 2^(0:(nrow(df1) - 1L)))[, 1L]) 之类的东西,如果你有小的 nrow 或幼稚的 split.default(df1, apply(is.na(df1) + 0L, 2, paste, collapse = ""))
  • 这是一个大数据框,大约有 115,000 行和 140 列。

标签: r


【解决方案1】:

我们使用which 获取NA 元素的行/列索引,并指定arr.ind=TRUE。我们split "col" by "row",得到索引的unique 元素,如果缺少某些列,即没有 NA 值,我们可以将 (c) 连接到 @ 的末尾987654326@。然后,subset 通过循环遍历list (lapply(i2,..) 使用索引的数据集,我们可以通过每个list 元素中的第一列名称order 输出list ('l2') .

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

【讨论】:

  • 非常感谢阿克伦。这段代码工作得很好。非常聪明的解决方案。希望有一天能达到你的水平:)
  • @orcim 很高兴知道它对您有用。我不知道我是什么水平,但是每天练习,你会学到很多东西
【解决方案2】:

使用每列中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% NAs:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-29
    • 2013-02-05
    • 2021-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    相关资源
    最近更新 更多