【问题标题】:Remove columns of dataframe based on conditions in R根据 R 中的条件删除数据框的列
【发布时间】:2016-04-26 11:05:34
【问题描述】:

我必须删除包含超过 4000 列和 180 行的数据框中的列。我要设置以删除数据框中的列的条件是: (i) 如果该列中的值/条目少于两个,则删除该列 (ii) 如果没有两个连续的列(一个接一个),则删除该列 列中的值。 (iii) 删除所有值为 NA 的列。 我已经提供了删除列的条件。此处的目的不仅仅是像“如何删除 data.table 中的列?”那样按名称查找列。 我说明如下:

A       B    C   D  E
0.018  NA    NA  NA NA
0.017  NA    NA  NA NA
0.019  NA    NA  NA NA
0.018  0.034 NA  NA NA
0.018  NA    NA  NA NA
0.015  NA    NA  NA 0.037
0.016  NA    NA  NA 0.031
0.019  NA    0.4 NA 0.025
0.016  0.03  NA  NA 0.035
0.018  NA    NA  NA 0.035
0.017  NA    NA  NA 0.043
0.023  NA    NA  NA 0.040
0.022  NA    NA  NA 0.042

所需的数据框:

A       E
0.018   NA
0.017   NA
0.019   NA
0.018   NA
0.018   NA
0.015   0.037
0.016   0.031
0.019   0.025
0.016   0.035
0.018   0.035
0.017   0.043
0.023   0.040
0.022   0.042

如何将这三个条件合并到一个代码中。我将感谢您在这方面的帮助。 可重现的例子

structure(list(Month = c("Jan-2000", "Feb-2000", "Mar-2000", 
"Apr-2000", "May-2000", "Jun-2000"), A.G.L.SJ.INVS...LON..DEAD...13.08.15 = c(NA_real_, 
NA_real_, NA_real_, NA_real_, NA_real_, NA_real_), ABACUS.GROUP.DEAD...18.02.09 = c(0.00829384766220866, 
0.00332213653674028, 0, 0, NA, NA), ABB.R..IRS. = c(NA_real_, 
NA_real_, NA_real_, NA_real_, NA_real_, NA_real_)), .Names = c("Month", 
"A.G.L.SJ.INVS...LON..DEAD...13.08.15", "ABACUS.GROUP.DEAD...18.02.09", 
"ABB.R..IRS."), class = c("data.table", "data.frame"), row.names = c(NA, 
-6L), .internal.selfref = <pointer: 0x0000000001c90788>)

【问题讨论】:

  • 对于(i):df[,sapply(df, function(x) sum(!is.na(x))&gt;1)]
  • @Frank 此处删除列是基于条件而不是名称。
  • @Aquarius 在链接的q中,这些也是条件。它们只是基于名称而不是值向量的条件。我不认为它有本质上的不同。我也认为目标链接很有帮助,因为它显示了:= NULL,这是如何通过引用删除列(而不是创建一个全新的表)。
  • @Frank 好吧,我认为这里的决定有点苛刻。
  • 你不应该这样看。问一个被标记为欺骗的问题并没有错。骗子和他们的回答也对网站有帮助(因为人们也可以在谷歌搜索结果中找到你的问题)。我认为,标记为骗子只会更容易找到相关问题。这是该网站的联合创始人关于它的博客文章:blog.stackoverflow.com/2010/11/…

标签: r dataframe data.table multiple-columns


【解决方案1】:

我觉得这一切都过于复杂了。条件2已经包含了其余所有条件,好像一列中至少有两个非NA的值,显然整列都不是NAs。如果一列中至少有两个连续的值,那么显然该列包含多个值。因此,这不是 3 个条件,而是全部归结为一个条件(我不希望每列运行许多函数,而是在每列运行 diff 之后 - 对整个事物进行矢量化):

cond <- colSums(is.na(sapply(df, diff))) < nrow(df) - 1

这是有效的,因为如果一列中没有连续的值,整列将变为NAs。

那么,就

df[, cond, drop = FALSE]
#        A     E
# 1  0.018    NA
# 2  0.017    NA
# 3  0.019    NA
# 4  0.018    NA
# 5  0.018    NA
# 6  0.015 0.037
# 7  0.016 0.031
# 8  0.019 0.025
# 9  0.016 0.035
# 10 0.018 0.035
# 11 0.017 0.043
# 12 0.023 0.040
# 13 0.022 0.042

根据您的编辑,您似乎有一个 data.table 对象,并且您还有一个 Date 列,因此代码需要进行一些修改。

cond <- df[, lapply(.SD, function(x) sum(is.na(diff(x)))) < .N - 1, .SDcols = -1] 
df[, c(TRUE, cond), with = FALSE]

一些解释:

  • 我们希望忽略计算中的第一列,因此在对 .SD 进行操作时指定 .SDcols = -1(这意味着 Sub Data in @987654333 @是)
  • .N 只是行数(类似于 nrow(df)
  • 下一步是按条件进行子集化。我们也不必忘记抓住第一列,所以我们从c(TRUE,... 开始
  • 最后,data.table 默认使用非标准评估,因此,如果您想像在data.frame 中一样选择列,则需要指定with = FALSE

不过,更好的方法是使用 := NULL 通过引用删除列

cond <- c(FALSE, df[, lapply(.SD, function(x) sum(is.na(diff(x)))) == .N - 1, .SDcols = -1])
df[, which(cond) := NULL]

【讨论】:

【解决方案2】:

为每个条件创建逻辑向量:

# condition 1
cond1 <- sapply(df, function(col) sum(!is.na(col)) < 2)

# condition 2
cond2 <- sapply(df, function(col) !any(diff(which(!is.na(col))) == 1))

# condition 3
cond3 <- sapply(df, function(col) all(is.na(col)))

然后将它们组合成一个掩码:

mask <- !(cond1 | cond2 | cond3)

> df[,mask,drop=F]
       A     E
1  0.018    NA
2  0.017    NA
3  0.019    NA
4  0.018    NA
5  0.018    NA
6  0.015 0.037
7  0.016 0.031
8  0.019 0.025
9  0.016 0.035
10 0.018 0.035
11 0.017 0.043
12 0.023 0.040
13 0.022 0.042

【讨论】:

  • 仅供参考,这里只需要条件 2,可以简化为 cond2 &lt;- sapply(df, function(col) any(!is.na(diff(col)))),你就可以开始了。其余所有条件都是多余的。
  • OP 对 R 来说似乎是新的,所以我选择了一个更清晰(如果多余的话)的答案,希望能展示一种在未来有用的模式。虽然可以在 this 示例中组合条件,但情况可能并非总是如此。
  • 我为提供低效信息来执行此任务承担所有责任。我是新来的,对软件缺乏经验。我很抱歉,但答案 2 最符合我的要求。希望您能理解。
猜你喜欢
  • 1970-01-01
  • 2016-04-07
  • 1970-01-01
  • 2023-02-23
  • 1970-01-01
  • 2021-03-06
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
相关资源
最近更新 更多