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

时间:2015-09-29 16:21:10

标签: r data.table lapply

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

我知道如何通过变量来做这个变量,但我想要一个更有效的解决方案,我可以自动化,也许使用lapply

更新:我的数据集(相当于下例中的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等是否有更高效的解决方案?

2 个答案:

答案 0 :(得分:4)

看起来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)

答案 1 :(得分:4)

我们还可以将set用于多个列。它非常有效,因为避免了[.data.table的开销。我们遍历&#39; mtcars&#39;的列索引,并使用set更改&#39; j&#39;指定的列。使用value计算相应的&#39; mtcars&#39;带有&#39; DT $ Decimal&#39;的列元件。

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的评论,假设我们没有对数据集进行子集化并希望保留所有列,同时转换&#39; var&#39;中指定的某些列,我们可以循环在&#39; var&#39;并使用set更改&#39; var&#39;指定的列。在这里,我在转换为mtcars后使用完整的data.table数据集。

 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