【问题标题】:update one column twice in a data.table efficient in R在 R 中有效的 data.table 中更新一列两次
【发布时间】:2020-05-17 14:53:14
【问题描述】:

我有一个如下所示的数据表:

DT <- data.table(Zeit = c(0.024, 0.4, 0.05),
                 Gier = c(1, 2, 3),
                 GierVZ = c(1, 0, 1),
                 Quer = c(2, 4, 6))

现在我想更新并添加一些列到这个数据表中。但我无法更新Gier 两次,因为它会创建重复并出现错误。

DT[, ':='(Zeit   = round(Zeit, digits = 2),
          Gier   = replace(Gier, Gier == 163.83, NA),
          GierVZ = factor(GierVZ, levels = c(0, 1), labels = c("positiv", "negativ")),
          Quer   = Quer * 9.81,
          Gier   = ifelse(GierVZ == "negativ", Gier * -1, Gier))]

一般而言,我怎样才能避免这种情况并仍然创建一些可读的快速代码? 我确信有一个简单的答案。但我是数据表的新手,我认为(至少目前)它不像 dplyr 那样直观,但它对我的大数据来说要快得多。

【问题讨论】:

  • Gier = ifelse(GierVZ == "negativ", replace(Gier, Gier == 163.83, NA)* -1, replace(Gier, Gier == 163.83, NA))) 没有完成任务吗?
  • 确实如此,但这样做是不是一个好方法?如果您想第三次更改列怎么办?如果你想用一列做更多的事情怎么办?

标签: r performance data.table dplyr readability


【解决方案1】:

你可以用花括号计算Gier

DT[, ':='(Zeit   = round(Zeit, digits = 2),
          Gier   = {Gier[Gier == 163.83] <- NA; ifelse(GierVZ, -Gier, Gier)},
          GierVZ = factor(GierVZ, levels = c(0, 1), labels = c("positiv", "negativ")),
          Quer   = Quer * 9.81)]

【讨论】:

  • 不错的解决方案!是否可以在Gier2 的基础上创建一个新列Gier2 来创建一个新列Gier3,比如Gier3 = log(Gier2)
  • dplyr 相对,您可以在mutate 调用中引用新创建的变量,data.table 不允许您这样做,AFAIK。您可以在 {} 中分别计算 Gier2 和 Gier3(效率相当低),或者链 [] 括号,这相当于一次执行一个步骤(通常有助于提高可读性;请参阅@MichaelChirico 采用的第一种方法)。一般来说,我只会创建下游所需的变量,所以如果你最终需要Gier = {Gier[Gier == 163.83] &lt;- NA; log(ifelse(GierVZ, -Gier, Gier));},只需生成它。
【解决方案2】:

这种方法对我来说具有大致相同的可读性并实现了您的目标:

DT[ , `:=`(
  Zeit = round(Zeit, digits=2L),
  GierVZ = factor(GierVZ, levels = c(0, 1), labels = c("positiv", "negativ")),
  Quer   = Quer * 9.81
)]
DT[Gier == 163.83, Gier := NA]
DT[ , Gier := fifelse(GierVZ == "negativ", Gier * -1, Gier))]

或者,在data.table (Installation instructions) 的开发版本中,您可以从fcase 中受益:

DT[ , `:=`(
  Zeit   = round(Zeit, digits=2L),
  GierVZ = factor(GierVZ, levels = c(0, 1), labels = c("positiv", "negativ")),
  Quer   = Quer * 9.81
  Gier   = fcase(
      Gier == 163.83    , NA_real_, 
    GierVZ == 'negative',    -Gier, 
    GierVZ == 'positiv' ,     Gier
  )
)]

如果您可以跳过写出最后一个GierVZ=='positiv' 条件会更容易;这是一个正在进行的功能请求。

【讨论】:

  • 我喜欢你的解决方案!但我收到一个错误:could not find function "fcase"虽然我更新并加载了最新版本的 data.table
  • @Bolle 它在​​ CRAN 上不可用。请参阅链接。希望以下工作:install.packages('data.table', type = 'source', repos = 'http://Rdatatable.github.io/data.table')
  • 像这样安装软件包效果很好!谢谢 :) 但是由于类型不同,代码 fcase 不起作用。参数 4 是 double 类型,参数 2 是逻辑类型。它似乎像 fifelse 一样工作 ;)
  • 哦,对了。我已经确定了答案,谢谢@Bolle。实际上是另一个待处理的功能请求:)
  • 还有一个问题。我用 fcase 试过你的代码。如果您使用这种方法,例如 Gier = 2,则 Gier 的所有值都是 NA 而不仅仅是值 2
猜你喜欢
  • 2015-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-20
  • 2013-08-21
  • 2019-10-09
相关资源
最近更新 更多