2015-09-29 44 views
4

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

我知道如何通过变量做这个变量,但我想更有效的解决方案,我可以自动化,可能使用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等?

回答

4

我们还可以用set多列。由于避免了[.data.table的开销,所以它非常有效。我们遍历'mtcars'的列索引,并使用set来更改由'j'指定的列,其中value是使用'DT $ Decimal'元素计算相应'mtcars'列的列。

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 

编辑:基于业务方案的意见,想如果我们没有子集划分的数据集,并希望保持所有列,同时改造中的“变种”指定某些列,我们可以遍历所有的“变种”并使用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 
+1

我应该更清楚@akrun。现在它工作完美! –

+0

@RafaelPereira感谢您的反馈。 – akrun

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) 
+0

虽然这会需要两倍的对象内存。 – Arun

+1

@Arun - 它应该是'mtcars [,名称(mtcars):= Map(“/”,.SD,DT $ Decimal)] '那么? –

+0

问题在于,lapply等和map首先必须在分配之前返回整个列表。所以我们无法避免内存需求,除非我们去找for循环... – Arun