2015-09-29 79 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