2015-09-29 8 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] ] 

Этот код работает отлично, и это дает желаемый результат.

Желаемая Result

Первый ряд 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 из расчета соответствующих столбцов «mtcars» с элементами «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 

EDIT: На основе замечаний Op, в полагаю, что если мы не Подменю набор данных и хотите, чтобы все столбцы, при преобразовании некоторых столбцов, указанных в «вар», мы можем цикл над «вар» и используйте set для изменения столбцов, заданных параметром 'var'. Здесь я использую полный набор данных 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 
+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 [, names (mtcars): = Map ("/", .SD, DT $ Decimal)] ' then? –

+0

Проблема в том, что lapply etc и map сначала должны вернуть весь список перед назначением. Поэтому мы не можем избежать требований к памяти, если мы не займемся циклом for ... – Arun

Смежные вопросы