根据R中的条件删除数据框的列

Remove columns of dataframe based on conditions in R

我必须删除我的数据框中的列,它有超过 4000 列和 180 个 rows.The 我想设置以删除数据框中的列的条件是: (i) 如果该列中的 values/entries 少于两个,则删除该列 (ii) 如果没有两个连续的(一个接一个)删除该列 列中的值。 (iii) 删除所有值为 NA 的列。 我已经提供了删除列的条件。这里的目的不仅仅是像 "How do you delete a column in 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>)

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

# 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

感觉就这些了over-complicated。条件 2 已经包含了所有其他条件,就好像一列中至少有两个非 NA 值,显然整列都不是 NA。而如果一列中至少有两个连续的值,那么显然这一列包含的值不止一个。因此,而不是 3 个条件,这全部总结为一个条件(我不喜欢每列 运行 许多函数,而是在每列 运行 宁 diff 之后 - vecotriize 整个事情) :

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 D数据在data.table是)
  • .N 只是行数(类似于 nrow(df)
  • 下一步是按条件进行子集化。我们也不要忘记获取第一列,所以我们从 c(TRUE,...
  • 开始
  • 最后,data.table 默认情况下使用非标准评估,因此,如果您想 select 列就像在 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]