Подтвердить что ты не робот

Как использовать ссылочные переменные по символьной строке в формуле?

В приведенном ниже минимальном примере я пытаюсь использовать значения символьной строки vars в формуле регрессии. Однако я могу передать строку имен переменных ( "v2 + v3 + v4" ) в формулу, а не реальный смысл этой строки (например, "v2" равен $v2).

Я знаю, что существуют лучшие способы запуска регрессии (например, lm(v1 ~ v2 + v3 + v4, data=dat)). Моя ситуация более сложная, и я пытаюсь понять, как использовать символьную строку в формуле. Любые мысли?

Обновлен ниже код

# minimal example 
# create data frame
v1 <- rnorm(10)
v2 <- sample(c(0,1), 10, replace=TRUE)
v3 <- rnorm(10)
v4 <- rnorm(10)
dat <- cbind(v1, v2, v3, v4)
dat <- as.data.frame(dat)

# create objects of column names
c.2 <- colnames(dat)[2]
c.3 <- colnames(dat)[3]
c.4 <- colnames(dat)[4]

# shortcut to get to the type of object my full code produces
vars <- paste(c.2, c.3, c.4, sep="+")

### TRYING TO SOLVE FROM THIS POINT:
print(vars)
# [1] "v2+v3+v4"

# use vars in regression
regression <- paste0("v1", " ~ ", vars)
m1 <- lm(as.formula(regression), data=dat)

Обновление: @Arun был прав относительно отсутствующих "" на v1 в первом примере. Это подтвердило мой пример, но у меня все еще были проблемы с моим реальным кодом. В приведенном ниже фрагменте кода я адаптировал свой пример, чтобы лучше отразить мой фактический код. Я решил создать более простой пример, считая сначала, что проблема была в строке vars.

Вот пример, который не работает:) Использует тот же фрейм данных dat, который был создан выше.

dv <- colnames(dat)[1]
r2 <- colnames(dat)[2]
# the following loop creates objects r3, r4, r5, and r6
# r5 and r6 are interaction terms
for (v in 3:4) {
  r <- colnames(dat)[v]
  assign(paste("r",v,sep=""),r)
  r <- paste(colnames(dat)[2], colnames(dat)[v], sep="*")
  assign(paste("r",v+2,sep=""),r)
}

# combine r3, r4, r5, and r6 then collapse and remove trailing +
vars2 <- sapply(3:6, function(i) { 
                paste0("r", i, "+")
                })
vars2 <- paste(vars2, collapse = '')
vars2 <- substr(vars2, 1, nchar(vars2)-1)

# concatenate dv, r2 (as a factor), and vars into `eq`
eq <- paste0(dv, " ~ factor(",r2,") +", vars2)

Вот проблема:

print(eq)
# [1] "v1 ~ factor(v2) +r3+r4+r5+r6"

В отличие от regression в первом примере, eq не вводит имена столбцов (например, v3). Имена объектов (например, r3) сохраняются. Таким образом, следующая команда lm() не работает.

m2 <- lm(as.formula(eq), data=dat)
4b9b3361

Ответ 1

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

dat <- data.frame(v1 = rnorm(10),
                  v2 = factor(sample(c(0,1), 10, replace=TRUE)),
                  v3 = rnorm(10),
                  v4 = rnorm(10) )

Часть первая Теперь, для вашей первой части, похоже, это то, что вы хотите:

lm(v1 ~ v2 + v3 + v4, data=dat)

Здесь более простой способ сделать это, хотя вам все равно нужно указать переменную ответа.

lm(v1 ~ ., data=dat)

В качестве альтернативы вы можете создать функцию с пастой и вызвать lm на ней.

f <- paste(names(dat)[1], "~", paste(names(dat)[-1], collapse=" + "))
# "v1 ~ v2 + v3 + v4"
lm(f, data=dat)

Однако в этих ситуациях я предпочитаю использовать do.call, который вычисляет выражения перед передачей их функции; это делает результирующий объект более подходящим для вызова функций типа update on. Сравните call часть вывода.

do.call("lm", list(as.formula(f), data=as.name("dat")))

Часть вторая О вашей второй части, похоже, вот что вы собираетесь делать:

lm(factor(v2) + v3 + v4 + v2*v3 + v2*v4, data=dat)

Во-первых, поскольку v2 является фактором в кадре данных, нам эта часть не нужна, и, во-вторых, это может быть упрощено дальше, используя методы R для использования арифметических операций для создания взаимодействий, например.

lm(v1 ~ v2*(v3 + v4), data=dat)

Я бы просто создал функцию, используя paste; цикл с assign, даже в большем случае, вероятно, не очень хорошая идея.

f <- paste(names(dat)[1], "~", names(dat)[2], "* (", 
           paste(names(dat)[-c(1:2)], collapse=" + "), ")")
# "v1 ~ v2 * ( v3 + v4 )"

Затем его можно вызвать с помощью либо lm напрямую, либо с помощью do.call.

lm(f, data=dat)
do.call("lm", list(as.formula(f), data=as.name("dat")))

О вашем коде Проблема, с которой вы пытались использовать r3 и т.д., заключалась в том, что вам нужно содержимое переменной r3, а не значение r3. Чтобы получить значение, вам нужно get, как это, а затем вы сбрасываете значения вместе с paste.

vars <- sapply(paste0("r", 3:6), get)
paste(vars, collapse=" + ")

Однако лучшим способом было бы избежать assign и просто построить вектор терминов, которые вы хотите, например.

vars <- NULL
for (v in 3:4) {
  vars <- c(vars, colnames(dat)[v], paste(colnames(dat)[2], 
                                          colnames(dat)[v], sep="*"))
}
paste(vars, collapse=" + ")

Более R-образное решение было бы использовать lapply:

vars <- unlist(lapply(colnames(dat)[3:4], 
                      function(x) c(x, paste(colnames(dat)[2], x, sep="*"))))

Ответ 2

TL; DR: используйте paste.

create_ctree <- function(col){
    myFormula <- paste(col, "~.", collapse="")
    ctree(myFormula, data)
}
create_ctree("class")