【问题标题】:With data.table in R, how do I efficiently replace multiple column values named within a single column?使用 R 中的 data.table,如何有效地替换单个列中命名的多个列值?
【发布时间】:2017-07-20 15:08:32
【问题描述】:

在 R 中,我有一个包含诊断值的列(“prncl_diag”)的数据表。这些诊断值(在 prncl_diag 列中)也都显示为数据表中的列。大约有 2.5K 诊断列,其中的一个子集作为值显示在“prncl_diag”列中。

如果诊断指示符的名称出现在“prncl_diag”列的给定行中,我想用 1 更新诊断指示符列。

解释得不是很好,但这是一个最小的工作示例。

dt <- data.table(heart_failure = c(0, 1, 0),
             kidney_failure = c(1, 0, 0),
             death = c(1, 1, 1), 
             prncl_diag = c('heart_failure', 'kidney_failure', 'death'))

for (i in 1:nrow(dt)) {
  name <- dt[i, prncl_diag]
  dt <- dt[i, eval(name) := 1]
}

此代码有效并将“heart_failure”的第 1 行更新为 1,将“kidney_failure”的第 2 行更新为 1,并且不会更改“death”列的第 3 行,因为它已经是 1。

但是,对于 5M 行的数据表,代码很慢,我知道我没有使用 data.table 的结构。

请提供更有效的解决方案。有兴趣从 StackOverflow 社区了解 R、data.table 和效率。

【问题讨论】:

  • 一个有效的base R 选项是setDF(dt); dt[cbind(1:nrow(dt), match(dt$prncl_diag, names(dt)))] &lt;- 1

标签: r performance data.table


【解决方案1】:

一种选择是按prncl_diag 中的唯一值进行子集化。

for (val in unique(dt$prncl_diag)) {
  dt[prncl_diag == val, (val) := 1]
}

这就是我可能会采用的方式,特别是如果prncl_diag 中的唯一值相对于行数而言很少。

结果:

#    heart_failure kidney_failure death     prncl_diag
# 1:             1              1     1  heart_failure
# 2:             1              1     1 kidney_failure
# 3:             0              0     1          death

【讨论】:

  • 太棒了。谢谢你,埃里克。这样做的一个问题是我有数千个诊断列。抱歉没有在问题中指定,我更新了。因此,我不想命名特定的列。另外,这个dcast真的更快吗?我想它可能比遍历所有行要慢?
  • 嘿 Erik -- 当我第一次浏览这个时,我完全错过了你的第一个解决方案!太多堆栈避免!我最终使用了您的第一个解决方案。它很快。我有 500 万行的 440 个唯一值。谢谢!
  • 我使用dcast 删除了部分答案。考虑到您的问题的更新,它不能很好地扩展。
【解决方案2】:

这是tidyverse的答案

library(tidyverse)
map_df(1:nrow(dt), ~dt[.x,] %>% mutate_at(vars(.$prncl_diag), function(y) ifelse(y==0,1,y)))

  heart_failure kidney_failure death     prncl_diag
1             1              1     1  heart_failure
2             1              1     1 kidney_failure
3             0              0     1          death

【讨论】:

  • 太棒了!谢谢。您认为这会比对我的问题的评论中提出的解决方案更快吗?将节省我的时间!
  • 这不起作用。我收到以下错误。我之前也将其转换为数据框。错误:所有 select() 输入必须解析为整数列位置。以下不是:* .$prncl_diag
  • 我添加了library(tidyverse) 以防万一...我没有收到错误...您使用的是完整的真实数据吗?还是你的玩具示例数据?
  • akrun 答案更快
【解决方案3】:

我认为这会实现你想要的。

> dt[, .SD
     ][, rID := 1:.N
     ][, melt(.SD, id.vars=c('prncl_diag', 'rID'))
     ][prncl_diag == variable, value := 1
     ][, dcast(.SD, prncl_diag + rID ~ variable, value.var='value')
     ][, rID := NULL
     ][]

       prncl_diag heart_failure kidney_failure death
1:          death             0              0     1
2:  heart_failure             1              1     1
3: kidney_failure             1              1     1
> 

【讨论】:

  • 顺便说一句,rID := .I
猜你喜欢
  • 2016-08-26
  • 1970-01-01
  • 2021-08-21
  • 2016-01-20
  • 1970-01-01
  • 2021-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多