web-dev-qa-db-fra.com

Comment utiliser les variables de référence par chaîne de caractères dans une formule?

Dans l'exemple minimal ci-dessous, j'essaie d'utiliser les valeurs d'une chaîne de caractères vars dans une formule de régression. Cependant, je ne peux transmettre que la chaîne de noms de variables ("v2 + v3 + v4") à la formule, pas la vraie signification de cette chaîne (par exemple, "v2" est dat $ v2).

Je sais qu'il existe de meilleures façons d'exécuter la régression (par exemple, lm(v1 ~ v2 + v3 + v4, data=dat)). Ma situation est plus complexe et j'essaie de comprendre comment utiliser une chaîne de caractères dans une formule. Des pensées?

mis à jour sous le code

# 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)

Mise à jour: @Arun avait raison sur le "" manquant sur v1 Dans le premier exemple. Cela a corrigé mon exemple, mais j'avais toujours des problèmes avec mon vrai code. Dans le bloc de code ci-dessous, j'ai adapté mon exemple pour mieux refléter mon code réel. J'ai d'abord choisi de créer un exemple plus simple en pensant que le problème était la chaîne vars.

Voici un exemple qui ne fonctionne pas :) Utilise le même bloc de données dat créé ci-dessus.

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)

Voici le problème:

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

Contrairement à regression dans le premier exemple, eq n'apporte pas les noms des colonnes (par exemple, v3). Les noms d'objets (par exemple, r3) Sont conservés. En tant que telle, la commande lm() suivante ne fonctionne pas.

m2 <- lm(as.formula(eq), data=dat)
40
Eric Green

Je vois quelques problèmes se produire ici. Tout d'abord, et je ne pense pas que cela pose de problème, mais faisons votre trame de données en une seule étape afin que vous n'ayez pas v1 à travers v4 flottant à la fois dans l'environnement global et dans la trame de données. Deuxièmement, faisons simplement v2 un facteur ici pour que nous n'ayons pas à en faire un facteur plus tard.

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

Première partie Maintenant, pour votre première partie, il semble que c'est ce que vous voulez:

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

Voici une façon plus simple de le faire, même si vous devez toujours spécifier la variable de réponse.

lm(v1 ~ ., data=dat)

Alternativement, vous pouvez certainement construire la fonction avec coller et appeler lm dessus.

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

Cependant, ma préférence dans ces situations est d'utiliser do.call, qui évalue les expressions avant de les passer à la fonction; cela rend l'objet résultant plus approprié pour appeler des fonctions comme update on. Comparez la partie call de la sortie.

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

Deuxième partie À propos de votre deuxième partie, il semble que c'est ce que vous recherchez:

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

D'abord parce que v2 est un facteur dans la trame de données, nous n'avons pas besoin de cette partie, et deuxièmement, cela peut être simplifié davantage en utilisant mieux les méthodes de R pour utiliser des opérations arithmétiques pour créer des interactions, comme ceci.

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

Je créerais alors simplement la fonction en utilisant paste; la boucle avec assign, même dans le cas le plus large, n'est probablement pas une bonne idée.

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

Il peut ensuite être appelé en utilisant lm directement ou avec do.call.

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

À propos de votre code Le problème que vous avez rencontré en essayant d'utiliser r3 etc était que vous vouliez le contenu de la variable r3, pas la valeur r3. Pour obtenir la valeur, vous avez besoin de get, comme ceci, puis vous réduisez les valeurs avec paste.

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

Cependant, une meilleure façon serait d'éviter assign et de simplement construire un vecteur des termes que vous voulez, comme ceci.

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

Une solution plus semblable à R serait d'utiliser lapply:

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

TL; DR: utilisez paste.

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