【问题标题】:Delete multiple rows based on some constrains根据某些约束删除多行
【发布时间】:2016-02-07 17:51:15
【问题描述】:

我正在使用 R,我正在尝试根据一些约束从数据框中删除一些行。所以,如果我得到了

dat <- data.frame(Cs=c("c1","c2","c3","c4","c5","c6"),  
  R1=sample(c("Y","N"),6,replace=TRUE), R2=sample(c("Y","N"),6,replace=TRUE),
  R3=sample(c("Y","N"),6,replace=TRUE), R4=sample(c("Y","N"),6,replace=TRUE),
  R5=sample(c("Y","N"),6,replace=TRUE), R6=sample(c("Y","N"),6,replace=TRUE))

我想删除在某些给定列(例如 R1、R3、R4)处具有“N”的所有行。对于一列,我找到了这个解决方案:delete row for certain constrains

d <- dat[dat[,"R1"]!="N",]

效果很好。但是如果我把多个列作为

d <- dat[dat[,c("R1","R3","R4")]!="N",]

我有很多额外的行充满了 NA。那我哪里错了?

【问题讨论】:

  • 如果您感兴趣的任何列中有任何“N”,您要删除该行吗?
  • 没错!我忘了说。对不起
  • 试试dat[rowSums(dat == "N") == 0, ]
  • 它似乎不起作用。我有一个空的数据框
  • @Stefano,这可能是因为您测试的样本中没有没有 N 的行

标签: r dataframe filtering delete-row


【解决方案1】:

你可以使用

dat[rowSums(dat[, c("R1","R3","R4")] == "N") == 0, , drop=FALSE]
#  Cs R1 R2 R3 R4 R5 R6
#5 c5  Y  Y  Y  Y  Y  Y

或者,如果您不喜欢过度打字:

dat[!rowSums(dat[c('R1','R3','R4')]=='N'),]

这将首先测试数据的“R1”、“R3”和“R4”列的每个“单元格”是否等于“N”,然后计算每行 TRUE 值的总和。如果一行中不存在“N”,则总和等于 0 并将被保留。我添加了drop=FALSE 以将结构保持为data.frame。

OP评论后的注意事项:

如果您仅对 data.frame 的 1 列进行子集化而不指定 drop=TRUE 选项,则 [.data.frame 的默认行为是将生成的 1-column-data.frame 强制为原子向量。然后,rowSums 将无法处理该结果向量。为避免这种情况,请将您的代码更改为:

dat[!rowSums(dat[,'R1', drop=FALSE]=='N'), ] 

样本数据:

set.seed(5) 
dat <- data.frame(Cs=c("c1","c2","c3","c4","c5","c6"),  
                  R1=sample(c("Y","N"),6,replace=TRUE), R2=sample(c("Y","N"),6,replace=TRUE),
                  R3=sample(c("Y","N"),6,replace=TRUE), R4=sample(c("Y","N"),6,replace=TRUE),
                  R5=sample(c("Y","N"),6,replace=TRUE), R6=sample(c("Y","N"),6,replace=TRUE))

【讨论】:

  • 您将如何仅对特定列进行测试?可以dat[rowSums(dat[,c("R1","R3","R4")]== "N") == 0, , drop=FALSE]吗?
  • 非常感谢!简短而干净的解决方案,它可以工作。只有一句话。您说“如果总和等于 0,则将保留该行”,但我想是相反的,不是吗?
  • @Stefano,不,正如我所说。如果一行(以及指定的列)中的“N”个数为 0,则保留该行。您可以查看我的示例的行总和:rowSums(dat[c('R1','R3', 'R4')]=='N') #[1] 1 3 2 1 0 2。您会看到在第五行中,没有“N”,这就是示例中保留的行
  • @docendodiscimus 是的,对不起。我的错!我得到“如果 N 存在”而不是“如果没有 N”......再次感谢!
  • 您也可以添加dat[!Reduce('+',lapply(dat[c('R1','R3', 'R4')],'==', 'N')),]
【解决方案2】:

您可以为每一行创建一个由布尔值组成的“保持”变量:

keep <- apply(dat[,c("R1","R3","R4")],
                  MARGIN=1,
                  FUN=function(x){all(x!='N')})
res <- dat[keep,]

> res
  Cs R1 R2 R3 R4 R5 R6
1 c1  Y  Y  Y  Y  Y  Y

数据: 使用的种子:1234

dat <- structure(list(Cs = structure(1:6, .Label = c("c1", "c2", "c3", 
"c4", "c5", "c6"), class = "factor"), R1 = structure(c(2L, 1L, 
1L, 1L, 1L, 1L), .Label = c("N", "Y"), class = "factor"), R2 = structure(c(2L, 
2L, 1L, 1L, 1L, 1L), .Label = c("N", "Y"), class = "factor"), 
    R3 = structure(c(2L, 1L, 2L, 1L, 2L, 2L), .Label = c("N", 
    "Y"), class = "factor"), R4 = structure(c(1L, 1L, 1L, 1L, 
    1L, 1L), .Label = "Y", class = "factor"), R5 = structure(c(2L, 
    1L, 1L, 1L, 1L, 2L), .Label = c("N", "Y"), class = "factor"), 
    R6 = structure(c(2L, 2L, 2L, 1L, 2L, 1L), .Label = c("N", 
    "Y"), class = "factor")), .Names = c("Cs", "R1", "R2", "R3", 
"R4", "R5", "R6"), row.names = c(NA, -6L), class = "data.frame")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    • 2016-08-28
    • 2013-04-28
    • 2011-08-20
    • 1970-01-01
    • 2021-02-04
    • 2017-06-26
    相关资源
    最近更新 更多