如何从列表中删除空数据框?

29

我有几十个列表,每个列表都是11个数据框的集合。一些数据框是空的(另一个脚本没有输出任何数据,不是bug)。

我需要将每个列表传递给一个函数,但是当它看到一个空的数据框时会出现问题。那么我该如何编写一个函数,该函数将获取一个列表,对其中每个元素(即数据框)执行dim操作,如果其为0,则跳到下一个。

我尝试了类似于以下代码:

empties <- function (mlist)
{
 for(i in 1:length(mlist))
   {
    if(dim(mlist[[i]])[1]!=0) return (mlist[[i]])
    }
}

但显然,那并不起作用。此时我会手动完成,但那需要很长时间。有什么办法吗?

4个回答

34
我不确定这是否完全符合你的要求,但如果你想在运行该函数之前将mlist裁剪为仅包含非空数据帧,请尝试使用mlist[sapply(mlist, function(x) dim(x)[1]) > 0]
例如:
R> M1 <- data.frame(matrix(1:4, nrow = 2, ncol = 2))
R> M2 <- data.frame(matrix(nrow = 0, ncol = 0))
R> M3 <- data.frame(matrix(9:12, nrow = 2, ncol = 2))
R> mlist <- list(M1, M2, M3)
R> mlist[sapply(mlist, function(x) dim(x)[1]) > 0]
[[1]]
  X1 X2
1  1  3
2  2  4

[[2]]
  X1 X2
1  9 11
2 10 12

嵌套列表怎么办?我需要循环吗? - Bonono

17

使用Filter()函数是一种稍微简单且更透明的方法,可以替代sapply/indexing组合:

> Filter(function(x) dim(x)[1] > 0, mlist)
[[1]]
  X1 X2
1  1  3
2  2  4

[[2]]
  X1 X2
1  9 11
2 10 12

有什么想法可以提高性能吗? - TMOTTM
@TMOTTM,我认为它们应该几乎完全相同。 (但是请尝试并告诉我们如果不是!) - Harlan
使用nrow(x)> 0代替dim(x)[1]> 0。 简洁为上 - Tunn
1
嵌套列表怎么办?我需要循环吗? - Bonono
1
从评论中得知:一些匿名编辑建议您尝试使用Filter(function(x) length(x) > 0, mlist),它的性能更好。 - SergGr
@SergGr我认为那样不行。length()应用于data.frame时得到的是列数,而不是行数。(因为data.frame是带有一些元数据的列表,而length是作用于列表上的函数。)所以,如果原始帖子中的"empty"是指"没有列",那么这个过滤器可能会起作用,但这可能不是原意... - Harlan

8

你可以使用nrow代替dim(x)[1],这样你就可以这样做:

mlist[sapply(mlist, nrow) > 0]

Filter(function(x) nrow(x) > 0, mlist)

您还可以使用purrr中的keepdiscard

purrr::keep(mlist, ~nrow(.) > 0)
purrr::discard(mlist, ~nrow(.) == 0)

purrr中还有一个compact,它可以直接移除所有空元素。它是discard的封装。

purrr::compact(mlist)

如果您愿意根据列数过滤列表,您可以将上面的答案中的nrow替换为ncol。另外,您也可以使用lengths来过滤该列表。
mlist[lengths(mlist) > 0]

1

添加tidyverse选项:

library(tidyverse)
mlist[map(mlist, function(x) dim(x)[1]) > 0]


mlist[map(mlist, ~dim(.)[1]) > 0]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接