Effizientes Programmieren

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

Moderatoren: EDi, jogo

Antworten
TopProtet
Beiträge: 7
Registriert: So Apr 18, 2021 12:36 pm

Effizientes Programmieren

Beitrag von TopProtet »

Ich habe folgende Aufgabe bekommen und komme aktuell nicht weiter:

Schreiben Sie eine Funktion sillyzv( ), welche die folgenden Argumente hat:
• n: Skalar, der die Anzahl der Beobachtungen pro Variable angibt.
• k: Skalar, der die Anzahl der Variablen angibt.
• mean: Vektor der Länge k (oder geeignet wiederholbar), der die Mittelwerte der Variablen enthält.
• sd: Vektor der Länge k (oder geeignet wiederholbar), der die Standardabweichung der Variablen enthält.

Die Funktion soll entsprechend Beobachtungen aus der Normalverteilung ziehen und eine Matrix zurückgeben, die n Zeilen fu ̈r die Beobachtungen und k Spalten für die Variablen hat. Die Mittelwerte und Standardabweichungen in den Spalten variieren je nach mean und sd.

Dies soll ich im ersten Schritt möglichst ineffizient gestalten indem ich die Ergebnismatrix für jede Variable spaltenweise dynamisch erweitere. Ich soll dabei jedoch keine unnötigen Dinge tun und die n Beobachtungen pro Variable mit einem Aufruf erzeugen.

Danach soll ich, smartzv() möglichst effizient programmieren, d.h. die Ergebnismatrix möglichst mit einem vektorwertigen Aufruf erzeugen.

Meine erste Funktion sieht folgendermaßen aus (wobei ich mir sehr unsicher bin):

Code: Alles auswählen

sillyzv <- function(n,k,mean,sd){
  
  m<-matrix("numeric",nrow = n,ncol=k)
  for (i in 1:k) {
    assign(paste("x", i,sep = ""),rnorm(n = n,mean = mean[i],sd = sd[i]))
    m[,i]<-cbind(get(paste("x",i,sep="")))
  }
  return (m)
}

Die "effiziente" Methode hab ich folgendermaßen probiert, leider stimmen die Ergebnisse nicht überein:

Code: Alles auswählen

smartzv <- function(n,k,mean,sd){

  m<-matrix("numeric",nrow = n,ncol=k)
  m[,1:k]<-rnorm(n = n,mean = mean[1:k],sd[1:k] = sd)
  return(m)
}
Könnte mir jemand Tipps geben bezüglich der beiden Funktionen bzw. was ich falsch gemacht habe?
Vielen Dank!
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: Effizientes Programmieren

Beitrag von EDi »

Idee:

Alles in einem Aufwasch aus einer multivariaten Normalverteilung ziehen.

Geht mit mvtnorm::rmvnorm https://www.rdocumentation.org/packages ... ics/Mvnorm

n ist klar,
k kann man weglassen (weil gleich länge mean)
mean kann 1:1 übernommen werden (oder halt k-mal wiederholen.
sigma ist eine matrix mit sd^2 auf der Diagonalen und sonst 0 (geht mit ?diag), damit man unabhängige Variablen hat.

Sollte recht performant sein - weiß aber nicht ob es schneller ist also jede variablen einzeln aus der univariaten Normalverteilung zu ziehen.
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.
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: Effizientes Programmieren

Beitrag von EDi »

Habs überprüft. Mapply ist schneller (weil mvtnorm noch die Kovarianzmatrix zerlegen muss).
Am schnellsten ist es aber nur einen rnorm aufruf zu haben und dann in eine Matrix zu packen.

Code: Alles auswählen

library(mvtnorm)
library(bench)

mv <- function(n = 10000, mean = c(10, 0), sd = c(1, 0.1)) {
  mvtnorm::rmvnorm(n, mean = mean, sigma = diag(sd^2), method = "chol")
}
mv()

individual <- function(n = 10000, mean = c(10, 0), sd = c(1, 0.1)) {
  mapply(rnorm, mean = mean, sd = sd, MoreArgs = list(n = n))
}
individual()

direct <- function(n = 10000, mean = c(10, 0), sd = c(1, 0.1)) {
  k <- length(mean)
  v <- rnorm(n * k, mean = mean, sd = sd)
  matrix(v, ncol = k, byrow = TRUE)
}
direct()

check <- function(mat) {
  list(means = apply(mat, 2, mean),
       sds = apply(mat, 2, sd))
}

check(mv())
check(individual())
check(direct())


bench::mark(mv(n = 10), individual(n = 10), direct(n = 10), check = FALSE)
bench::mark(mv(n = 10000), individual(n = 10000), direct(n = 10000), check = FALSE)
bench::mark(mv(n = 100000), individual(n = 100000), direct(100000), check = FALSE)



Zu deinem Code:
möglichst ineffizient gestalten indem ich die Ergebnismatrix für jede Variable spaltenweise dynamisch erweitere.
Macht das denn dein Code? Für mich sieht das so aus, dass du die Matrix schon vorher in ihrer Endgröße erstellst, oder?
Die "effiziente" Methode hab ich folgendermaßen probiert, leider stimmen die Ergebnisse nicht überein:
Ich bekomme da einen Fehler:

Code: Alles auswählen

Error: unexpected '=' in "rnorm(n = n,mean = mean[1:k],sd[1:k] ="
Kann also gar nicht die Ergebnisse vergleichen?!

Vermutlich wegen dem "sd[1:k] =". rnorm hat kein Argument "sd[1:k]", nur "sd". Hast du hier was verdreht? Ansonsten ist das ähnlich zu meiner direct() Function, außer dass ich die matrix erst danach erstelle.
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.
Antworten