选择或子集列总和不为零的变量

时间:2018-10-31 07:13:22

标签: r dplyr

我想在列总和不为零的数据框中选择变量或对其进行子集设置,同时还要保留其他因子变量。它应该很简单,但是我无法弄清楚如何使用select_if()在变量子集上运行dplyr函数:

df <- data.frame(
  A = c("a", "a", "b", "c", "c", "d"),
  B = c(0, 0, 0, 0, 0, 0),
  C = c(3, 0, 0, 1, 1, 2),
  D = c(0, 3, 2, 1, 4, 5)
)

require(dplyr)
df %>% 
  select_if(funs(sum(.) > 0))

#Error in Summary.factor(c(1L, 1L, 2L, 3L, 3L, 4L), na.rm = FALSE) : 
#  ‘sum’ not meaningful for factors

然后我尝试仅选择B, C, D可行,但我没有变量A

df %>% 
  select(-A) %>% 
  select_if(funs(sum(.) > 0)) -> df2
df2
#  C D
#1 3 0
#2 0 3
#3 0 2
#4 1 1
#5 1 4
#6 2 5

我可以简单地cbind(A = df$A, df2)做,但由于我有一个数据集3000行和200列,恐怕这会引入错误(例如,如果值的排序方式不同)。

尝试在B, C, D函数中对变量sum()进行子集化无法正常工作要么:

df %>% 
  select_if(funs(sum(names(.[2:4])) > 0))
#data frame with 0 columns and 6 rows

3 个答案:

答案 0 :(得分:6)

尝试一下:

df %>% select_if(~ !is.numeric(.) || sum(.) != 0)
#   A C D
# 1 a 3 0
# 2 a 0 3
# 3 b 0 2
# 4 c 1 1
# 5 c 1 4
# 6 d 2 5

基本原理是,对于||,如果左侧为TRUE,则不会评估右侧。

注意:

  • select_if的第二个参数应该是函数名称或公式(lambda函数)。必须使用~来告诉select_if !is.numeric(.) || sum(.) != 0应该转换为函数。
  • 如@ zx8754下文所述,如果只想保留is.factor(.)列,则应使用factor

编辑:基本的R解决方案

cols <- c('B', 'C', 'D')
cols.to.keep <- cols[colSums(df[cols]) != 0]
df[!names(df) %in% cols || names(df) %in% cols.to.keep]

答案 1 :(得分:3)

以下更新适用于所有想要使用没有作用域变体的新 dplyr 1.0.0(例如 select_if,@mt1022 很好地展示了但已弃用):

df %>% 
  select(where(is.numeric)) %>% 
  select(where(~sum(.) != 0))

如果您想将两个 select 语句压缩为一个,则不能通过按元素的 & 而是通过更长的形式 && 来执行此操作,因为这会产生所需的布尔输出:

df %>% select(where(~ is.numeric(.x) && sum(.x) !=0 ))

答案 2 :(得分:1)

这是使用data.table的解决方案

df<-data.table(
  A = c("a", "a", "b", "c", "c", "d"),
  B = c(0, 0, 0, 0, 0, 0),
  C = c(3, 0, 0, 1, 1, 2),
  D = c(0, 3, 2, 1, 4, 5)
)

df2<-df[,lapply(X = .SD,FUN = function(x){sum(as.numeric(x))}),.SDcols = colnames(df)]
df[,which(is.na(df[1,]) == F),with = F]