2013-02-21 18 views
10

Ich möchte in der Lage sein, eine Funktion zu schreiben, die Regressionen in einem data.table von Gruppen ausgeführt und dann organisiert die Ergebnisse. Hier ist ein Beispiel dessen, was Ich mag würde tun:Übergabe von Spaltennamen an data.table programmgesteuert

require(data.table) 
dtb = data.table(y=1:10, x=10:1, z=sample(1:10), weights=1:10, thedate=1:2) 
models = c("y ~ x", "y ~ z") 

res = lapply(models, function(f) {dtb[,as.list(coef(lm(f, weights=weights, data=.SD))),by=thedate]}) 

#do more stuff with res 

Ich mag würde dies alles in eine Funktion wickeln, da die #doe more stuff lang sein kann. Das Problem, dem ich gegenüberstehe, ist, wie man die verschiedenen Namen der Dinge an data.table weitergibt? Wie gebe ich beispielsweise den Spaltennamen weights? Wie überlasse ich thedate? Ich stelle mir vor, einen Prototyp, der wie folgt aussieht:

myfun = function(dtb, models, weights, dates) 

Lassen Sie mich klar sein: die Formeln meiner Funktion übergeben ist nicht das Problem. Wenn die weights wollte ich verwenden und der Spaltenname beschreibt das Datum, wurde thedate bekannt dann meine Funktion einfach könnte wie folgt aussehen:

myfun = function(dtb, models) { 
res = lapply(models, function(f) {dtb[,as.list(coef(lm(f, weights=weights, data=.SD))),by=thedate]}) 

#do more stuff with res 
} 

jedoch die Spaltennamen entsprechend thedate und zum weights im Voraus nicht bekannt sind. Ich möchte sie als so meiner Funktion zu übergeben:

#this will not work 
myfun = function(dtb, models, w, d) { 
res = lapply(models, function(f) {dtb[,as.list(coef(lm(f, weights=w, data=.SD))),by=d]}) 

#do more stuff with res 
} 

Dank

Antwort

5

Hier ist eine Lösung, die auf mit den Daten im Langformat setzt (was mehr Sinn für mich macht, in dieser

cas
library(reshape2) 
dtlong <- data.table(melt(dtb, measure.var = c('x','z'))) 


foo <- function(f, d, by, w){ 
    # get the name of the w argument (weights) 
    w.char <- deparse(substitute(w)) 
    # convert `list(a,b)` to `c('a','b')` 
    # obviously, this would have to change depending on how `by` was defined 
    by <- unlist(lapply(as.list(as.list(match.call())[['by']])[-1], as.character)) 
    # create the call substituting the names as required 
    .c <- substitute(as.list(coef(lm(f, data = .SD, weights = w), list(w = as.name(w.char))))) 
    # actually perform the calculations 
    d[,eval(.c), by = by] 
} 

foo(f= y~value, d= dtlong, by = list(variable, thedate), w = weights) 

    variable thedate (Intercept)  value 
1:  x  1 11.000000 -1.00000000 
2:  x  2 11.000000 -1.00000000 
3:  z  1 1.009595 0.89019190 
4:  z  2 7.538462 -0.03846154 
+0

interessant. Vielen Dank! – Alex

+0

+1 Vielleicht '.BY' nützlich hier, um die' match.call() 'Zeile zu vermeiden, nicht sicher. –

1

Kannst du nicht einfach hinzufügen (innerhalb dieser anonymen Funktionsaufruf):

f <- as.formula(f) 

... als separate Zeile vor der dtb[,as.list(coef(lm(f, ...)? Das ist die übliche Art, ein Zeichenelement in ein Formelobjekt zu verwandeln.

> res = lapply(models, function(f) {f <- as.formula(f) 
       dtb[,as.list(coef(lm(f, weights=weights, data=.SD))),by=thedate]}) 
> 
> str(res) 
List of 2 
$ :Classes ‘data.table’ and 'data.frame': 2 obs. of 3 variables: 
    ..$ thedate : int [1:2] 1 2 
    ..$ (Intercept): num [1:2] 11 11 
    ..$ x   : num [1:2] -1 -1 
    ..- attr(*, ".internal.selfref")=<externalptr> 
$ :Classes ‘data.table’ and 'data.frame': 2 obs. of 3 variables: 
    ..$ thedate : int [1:2] 1 2 
    ..$ (Intercept): num [1:2] 6.27 11.7 
    ..$ z   : num [1:2] 0.0633 -0.7995 
    ..- attr(*, ".internal.selfref")=<externalptr> 

Wenn Sie Zeichen Versionen von Formeln von Komponentennamen zu bauen, nur paste oder paste0 verwenden und zu den Modellen Charakter Vektor passieren. Getesteter Code, der mit dem Empfang von testbaren Beispielen geliefert wurde.

+0

der Formel nto das ist Ausgabe, "lm" nimmt Strings in Ordnung. Das Problem ist 'Gewichte' und' thedate' – Alex

+0

ich denke, Sie könnten meine Frage missverstanden haben. Ich würde gerne den ganzen Code in eine Funktion setzen – Alex

+0

Ich tat all das war sinnvoll mit dem Beispiel Bitte bearbeiten Sie Ihr Beispiel. –

3

eine mögliche Lösung:

fun = function(dtb, models, w_col_name, date_name) { 
    res = lapply(models, function(f) {dtb[,as.list(coef(lm(f, weights=eval(parse(text=w_col_name)), data=.SD))),by=eval(parse(text=paste0("list(",date_name,")")))]}) 

} 
+1

+1 Ich denke, Sie können 'get()' anstelle von 'eval (parse())' in diesem Fall nicht sicher verwenden. –

Verwandte Themen