【问题标题】:Deleting certain rows without a loop在没有循环的情况下删除某些行
【发布时间】:2017-07-04 10:21:55
【问题描述】:

我有一个包含汽车维修数据的数据框。它还告诉我汽车是否发生故障(并得到维修)。我想在汽车抛锚后摆脱所有有维修事件的行。

Car <- c('A','A','B')
Damage <-c("Wheels","Motor","Motor")
date <-c('01-01-2015','01-01-2016','01-01-2016')
Broke_down <-c(1,0,1)

df <- as.data.frame(cbind(Car,date,Damage,Broke_down))

基本上,我想删除虚拟为 1 后汽车出现的所有行。

所以在这种情况下,输出必须是:

"Car"        "date"          "Damage"     "Broke_down"
 A           01-01-2015       Wheels         1
 B           01-01-2016       Motor          1

最好, 费利克斯

【问题讨论】:

  • 您的示例选择不当,因为它恰好可以通过更简单的方法轻松解决,尽管这对于其他情况不正确。更好地选择示例数据可以防止过于简单的解决方案

标签: r loops dataframe


【解决方案1】:

这里有一个使用splitlapply的解决方案,数据准备和问题中的一样:

df2 <- do.call(
  rbind,
  lapply(
    split(df, df$Car),
    function(x){
      x[1:which.min(x$Broke_down==1), ]
    })
)

解释:
split 给出data.frames 的列表
lapply 在其第二个参数中应用该函数并返回结果列表
最后do.call 调用rbind 并得到data.frames 的结果列表再次给你一个长的data.frame

使用data.tabledplyr 有类似但更快的解决方案。

【讨论】:

  • 也许是which.min 而不是min(which(...))? (+1)
  • 感谢您的建议,我相应地更改了答案。
【解决方案2】:

基于 OP 帖子中的更新

library(data.table)
setDT(df)[, .SD[cummin(Broke_down) > 0], Car]
#    Car       date Damage Broke_down
#1:   A 01-01-2015 Wheels          1
#2:   B 01-01-2016  Motor          1

或与ave 来自base R

df[with(df, ave(Broke_down, Car, FUN = cummin) > 0),]
#  Car       date Damage Broke_down
#1   A 01-01-2015 Wheels          1
#3   B 01-01-2016  Motor          1

【讨论】:

    【解决方案3】:

    可能有更优雅的方式,但 lapplydo.call 可以解决问题:

    df_out <- do.call(rbind,lapply(unique(df$Car),function(x){
    
      df_sub <- df[df$Car==x,]
      df_sub[1:which(df_sub$Broke_down == 1)[1],]
    
    }))
    
    > df_out
      Car       date Damage Broke_down
    1   A 01-01-2015 Wheels          1
    3   B 01-01-2016  Motor          1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多