2016-08-30 1 views
4

Ich habe einen großen Datensatz mit mehreren Klassen. Mein Ziel ist es, jeder Klasse ein Modell zu geben und dann die Ergebnisse vorherzusagen und sie für jede Klasse in einer Facette zu visualisieren.Anpassung verschiedener Modelle an jede Datenmenge in R

Für ein reproduzierbares Beispiel habe ich etwas Basis erstellt mit mtcars. Dies funktioniert gut für ein einfaches Regressionsmodell für jede Klasse.

mtcars = data.table(mtcars) 
model = mtcars[, list(fit = list(lm(mpg~disp+hp+wt))), keyby = cyl] 
setkey(mtcars, cyl) 
mtcars[model, pred := predict(i.fit[[1]], .SD), by = .EACHI] 
ggplot(data = mtcars, aes(x = mpg, y = pred)) + geom_line() + facet_wrap(~cyl) 

Allerdings möchte ich etwas wie unten versuchen, die noch nicht funktioniert. Dieser Versuch ist mit einer Liste von Formeln, aber ich suche auch, verschiedene Modelle (einige glms, ein paar Bäume) zu jeder Teilmenge von Daten zu senden.

mtcars = data.table(mtcars) 
factors = list(c("disp","wt"), c("disp"), c("hp")) 
form = lapply(factors, function(x) as.formula(paste("mpg~",paste(x,collapse="+")))) 
model = mtcars[, list(fit = list(lm(form))), keyby = cyl] 
setkey(mtcars, cyl) 
mtcars[model, pred := predict(i.fit[[1]], .SD), by = .EACHI] 
ggplot(data = mtcars, aes(x = mpg, y = pred)) + geom_line() + facet_wrap(~cyl) 
+0

ist eine Datentabelle wirklich notwendig? – rawr

+0

Nein, aber es war schneller auf dem großen Datensatz so bevorzugt. dplyr wird auch in Ordnung sein. – Divi

+1

Ich habe nur angedeutet, dass die Engpässe vorhersagen werden, lm, ggplot. ist 'liste (fit = lapply (form, lm, data = .SD))' was du willst – rawr

Antwort

4

Hier ist ein Ansatz, bei dem wir predict als unevaluierten Liste für jedes Modell einrichten, zu bewerten im data.table Objekt, gather die Ausgabe, und gibt es in ggplot:

models = quote(list(
     predict(lm(form[[1]], .SD)), 
     predict(lm(form[[2]], .SD)), 
     predict(lm(form[[3]], .SD)))) 

d <- mtcars 
d[, c("est1", "est2", "est3") := eval(models), by = cyl] 
d <- tidyr::gather(d, key = model, value = pred, est1:est3) 

library(ggplot2) 
ggplot(d, aes(x = mpg, y = pred)) + geom_line() + facet_grid(cyl ~ model) 

Ausgang:

enter image description here

3

lm() nimmt Formel als Zeichenvektor als auch. Ich würde daher erstellen Sie einfach form wie:

form = lapply(factors, function(x) paste("mpg~", paste(x, collapse="+"))) 

Und, müssen Sie die richtigen Daten liefern (entsprechend jede Gruppe des eingebaute spezielle Symbol .SD verwenden):

model = mtcars[, list(fit=lapply(form, lm, data=.SD)), keyby=cyl] 

Für jeden cyl, form wird durchgeschleift und die entsprechende Formel wird als erstes Argument an lm jedes Mal zusammen mit data = .SD übergeben, wobei .SD für Subset von Daten steht und selbst eine data.table ist. Sie können mehr darüber aus der vignettes lesen.


Wenn Sie möchten, auch die Formel in der Folge haben, dann gilt:

chform = unlist(form) 
model = mtcars[, list(form=chform, fit=lapply(form, lm, data=.SD)), keyby = cyl] 

HTH

PS: Bitte lesen Sie this post wenn Sie update() innerhalb [...] mit data.tables verwenden .

+0

Dies löste das Problem, mit dem ich derzeit konfrontiert bin. Nur Frage - Ich verstehe nicht, warum, wenn man ein gemeinsames Modell anpasst, ohne 'data = .SD' zu liefern, funktioniert es? – Divi

+0

Formel-Objekte erfassen auch die Umgebung, in der sie erstellt wurden .. und das wird verwendet werden. Sieh dir '? Lm' an. – Arun

1

Ich mache eigentlich fast genau das im Moment, also perfektes Timing. Das wird eine "ordentlich" - schwere Antwort, aber ich mag die Art, wie es funktioniert.

purrr hat einige sehr nützliche map Funktionen, die diese unglaublich glatt machen, wenn sie mit Listenspalten in tibble kombiniert werden.Verwenden Sie Ihre Definitionen (Ich bin nicht so zu optimieren versuchen)

library(data.table) 
mtcars = data.table(mtcars) 
factors = list(c("disp","wt"), c("disp"), c("hp")) 
form = lapply(factors, function(x) as.formula(paste("mpg~",paste(x,collapse="+")))) 

, die eine Liste von Funktionen zur Verfügung stellt, können diese zu purrr::invoke_map weitergegeben werden, die eine Liste von Argumenten gilt (was Sie haben) auf eine Liste von Funktionen (in Ihrem Fall, nur lm, aber ich vermute, erweiterbar auf andere auch) mit optionalen Argumenten (in Ihrem Beispielfall, mtcars). Mit tibble, werden diese gespeichert als ordentlich data.frame -esque list, sonst werden sie als lm Objekte zurückgegeben werden

library(tibble) 
library(purrr) 
models <- tibble(fit = invoke_map(lm, form, data = mtcars)) 
models 
#> # A tibble: 3 x 1 
#>   fit 
#>  <list> 
#> 1 <S3: lm> 
#> 2 <S3: lm> 
#> 3 <S3: lm> 

Der Super-nützlichen Teil kommt, wenn Sie etwas zu all diese Elemente machen wollen, sagen wir, extrahieren die Einbau Koeffizienten:

map(models$fit, coefficients) 
#> [[1]] 
#> (Intercept)  disp   wt 
#> 34.96055404 -0.01772474 -3.35082533 
#> 
#> [[2]] 
#> (Intercept)  disp 
#> 29.59985476 -0.04121512 
#> 
#> [[3]] 
#> (Intercept)   hp 
#> 30.09886054 -0.06822828 

oder erneut prüfen, die Formel verwendet

map(models$fit, formula) 
#> [[1]] 
#> mpg ~ disp + wt 
#> <environment: 0x0000000017ee73a8> 
#> 
#> [[2]] 
#> mpg ~ disp 
#> <environment: 0x0000000018392c58> 
#> 
#> [[3]] 
#> mpg ~ hp 
#> <environment: 0x0000000018471d18> 

Furth ermore, wenn Sie einige Vorhersagen aus den Modellen hinzugefügt werden sollen, ist dies einfach mit erreicht broom::augment

library(broom) 
models_with_predicts <- models %>% mutate(predict = map(fit, augment)) 
models_with_predicts 
#> # A tibble: 3 x 2 
#>   fit    predict 
#>  <list>     <list> 
#> 1 <S3: lm> <data.frame [32 x 10]> 
#> 2 <S3: lm> <data.frame [32 x 9]> 
#> 3 <S3: lm> <data.frame [32 x 9]> 

Sie können zu einem Datenebene zurück (mit Prognosen) durch unnest() ing, aber das wird kombiniert alle Ihre Daten (fügen Sie eine Gruppierungsebene hinzu, um die Passungen getrennt zu halten)

library(tidyr) 
unnest(models_with_predicts, predict) 

#> # A tibble: 96 x 11 
#> mpg disp wt .fitted .se.fit  .resid  .hat .sigma  .cooksd .std.resid hp 
#> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl> <dbl>  <dbl>  <dbl> <dbl> 
#> 1 21.0 160.0 2.620 23.34543 0.6075520 -2.3454326 0.04339369 2.933379 0.010222201 -0.8222164 NA 
#> 2 21.0 160.0 2.875 22.49097 0.6221836 -1.4909721 0.04550894 2.954135 0.004351414 -0.5232550 NA 
#> 3 22.8 108.0 2.320 25.27237 0.7326015 -2.4723669 0.06309504 2.928665 0.017217431 -0.8757799 NA 
#> 4 21.4 258.0 3.215 19.61467 0.5743205 1.7853334 0.03877647 2.948162 0.005241995 0.6243627 NA 
#> 5 18.7 360.0 3.440 17.05281 1.0943208 1.6471930 0.14078260 2.949120 0.020275438 0.6092882 NA 
#> 6 18.1 225.0 3.460 19.37863 0.6122393 -1.2786309 0.04406584 2.957872 0.003089406 -0.4483953 NA 
#> 7 14.3 360.0 3.570 16.61720 0.9897465 -2.3171997 0.11516157 2.931444 0.030948880 -0.8446199 NA 
#> 8 24.4 146.7 3.190 21.67120 0.9053245 2.7287988 0.09635365 2.918183 0.034431234 0.9842424 NA 
#> 9 22.8 140.8 3.150 21.90981 0.9165259 0.8901898 0.09875274 2.962885 0.003775416 0.3215070 NA 
#> 10 19.2 167.6 3.440 20.46305 0.9678618 -1.2630477 0.11012510 2.957375 0.008693734 -0.4590766 NA 
#> # ... with 86 more rows 
Verwandte Themen