【问题标题】:subset of data.frame columns to maximize "complete" observationsdata.frame 列的子集以最大化“完整”观察
【发布时间】:2014-07-23 20:58:49
【问题描述】:

我有一个数据框,其中包含大约 20 个数字列,每个列都包含大量的 NA 值。我想选择这些列的一个子集,这将为我提供包含零 NA 值的最多行。详尽的搜索会花费大量的计算时间——有没有更好的方法来获得近似值?

这是一个数据框较小的示例(完全任意):

set.seed(2)
foo = as.data.frame(matrix(rnorm(200), nr = 20))
foo[sapply(foo, function(x) x > abs(x[1]))] = NA
foo = foo[-1, ]

round(foo, 3)

       V1     V2     V3     V4     V5     V6     V7     V8     V9    V10
2   0.185 -1.200 -1.959     NA -1.696  0.261  0.139  0.410 -0.638 -1.262
3      NA  1.590 -0.842 -0.703 -0.533 -0.314     NA -0.807 -0.268  0.392
4  -1.130  1.955     NA  0.158 -1.372 -0.750 -0.431  0.086  0.360 -1.131
5  -0.080  0.005     NA  0.506 -2.208 -0.862 -1.044     NA -1.313  0.544
6   0.132 -2.452     NA -0.820     NA     NA  0.538 -0.654 -0.884     NA
7   0.708  0.477 -0.305 -1.999 -0.653  0.940 -0.670     NA     NA  0.025
8  -0.240 -0.597 -0.091 -0.479 -0.285     NA  0.639  0.550 -2.099  0.515
9      NA  0.792 -0.184  0.084 -0.387 -0.421 -1.724 -0.807 -1.239 -0.654
10 -0.139  0.290 -1.199 -0.895  0.387 -0.351 -1.742 -0.997     NA  0.504
11  0.418  0.739 -0.838 -0.921     NA -1.027  0.690     NA     NA -1.272
12     NA  0.319     NA  0.330     NA -0.251  0.331 -0.169     NA -0.077
13 -0.393  1.076 -0.562 -0.142 -1.184  0.472  0.871     NA  0.057 -1.345
14 -1.040 -0.284     NA  0.435 -1.358     NA -2.016 -0.844  0.324 -0.266
15     NA -0.777 -1.048 -0.054 -1.513  0.564  1.213     NA -0.905     NA
16 -2.311 -0.596 -1.966 -0.907 -1.253  0.456  1.200 -1.343 -0.652  0.701
17  0.879 -1.726 -0.323  1.304     NA     NA  1.032     NA -0.262 -0.443
18  0.036 -0.903     NA  0.772  0.008     NA  0.786  0.464 -0.935 -0.789
19     NA -0.559     NA  1.053 -0.843  0.107     NA  0.268     NA -0.857
20  0.432 -0.247     NA -1.410 -0.601 -0.783 -1.454     NA -1.624 -0.746

dim(na.omit(foo))
[1]  1 10

这是我制定详尽搜索的方式:

best.list = list()
for (i in 5:ncol(foo)) {
    # get best subset for each size
    collist = combn(ncol(foo), i)
    numobs = apply(collist, 2, function(x) nrow(na.omit(foo[, x])))
    cat("for subset size", i, "most complete obs is", max(numobs), "\n")
    best = which(numobs == max(numobs))[1]
    best.list = c(best.list, list(collist[, best]))
}

例如,best.list[[1]] 告诉我,如果我保留 5 列,我可以有 12 个完整的观察值(NA 为零的行),我应该选择第 1、2、4、7 和 10 列。

虽然这适用于非常小的数据帧,但对于较大的数据帧,它很快就会变得令人望而却步。 R中有没有办法有效地估计给定大小的最佳子集?我唯一能找到的是subselect 包,尽管我不知道如何为手头的问题实现它的方法。

【问题讨论】:

  • 您真的需要最好的解决方案来解决您的问题吗?如果您可以接受近似值,那么贪婪的方法可能会有所帮助(至少很容易)。一次选择一列,在每个步骤中选择一个与您已经选择的列一起产生最完整案例的列。
  • ...具体来说,您有一个离散优化问题。定义X <- (is.na(foo))+0。那么你的问题相当于找到一个 0/​​1 向量 vsum(v)==ksum((X%*%v)[,1]==0) 最大。可能在 R 中解决这个问题的具体方法是您最不用担心的,R 在优化方面并不是很强大 - 您可能需要先考虑算法。 CRAN 优化任务视图可能会有所帮助,虽然我没有马上找到任何东西:cran.r-project.org/web/views/Optimization.html
  • 一个近似值很好。我对优化知之甚少,但我得到了贪婪算法的要点。我会试试看的。

标签: r optimization mathematical-optimization subquery


【解决方案1】:

旧帖子,但有一个内置函数可以做到这一点。我敢打赌它非常有效:

df_noNAs <- df[complete.cases(df[,1:20]),]

【讨论】:

    【解决方案2】:

    不确定这是否是完整的解决方案,但如果您想要快速的结果,data.table 和阴影矩阵是最可能的成分。

    library(data.table)
    df = data.table(foo) # your foo dataframe, converted to data.table
    
    y = sort(df[,lapply(.SD, function(x) sum(is.na(x)))]) # nr of NA in columns, increasing
    setcolorder(df, names(y)) # now the columns are ordered - less NA first
    
    df[, idx := rowSums(is.na(df))] # count nr of NA in rows
    df = df[order(idx),] # sort by nr of NA in rows
    df[, idx := NULL] # idx not needed anymore
    # now your data.table is sorted: columns with least NA to the left,  
    # rows with with least NA on top
    
    # shadow matrix
    x= data.table(abs(!is.na(df)))  # 0 = NA value
    y = as.data.table(t(x))
    y = y[,lapply(.SD, cumprod)]
    y = as.data.table(t(y))
    y[,lapply(.SD, sum)] 
    
    # nr of complete cases from column selections:
    # V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
    # 1: 19 18 16 14 11 10  7  5  2   1
    

    【讨论】:

    • 这似乎是一个很好的近似值。我将它与几个 15 列矩阵的精确解决方案进行了比较,它通常在真实答案的 1 或 2 范围内。有没有关于错误如何随着更大的数据帧扩展的理论?
    • 不知道是什么导致了微小的差异[除了可能在同一行中重复计算 NA?]。顺便说一句,不需要[通过 idx 列]对行进行 NA 排序。将它们注释掉,你会得到相同的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    • 1970-01-01
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多