【问题标题】:Delete empty dataframes from List从列表中删除空数据框
【发布时间】:2021-11-06 09:54:02
【问题描述】:

在 for 循环中包含我正在使用的以下数据框列表。这里我有两个空数据框,x[[2]] 和 x[[4]]。如果我这样做,我该如何在我的 for 循环中删除 then:

for (i in 1:length(x)){
 ****x[[i]] = ***remove empty dataframes in x[[i]]***
}

数据集:

    x <- list(structure(list(`8935364000175` = c(0.0060428512369981, 0.00603116477577714, 
0.00601948031544453, 0.00584680183237651, 0.00588356233492959, 
0.00604482211201685, 0.00595391284150537, 0.00612897711107507, 
0, 0.00608207737968769), `25079578000106` = c(0.0561319890039158, 
0.0713528263077023, -0.310352321776008, 0.244770088829682, 0.0361304175385158, 
-0.215327063233417, -0.0463209246845508, 0, 0.0781647175244871, 
0.0306871725115343)), row.names = c("Retorno D - 260", "Retorno D - 259", 
"Retorno D - 258", "Retorno D - 257", "Retorno D - 256", "Retorno D - 255", 
"Retorno D - 254", "Retorno D - 253", "Retorno D - 252", "Retorno D - 251"
), class = "data.frame"), structure(list(), row.names = c("Retorno D - 260", 
"Retorno D - 259", "Retorno D - 258", "Retorno D - 257", "Retorno D - 256", 
"Retorno D - 255", "Retorno D - 254", "Retorno D - 253", "Retorno D - 252", 
"Retorno D - 251"), class = "data.frame"), structure(list(`25079578000106` = c(-0.0284871479379945, 
0.141976900522423, -0.115634388475883, 0.0858369759953348, 0.252102295598888, 
-0.130994651044603, 0.213179273123387, 0, 0.254748840234242, 
-0.162688137697842), `19107923000175` = c(-2.542040795106, -1.30722252988562, 
0.166101507966232, -0.333577277251607, -0.48391700402135, -0.287302340893802, 
0.276978237343428, 0, -2.20114477424431, 2.28636453339277), `15674503000110` = c(0.151917711446004, 
0.27261553095741, -0.0217761778003478, 0.0357082184564206, 0, 
-0.430589756888367, 0.0980497330601793, 0.162832113528566, 0.135437075368827, 
0.0254803373536561), `19391009000107` = c(0.118515970461885, 
0.0201793494852609, 0.05212900123297, -0.122335026844667, 0, 
-0.173768502372695, -0.146583881632978, -0.102553665146843, -0.161486374236119, 
0.522601667762501), `26111809000184` = c(0.188357122169691, 0.597206398924754, 
-0.117262560343079, -0.350788641299005, 0, -0.427825340193522, 
0.0359309879058856, 0.144902896136045, 0.43725947070925, 0.0456868876426597
), `32666326000149` = c(1.84565666459093, 3.33521612974437, -0.706821796120494, 
-1.41998375802359, 0, -1.00702592444577, -0.764259576953918, 
0.504494091364904, 2.34908743768756, 1.12513038984616)), row.names = c("Retorno D - 260", 
"Retorno D - 259", "Retorno D - 258", "Retorno D - 257", "Retorno D - 256", 
"Retorno D - 255", "Retorno D - 254", "Retorno D - 253", "Retorno D - 252", 
"Retorno D - 251"), class = "data.frame"), structure(list(), row.names = c("Retorno D - 260", 
"Retorno D - 259", "Retorno D - 258", "Retorno D - 257", "Retorno D - 256", 
"Retorno D - 255", "Retorno D - 254", "Retorno D - 253", "Retorno D - 252", 
"Retorno D - 251"), class = "data.frame"))

【问题讨论】:

    标签: r list dataframe loops for-loop


    【解决方案1】:

    我喜欢在这种情况下使用purrr::keeppurrr:::discard,而不是for 循环。下面的代码discards 所有带有ncol==0nrow==0 的列表元素('empty' data.frames):

    library(purrr)
    
    new_x <- discard(x, ~ncol(.x)==0 || nrow(.x)==0)
    
    # OR with `length(as.matrix)`:
    
    new_x <- discard(x, ~length(as.matrix(x))==0)
    
    str(new_x)
    List of 2
     $ :'data.frame':   10 obs. of  2 variables:
      ..$ 8935364000175 : num [1:10] 0.00604 0.00603 0.00602 0.00585 0.00588 ...
      ..$ 25079578000106: num [1:10] 0.0561 0.0714 -0.3104 0.2448 0.0361 ...
     $ :'data.frame':   10 obs. of  6 variables:
      ..$ 25079578000106: num [1:10] -0.0285 0.142 -0.1156 0.0858 0.2521 ...
      ..$ 19107923000175: num [1:10] -2.542 -1.307 0.166 -0.334 -0.484 ...
      ..$ 15674503000110: num [1:10] 0.1519 0.2726 -0.0218 0.0357 0 ...
      ..$ 19391009000107: num [1:10] 0.1185 0.0202 0.0521 -0.1223 0 ...
      ..$ 26111809000184: num [1:10] 0.188 0.597 -0.117 -0.351 0 ...
      ..$ 32666326000149: num [1:10] 1.846 3.335 -0.707 -1.42 0 ...
    

    【讨论】:

    • @Ben Bolker,这会让它更加一致吗?我很确定您提到的问题有解决方法:discard(x, ~ncol(.x)==0 | nrow(.x)==0)
    • 还有这个:length(as.matrix(.x))==0
    • 是的,但这可能很昂贵。
    • 如果我的对象名为“Z”,例如,我需要在 ~nrow(.x) 行中放入什么? ~nrow(.Z) 还是 ~nrow(.x)?此处出错
    • 这不是基于循环的解决方案,因此您可能不想要它。 .x 硬编码在 discard 中(即,不依赖于对象的实际名称):你会想要 discard(Z, ~ncol(.x)==0)(在你的情况下)
    【解决方案2】:

    更简单的测试数据:

    x <- list(data.frame(x=1:3), data.frame(x=numeric(0)), data.frame(x=1:4))
    

    我会推荐(没有for 循环):

    is_empty <- function(x) (nrow(x)==0 || ncol(x) ==0)
    x <- x[sapply(x, is_empty)] 
    

    ?如果数据框为空,这将创建一个逻辑向量 TRUE,并相应地对原始列表进行子集化。

    将列表的元素设置为NULL (x[[i]] &lt;- NULL) 会将其从列表中删除,但我担心您的索引会搞砸。要做到这一点非常棘手,因为循环会在您的控制下发生变化。例如,考虑

    x <- list(data.frame(x=1:3), data.frame(x=numeric(0)),
              data.frame(x=numeric(0)))
    for (i in 1:length(x)) {
       if (nrow(x[[i]])==0) x[[i]] <- NULL
    }
    

    这会得到“x[[i]] 中的错误:下标超出范围”,因为

    1. i==1,检查x[[1]]:好的,继续下一个元素
    2. i==2;删除第二个元素。现在我们有一个只有两个元素(前面的第一个和第三个元素)的列表
    3. i==3;错误,因为x[[3]] 不存在!

    可以这样做以避免弄乱索引:

    j <- 0  ## cumulative number removed
    for (i in seq(length(x))) {
      if (is_empty(x[[i-j]])) {
         x[[i-j]] <- NULL
         j <- j + 1
      }
    }
    

    但这似乎是一种“代码味道”,即你必须更加努力地工作,因为你的工作方式很尴尬。

    【讨论】:

    • 如果我在循环中使用它,我会得到这个结果: for (i in 1:length(x)){ x[[i]] = x[[i]][sapply(x [[i]], nrow) > 0] } "[.data.frame(x[[i]], sapply(x[[i]], nrow) > 0) 中的错误:'list' 对象不能被强制输入'双'"
    • 不要在循环中使用它!
    • 有没有办法可以在循环中使用它?一直在处理 200 行代码循环,如果我不必结束循环而只需在下一行序列中开始另一个循环来完成我的转换,那就太好了。
    • 这很棘手,因为如果你不小心,索引会搞砸。例如如果你在i==2 时设置x[[2]] &lt;- 0,那么你下面的循环会改变,并且会有一个new 第二个元素来测试。
    • 这个答案是否无法删除空数据帧,即 OP 的数据,它的 data.frames 的 nrow=10 但 ncol=0?
    【解决方案3】:
    for (i in 1:length(x)) {
      if ( ncol(x[[i]]) == 0) {
        x[[i]] <- NULL
      }
    }
    x
    

    如果您看到:“x[[i]] 中的错误:下标超出范围。”就没有问题。问题解决了。

    【讨论】:

    • 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。
    • 你能证明这不会跳过/无法测试某些输入的某些元素吗?可能没问题,但我想被说服。
    • 另外,在代码中出现错误是非常有问题的 - 如果这是在非交互式工作流程的中间怎么办?
    • 这不适用于所有输入。 ff &lt;- function(x) {for (i in seq(length(x))) { try(if (nrow(x[[i]])==0) x[[i]] &lt;- NULL) }; return(x)}; f &lt;- data.frame(x=1:3); e &lt;- data.frame(x=numeric(0)); ff(list(e,e,f)) 表明我们在结果中仍然有一个空数据框。 (我使用nrow() 而不是ncol() 测试来匹配我的测试数据...)
    • 如果不是采样数据集,解决方案就可以了。不幸的是,它是 100 个项目列表中的一个示例,此代码不能完全适用。对不起
    猜你喜欢
    • 2011-03-16
    • 2021-01-12
    • 1970-01-01
    • 1970-01-01
    • 2021-10-19
    • 2016-03-13
    • 2017-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多