paste() character string als Befehl ausführen

Wie rufe ich R-Funktionen auf, wie selektiere ich Daten, ich weiß nicht genau ....

Moderatoren: EDi, jogo

Antworten
LeaRn
Beiträge: 17
Registriert: Sa Mär 14, 2020 12:25 am

paste() character string als Befehl ausführen

Beitrag von LeaRn »

Sehr geehrter Leser

Ich habe folgendes Problem:

Code: Alles auswählen

library(data.table)

dat <- data.table(x = 1:2,
                  y = 2:3,
                  z = 1:2)

for (i in 1:2) {
  for (j in 2:3) {
    get(paste0("dat[x == ", i," & y == ", j,"]"))
  }
}

#Ausgabe:
#Fehler in get(paste0("dat[x == ", i, " & y == ", j, "]")) : 
#Objekt 'dat[x == 1 & y == 2]' nicht gefunden

#Gewünschtes Resultat:
dat[x == 1 & y == 2] 
 
Führe ich den Code so aus, wie beschrieben, führt dies zu einer Fehlermeldung. Führe ich den Befehl "dat[x == 1 & y == 2]" einfach so aus, so komme ich zum gewünschten Resultat. Das Problem ist wohl, dass "dat[x == 1 & y == 2]" kein Objekt ist. Wie kann ich den Befehl trotzdem ausführen?

Neben get() habe ich auch eval(parse()) ausprobiert, was aber auch nicht funktioniert hat.

Wie kann ich einen mit paste() zusammengefügten Befehl ausführen?

Für eine Antwort bedanke mich schon im Voraus.

Liebe Grüsse
LeaRn
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: paste() character string als Befehl ausführen

Beitrag von EDi »

parse + eval funktioniert:

Code: Alles auswählen

library(data.table)

dat <- data.table(x = 1:2,
                  y = 2:3,
                  z = 1:2)

for (x in 1:2) {
  for (y in 2:3) {
    eval(parse(text = paste0("print(dat[x == ", x," & y == ", y,"])")))
  }
}
Was willst du denn machen? Meist gibt es einfachere/ besserer/robustere Lösungen:

Code: Alles auswählen

fortunes::fortune("answer is parse") 

Wenn es wirklich meta-programmierung sein soll (Etwas das R gut kann, aber auch mit das komplexeste was man mit R anstellen kann), dann würde ich mir mal rlang anschauen https://github.com/rstudio/cheatsheets/ ... dyeval.pdf bzw. das Kapitel im Advanced R Buch.
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
LeaRn
Beiträge: 17
Registriert: Sa Mär 14, 2020 12:25 am

Re: paste() character string als Befehl ausführen

Beitrag von LeaRn »

Danke für die Antwort. Ich hatte einen Syntax Fehler, als ich es mit eval(parse()) probiert hatte.

Die Idee ist, aus einem Datensatz jede mögliche Kombination von X und Y separat mit einem Test zwischen den Variablen nv1 und nv2 zu untersuchen:

Code: Alles auswählen

library(data.table)

dat <- data.table(x = sample(1:4, 10000, replace = TRUE),
                  y = sample(1:4, 10000, replace = TRUE),
                  nv1 = rnorm(10000, mean = 4999, sd = 100),
                  nv2 = rnorm(10000, mean = 5001, sd = 100))
                  
resultate <- list()
resultate.als.dt <- list()
l = 1

for (x in 1:4) {
  for (y in 1:4) {
    komponente_1 <- eval(parse(text = paste0("dat[x == ", x," & y == ", y,"]")))
    komponente_2 <- eval(parse(text = paste0("dat[x == ", x," & y == ", y,"]")))
    resultate[[l]] <- t.test(x = komponente_1$nv1,
                             y = komponente_2$nv2)
    resultate.als.dt[[l]] <- data.table(x = x,
                                        y = y,
                                        p_wert = resultate[[l]]$p.value,
                                        test = resultate[[l]]$method )
    l = l + 1
  }
}
ttest.liste <- rbindlist(resultate.als.dt)
Zugegeben, mein Beispiel mit diesem Datensatz und dem T-test ist nicht ganz so realistisch. Es wäre trotzdem interessant zu wissen, wie man meinen Code optimieren kann. Ich nehme an, dass man durch geschickteres Programmieren mindestens eine der beiden Listen weglassen kann und dass es eine bessere Lösung bezüglich dem Einlesen der XY-Kombinationen gibt.

Liebe Grüsse
LeaRn
bigben
Beiträge: 2781
Registriert: Mi Okt 12, 2016 9:09 am

Re: paste() character string als Befehl ausführen

Beitrag von bigben »

Hallo LeaRn,

es gibt da bestimmt data.table-Magie, die das ganze superelegant und auch superschnell macht. Da kommt bestimmt noch was von EDi oder von Athomas. Mit ganz einfachem Basis R hätte ich den t-Test über alle Kombinationen von x und y so gemacht:

Code: Alles auswählen

dat <- data.frame(x = sample(1:4, 1000, replace = TRUE),
                  y = sample(1:4, 1000, replace = TRUE),
                  nv1 = rnorm(1000, mean = 4999, sd = 100),
                  nv2 = rnorm(1000, mean = 5001, sd = 100))

by(dat, list(dat$x, dat$y), function(teil) t.test(teil$nv1, teil$nv2))
Dieser Einzeiler gibt Dir eine Liste von 16 t-Tests zurück.

Die p-Werte aus dieser Liste kannst Du beispielsweise mit lapply extrahieren:

Code: Alles auswählen

tests <- by(dat, list(dat$x, dat$y), function(teil) t.test(teil$nv1, teil$nv2))
p.values <- sapply(tests, function(t) t$p.value)
p.values
by ist extra dafür gemacht, Teile von Dataframes getrennt mit der gleichen Funktion zu untersuchen. Kurze Kommandos sind meistens leichter auf Syntax- oder Logikfehler zu untersuchen als lange Programmabschnitte.
Meines Erachtens ist das Erlernen von by sehr viel wertvoller als eval-parse. Wie EDi schon schrieb, ist der Ruf nach eval-parse meistens ein Hinweis, dass man weiter vorne was falsch gemacht hat.

HTH,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
Athomas
Beiträge: 769
Registriert: Mo Feb 26, 2018 8:19 pm

Re: paste() character string als Befehl ausführen

Beitrag von Athomas »

In der Hoffnung, dass die "Magie" nicht als unerlaubt empfunden wird :lol: :

Code: Alles auswählen

Ergebnisse <- dat[  , t.test(nv1,nv2)[c("p.value","method")], by=.(x,y)][order(x,y)]
bigben
Beiträge: 2781
Registriert: Mi Okt 12, 2016 9:09 am

Re: paste() character string als Befehl ausführen

Beitrag von bigben »

Erlaubt ist, was gefällt. Dass order mehrere Vektoren als Argument annimmt, war mir nicht klar, bis ich es gerade bei Dir gelesen habe. Danke!
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
LeaRn
Beiträge: 17
Registriert: Sa Mär 14, 2020 12:25 am

Re: paste() character string als Befehl ausführen

Beitrag von LeaRn »

Danke für die Beiträge.
Leider habe ich bemerkt, dass ich einen Fehler in meinem Beispiel gehabt habe. Im Beispiel waren die Komponenten 1 und 2 in jedem Durchgang jeweils identisch. Eigentlich sollten sie jeweils unterschiedlich sein, damit man sie mit psych::r.test() vergleichen kann. Hier nochmals meine Version:

Code: Alles auswählen

pkgs <- c("data.table", 
          "psych")
lapply(pkgs, library, character.only = TRUE)

dat <- data.table(x = sample(1:4, 100, replace = TRUE),
                  y = sample(1:4, 100, replace = TRUE),
                  nv1 = rnorm(100, mean = 10, sd = 5),
                  nv2 = rnorm(100, mean = 30, sd = 5))

resultate <- list()
resultate.als.dt <- list()

l = 1

for (x1 in 1:4) {
  for (x2 in 1:4) {
    for (y1 in 1:4) {
      for (y2 in 1:4) {
      komponente_1 <- eval(parse(text = paste0("dat[x == ", x1," & y == ", y1,"]")))
      komponente_2 <- eval(parse(text = paste0("dat[x == ", x2," & y == ", y2,"]")))
      resultate[[l]] <- r.test(n = nrow(komponente_1),
                               n2 = nrow(komponente_2),
                               r12 = cor(komponente_1$nv1,
                                         komponente_1$nv2,
                                         method = "pearson"),
                               r34 = cor(komponente_2$nv1,
                                         komponente_2$nv2,
                                         method = "pearson"))
      resultate.als.dt[[l]] <- data.table(x1 = x1,
                                          y1 = y1,
                                          x2 = x2,
                                          y2 = y2,
                                          p_wert = resultate[[l]]$p,
                                          z_wert = resultate[[l]]$z,
                                          cor1 = cor(komponente_1$nv1,
                                                     komponente_1$nv2,
                                                     method = "pearson"),
                                          cor2 = cor(komponente_2$nv1,
                                                     komponente_2$nv2,
                                                     method = "pearson"))
      l = l + 1
      }
    }
  }
}
ttest.liste <- rbindlist(resultate.als.dt)
Es sollen also jeweils die Korrelation von nv1 und nv2 zwischen zwei verschiedenen Kombinationen von x und y geprüft werden und das für alle möglichen Kombinationen.

Liebe Grüsse
LeaRn
bigben
Beiträge: 2781
Registriert: Mi Okt 12, 2016 9:09 am

Re: paste() character string als Befehl ausführen

Beitrag von bigben »

Uiuiuiuiui. 256 p-Werte wollt Ihr berechnen? Und dann nach Bonferroni korrigieren? Ich hab da statistisch kein gutes Gefühl bei, aber das war nicht die Fragestellung.

Also ich würde wahrscheinlich die 4 for-Schleifen weglassen und stattdessen eine Liste aller 256 möglichen Kombinationen mit expand.grid erstellen und diese Liste dann zeilenweise abarbeiten:

Code: Alles auswählen

expand.grid(x1=1:4, y1=1:4, x2=1:4, y2=1:4)


Alternativ gibt es ganz bestimmt tolle data.table-Magie ;-)

Du kannst natürlich auch bei den geschachtelten for-Schleifen bleiben, wenn Dir die leichter fallen. Ich bleibe jetzt mal bewusst nahe an Deiner Lösung. Nehmen wir an, Du hast dat wie oben beschrieben definiert und willst jetzt komponente_1 für die Werte 3 und 3 bestimmen. Momentan machst Du das so:

Code: Alles auswählen

x1<-3
y1 <- 3
komponente_1 <- eval(parse(text = paste0("dat[x == ", x1," & y == ", y1,"]")))
komponente_1
deutlich einfacher wäre aber doch den Umweg über den String wegzulassen und zu schreiben:

Code: Alles auswählen

komponente_1 <- dat[x==x1 & y==y1]
Das Ergebnis ist das gleiche, der Code ist viel übersichtlicher und es geht keine Zeit verloren mit komplizierten Umwegen über Strings.

HTH,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
Antworten