Ответ 1
Хотя ваши функции выглядят интересно, я думаю, вы спрашиваете, есть ли другие способы сделать это.
Лично мне нравится использовать что-то вроде этого:
## SAMPLE DATA
DT1 <- data.table(id=sample(LETTERS[1:4], 20, TRUE), Col1=1:20, Col2=rnorm(20))
DT2 <- data.table(id=sample(LETTERS[3:8], 20, TRUE), Col1=sample(100:500, 20), Col2=rnorm(20))
DT3 <- data.table(id=sample(LETTERS[19:20], 20, TRUE), Col1=sample(100:500, 20), Col2=rnorm(20))
ДОСТУП К ТАБЛИЦЕ ПО ССЫЛКЕ НАИМЕНОВАНИЯ ТАБЛИЦЫ:
Это просто, очень похоже на любой объект в R
# use strings to select the table
tablesSelected <- "DT3"
# use get to access them
get(tablesSelected)
# and we can perform operations:
get(tablesSelected)[, list(C1mean=mean(Col1), C2mean=mean(Col2))]
ВЫБОР КОЛОНН ПО ССЫЛКЕ
Чтобы выбрать столбцы по их именам, используйте аргумент .SDcols
.
Задан вектор имен столбцов:
columnsSelected <- c("Col1", "Col2")
Присвойте этот вектор аргументу .SDcols:
## Here we are simply accessing those columns
DT3[, .SD, .SDcols = columnsSelected]
Мы также можем применить функцию к каждому столбцу, указанному в строковом векторе:
## apply a function to each column
DT3[, lapply(.SD, mean), .SDcols = columnsSelected]
Обратите внимание, что если наша цель - просто вывести столбцы, мы можем отключить with
:
# This works for displaying
DT3[, columnsSelected, with=FALSE]
Примечание. Более "современный" способ сделать это - использовать ярлык ..
для доступа к columnsSelected
с уровня "вверх на один уровень":
DT3[ , ..columnsSelected]
Однако, если использовать with=FALSE
, мы не сможем работать напрямую со столбцами обычным способом
## This does NOT work:
DT3[, someFunc(columnsSelected), with=FALSE]
## This DOES work:
DT3[, someFunc(.SD), .SDcols=columnsSelected]
## This also works, but is less ideal, ie assigning to new columns is more cumbersome
DT3[, columnsSelected, with=FALSE][, someFunc(.SD)]
Мы также можем использовать get
, но это немного сложнее.
Я оставляю это здесь для справки, но .SDcols
- путь
## we need to use 'get', but inside 'j'
## AND IN A WRAPPER FUNCTION <~~~~~ THIS IS VITAL
DT3[, lapply(columnsSelected, function(.col) get(.col))]
## We can execute functions on the columns:
DT3[, lapply(columnsSelected, function(.col) mean( get(.col) ))]
## And of course, we can use more involved-functions, much like any *ply call:
# using .SDcols
DT3[, lapply(.SD, function(.col) c(mean(.col) + 2*sd(.col), mean(.col) - 2*sd(.col))), .SDcols = columnsSelected]
# using 'get' and assigning the value to a var.
# Note that this method has memory drawbacks, so using .SDcols is preferred
DT3[, lapply(columnsSelected, function(.col) {TheCol <- get(.col); c(mean(TheCol) + 2*sd(TheCol), mean(TheCol) - 2*sd(TheCol))})]
Для справки: если вы попробуете следующее, вы заметите, что они не дают результатов, к которым мы стремимся.
## this DOES NOT work (need ..columnsSelected)
DT3[, columnsSelected]
## netiher does this
DT3[, eval(columnsSelected)]
## still does not work:
DT3[, lapply(columnsSelected, get)]
Если вы хотите изменить имя столбца:
# Using the '.SDcols' method: change names using 'setnames' (lowercase "n")
DT3[, setnames(.SD, c("new.Name1", "new.Name2")), .SDcols =columnsSelected]
# Using the 'get' method:
## The names of the new columns will be the names of the 'columnsSelected' vector
## Thus, if we want to preserve the names, use the following:
names(columnsSelected) <- columnsSelected
DT3[, lapply(columnsSelected, function(.col) get(.col))]
## we can also use this trick to give the columns new names
names(columnsSelected) <- c("new.Name1", "new.Name2")
DT3[, lapply(columnsSelected, function(.col) get(.col))]
Понятно, что использовать .SDcols проще и элегантнее.
Как насчет by
?
# 'by' is straight forward, you can use a vector of strings in the 'by' argument.
# lets add another column to show how to use two columns in 'by'
DT3[, secondID := sample(letters[1:2], 20, TRUE)]
# here is our string vector:
byCols <- c("id", "secondID")
# and here is our call
DT3[, lapply(columnsSelected, function(.col) mean(get(.col))), by=byCols]
ВСТАВЬТЕ ВСЕ ВМЕСТЕ
Мы можем получить доступ к data.table по его имени, а затем выбрать его столбцы также по имени:
get(tablesSelected)[, .SD, .SDcols=columnsSelected]
## OR WITH MULTIPLE TABLES
tablesSelected <- c("DT1", "DT3")
lapply(tablesSelected, function(.T) get(.T)[, .SD, .SDcols=columnsSelected])
# we may want to name the vector for neatness, since
# the resulting list inherits the names.
names(tablesSelected) <- tablesSelected
ЭТО ЛУЧШАЯ ЧАСТЬ:
Поскольку так много в data.table
передается по ссылке, легко иметь список таблиц, отдельный список добавляемых столбцов и еще один список столбцов, с которыми можно работать, и собирать все вместе для добавления аналогичных операций. - но с разными входами - на всех ваших столах.
В отличие от аналогичного действия с data.frame
, нет необходимости переназначать конечный результат.
newColumnsToAdd <- c("UpperBound", "LowerBound")
FunctionToExecute <- function(vec) c(mean(vec) - 2*sd(vec), mean(vec) + 2*sd(vec))
# note the list of column names per table!
columnsUsingPerTable <- list("DT1" = "Col1", DT2 = "Col2", DT3 = "Col1")
tablesSelected <- names(columnsUsingPerTable)
byCols <- c("id")
# TADA:
dummyVar <- # I use 'dummyVar' because I do not want to display the output
lapply(tablesSelected, function(.T)
get(.T)[, c(newColumnsToAdd) := lapply(.SD, FunctionToExecute), .SDcols=columnsUsingPerTable[[.T]], by=byCols ] )
# Take a look at the tables now:
DT1
DT2
DT3