Аргумент преобразования rxDataStep с использованием квазицитирования

Я пытаюсь использовать синтаксис квазицитирования (quo, exprs, !! и т. д.), а также функцию foreach для создания нескольких новых переменных с помощью именованного списка выражений, которые должны быть оценены внутри функции rxDataStep, в частности, transforms аргумент. Я получаю следующую ошибку:

Error in rxLinkTransformComponents(transforms = transforms, transformFunc = transformFunc,  : 'transforms' must be of the form list(...)

У меня есть набор данных, который включает в себя ряд переменных, которые мне нужно преобразовать в журнал, чтобы выполнить дальнейший анализ. Я использую функции rx из пакета "RevoScaleR" примерно три года и полностью пропустил "tidyverse"/конвейерный метод методов преобразования данных. Я иногда балуюсь этими инструментами, но предпочитаю придерживаться вышеупомянутых rx функций, учитывая мое относительное знакомство и тот факт, что до сих пор они очень хорошо служили мне.


Как MWE:

Требуемые библиотеки:

library(foreach)
library(rlang)

Создание переменных, которые необходимо преобразовать в журнал.

vars <- foreach(i = 10:20, .combine = "cbind") %do% rnorm(10, i)

Фрейм данных с идентификатором и вышеуказанными переменными.

data_in <- data.frame(id = 1:10, vars)

Объект, который создает выражения логарифмически преобразованных переменных; это создает именованный список.

log_vars <- foreach(i = names(data_in[-1]), .final = function(x) set_names(x, paste0(names(data_in[-1]), "_log"))) %do%
expr(log10(!!sym(i)))

Теперь пытаемся добавить переменные в существующий фрейм данных.

data_out <- rxDataStep(inData = data_in, transforms = log_vars, transformObjects = list(log_vars = log_vars))

В результате ошибка следующая:

Error in rxLinkTransformComponents(transforms = transforms, transformFunc = transformFunc,  :  'transforms' must be of the form list(...)

Я просто не могу понять ошибку, учитывая, что log_vars определяется как именованный список. Это можно проверить с помощью str и typeof.

Я попробовал немного другой способ определения новых переменных:

log_vars <- unlist(foreach(i = names(data_in[-1]), j = paste0(names(data_in[-1]), "_log")) %do%
exprs(!!j := log10(!!sym(i))))

Я должен использовать unlist, учитывая, что exprs уже выдает список в качестве вывода. В любом случае, я получаю ту же ошибку, что и раньше.

Естественно, я ожидаю, что в кадр данных будет вставлено 10 новых переменных с именами result.1_log, result.2_log и т. д. Вместо этого я получаю указанную выше ошибку, и новый кадр данных не создается.


Я подозревал, что функции rx не любят работать с синтаксисом квазицитирования, однако я использовал его раньше, когда нужно было идентифицировать субъектов с нулевыми значениями некоторых переменных. Это было сделано с использованием аргумента rowSelection функции rxDataStep. Я понимаю, что для rowSelection требуется одно логическое выражение, а для transforms требуется именованный список выражений.

Любая помощь будет высоко оценена, так как этот тип преобразования данных снова будет поддерживаться в моих анализах. Я подозреваю, что просто не понимаю внутренней работы синтаксиса квазицитирования или, возможно, того, как работают списки в целом, но, надеюсь, есть простое решение.

Я использую Microsoft R Open 3.4.3.


Информация о моем сеансе следующая:

R Services Information: Local R: C:\Program Files\Microsoft\ML Server\R_SERVER\ Version: 1.3.40517.1016 Operating System: Microsoft Windows 10.0.17134 CPU Count: 4 Physical Memory: 12169 MB, 6810 MB free Virtual Memory: 14025 MB, 7984 MB free Video controller[1]: Intel(R) HD Graphics 620 GPU[1]: Intel(R) HD Graphics Family Video memory[1]: 1024 MB Connected users: 1


person M. Meiring    schedule 24.12.2018    source источник


Ответы (1)


Я не совсем уверен, что вы пытаетесь сделать, поскольку я думаю, что вы слишком усложнили ситуацию. Если все, что вы хотите сделать, это взять журнал каждого # в каждой точке данных, то ниже я покажу два подхода.

  1. Подход № 1 является статическим, вы знаете фиксированное количество столбцов и жестко кодируете его. При таком подходе rxDataStep работает немного быстрее.
  2. Подход № 2 немного более динамичный, в нем используется функция transformFunc. transformFunc работает фрагментарно, поэтому его можно безопасно использовать в кластерном режиме. rxDataStep знает, как интегрировать фрагменты вместе. Но для этого будет небольшой удар по производительности.
  3. Возможно, вы пытались найти гибридный подход — динамически формировать список для параметра transforms в rxDataStep. Я не нашел способ заставить это работать. Вот аналогичный вопрос для этого в rxSetVarInfo (Измените имя динамической переменной с помощью rxSetVarInfo), но использование этого подхода пока не принесло мне успеха.

Дайте мне знать, если я полностью промахнулся!

library(foreach)
library(rlang)

startSize <- 10
endSize <- 20
vars <- foreach(i = startSize:endSize, .combine = "cbind") %do% rnorm(10, i)

data_in <- data.frame(vars)
tempInput <- tempfile(fileext = ".xdf")
tempOutput <- tempfile(fileext = ".xdf")

rxImport(inData = data_in, outFile = tempInput, overwrite = T)
rxGetInfo(tempInput, getVarInfo = T)

### Approach #1
print("Approach #1")

rxDataStep(inData = tempInput, outFile = tempOutput, overwrite = T,
       transforms = list(
         log_R1 = log10(result.1),
         log_R2 = log10(result.2),
         log_R3 = log10(result.3),
         log_R4 = log10(result.4),
         log_R5 = log10(result.5),
         log_R6 = log10(result.6),
         log_R7 = log10(result.7),
         log_R8 = log10(result.8),
         log_R9 = log10(result.9),
         log_R10 = log10(result.10),
         log_R11 = log10(result.11)))

rxGetInfo(tempOutput, getVarInfo = T)

### Approach #2
print("Approach #2")

logxform <- function(dataList) {
  numRowsInChunk <- length(dataList$result.1)

  for (j in 1:columnDepth) { 
    dataList[[paste0("log_R",j)]] <- rep(0, times=numRowsInChunk)
    for (i in 1:numRowsInChunk) {
     dataList[[paste0("log_R",j)]][i] <- log10(dataList[[paste0("result.",j)]][i])
    }
  }
  return(dataList)
}
rxDataStep(inData = tempInput, outFile = tempOutput, overwrite = T,
           transformObjects = list(columnDepth = endSize - startSize + 1), 
           transformFunc = logxform)

rxGetInfo(tempOutput, getVarInfo = T)
person Mike Silverman    schedule 04.01.2019