根据外部数据更新指定列中的值 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
是否有使用 function
、 lapply
等更有效的解决方案?
看起来 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
我想根据另一个数据 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
是否有使用 function
、 lapply
等更有效的解决方案?
看起来 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