根据外部数据更新指定列中的值 table

Update values in specified columns based on external data table

我想根据另一个数据 table 的外部值更新数据 table 某些指定列中的值。

我知道如何逐个变量执行此操作,但我想要一个更高效的自动化解决方案,或许可以使用 lapply

UPDATE:我的数据集(相当于下面示例中的 mtcars)有其他我不想更新的列。

对于可重现的示例,运行 首先是这段代码

# Load library
  library(data.table)

# load data
  data(mtcars)

# create another Data Table which we'll use as external reference
# this table shows the number of decimals of those variables we want to modify in mtcars
  var <- c("mpg","disp","hp")
  Decimal <- c(1,3,2)
  DT <- cbind.data.frame(var, Decimal)

# convert into data.table
  setDT(DT)
  setDT(mtcars)

我的代码,逐列更新

mtcars[, mpg  := mpg  / 10 ^ DT[var=="mpg",  Decimal] ]
mtcars[, disp := disp / 10 ^ DT[var=="disp", Decimal] ]
mtcars[, hp   := hp   / 10 ^ DT[var=="hp",   Decimal] ]

此代码运行良好,并给出了预期的结果。

想要的结果

mtcars 的第一行曾经是这样的:

>     mpg disp  hp
> 1: 21.0  160 110

现在看起来像这样:

>     mpg   disp   hp
> 1: 2.10  0.160 1.10

是否有使用 functionlapply 等更有效的解决方案?

看起来 Map() 会这样做

library(data.table)
## match 'DT$var' to the names of 'mtcars'
m <- chmatch(levels(DT$var)[DT$var], names(mtcars))
## update 'mtcars' with the desired operation
mtcars[, names(mtcars) := Map("/", .SD, 10 ^ DT$Decimal[m])]
## result
head(mtcars)
#     mpg  disp   hp
# 1: 2.10 0.160 1.10
# 2: 2.10 0.160 1.10
# 3: 2.28 0.108 0.93
# 4: 2.14 0.258 1.10
# 5: 1.87 0.360 1.75
# 6: 1.81 0.225 1.05

或者如果你想走得快一点,我们可以使用 .mapply() 代替 Map() 那个电话是

.mapply(`/`, list(.SD, 10 ^ DT$Decimal[match(DT$var, names(mtcars))]), NULL)

我们也可以对多列使用set。它非常有效,因为避免了 [.data.table 的开销。我们遍历 'mtcars' 的列索引,并使用 set 从对应的 'mtcars' 列的计算中将 'j' 指定的列更改为 value 'DT$Decimal' 个元素。

for(j in seq_along(mtcars)){
  set(mtcars, i=NULL, j=j, value=mtcars[[j]]/10^DT[,Decimal][j])
 }


head(mtcars)
#    mpg  disp   hp
#1: 2.10 0.160 1.10
#2: 2.10 0.160 1.10
#3: 2.28 0.108 0.93
#4: 2.14 0.258 1.10
#5: 1.87 0.360 1.75
#6: 1.81 0.225 1.05

编辑:根据 OP 的评论,假设如果我们不对数据集进行子集化并希望保留所有列,同时转换 'var' 中指定的某些列,我们可以遍历 'var' 并使用 set 更改由 'var' 指定的列。在这里,我在转换为 data.table.

后使用完整的 mtcars 数据集
 for(j in seq_along(var)){
  set(mtcars, i=NULL, j=var[j], value=mtcars[[var[j]]]/10^DT[, Decimal][j])
 }

head(mtcars)
#    mpg cyl  disp   hp drat    wt  qsec vs am gear carb
#1: 2.10   6 0.160 1.10 3.90 2.620 16.46  0  1    4    4
#2: 2.10   6 0.160 1.10 3.90 2.875 17.02  0  1    4    4
#3: 2.28   4 0.108 0.93 3.85 2.320 18.61  1  1    4    1
#4: 2.14   6 0.258 1.10 3.08 3.215 19.44  1  0    3    1
#5: 1.87   8 0.360 1.75 3.15 3.440 17.02  0  0    3    2
#6: 1.81   6 0.225 1.05 2.76 3.460 20.22  1  0    3    1