Ponowne użycie modelu wbudowanego w R

82

Podczas budowania modelu w języku R, jak zapisać specyfikacje modelu, aby można było ich ponownie użyć na nowych danych? Powiedzmy, że buduję regresję logistyczną na danych historycznych, ale nowe obserwacje pojawią się dopiero w przyszłym miesiącu. Jakie jest najlepsze podejście?

Rzeczy, które rozważałem:

  • Zapisywanie obiektu modelu i ładowanie w nowej sesji
  • Wiem, że niektóre modele można eksportować za pomocą PMML, ale tak naprawdę nie widziałem nic o importowaniu PMML

Po prostu staram się zrozumieć, co robisz, kiedy musisz użyć swojego modelu w nowej sesji.

Z góry dziękuję.

Btibert3
źródło
Cóż, zawsze możesz "zapisać" modelową formułę i podać zaktualizowane dane w dataargumentacji ... zakładając, że dobrze cię zrozumiałem ...
aL3xa
Hmm, co masz na myśli mówiąc o ponownym użyciu? Przewidzieć nowe obserwacje lub zaktualizować model tak, aby używał nowych i starych obserwacji?
Gavin Simpson,
@Gavin. Chcę wykorzystać opracowany przeze mnie model do przewidywania nowych wartości na danych, których jeszcze nie mam i które mogą nie mieć przez jakiś czas.
Btibert3,
1
@ Bitbert3 OK, więc początkowa część mojej odpowiedzi jest taka, co bym zrobił. Zapisanie obiektu modelu na dysku jest więcej niż akceptowalne, ale ważne jest, aby zapisać kod / skrypt R używany do generowania modelu w pierwszej kolejności, aby Twoje badania / modelowanie były odtwarzalne.
Gavin Simpson,

Odpowiedzi:

144

Ponowne wykorzystanie modelu do przewidywania nowych obserwacji

Jeśli model nie jest kosztowny obliczeniowo, zwykle dokumentuję cały proces budowy modelu w skrypcie R, który w razie potrzeby uruchamiam ponownie. Jeśli w dopasowaniu modelu występuje element losowy, upewniam się, że ustawiam znane losowe ziarno.

Jeśli obliczenie modelu jest kosztowne, nadal używam skryptu jak powyżej, ale zapisuję obiekty modelu za pomocą save()into i obiektu rda. Następnie mam tendencję do modyfikowania skryptu w taki sposób, że jeśli zapisany obiekt istnieje, ładuję go, a jeśli nie, ponownie modyfikuję model, używając prostej if()...elseklauzuli owiniętej wokół odpowiednich części kodu.

Podczas ładowania zapisanego obiektu modelu pamiętaj o ponownym załadowaniu wszystkich wymaganych pakietów, chociaż w twoim przypadku, jeśli model logit został dopasowany przez, glm()nie będzie żadnych dodatkowych pakietów do załadowania poza R.

Oto przykład:

> set.seed(345)
> df <- data.frame(x = rnorm(20))
> df <- transform(df, y = 5 + (2.3 * x) + rnorm(20))
> ## model
> m1 <- lm(y ~ x, data = df)
> ## save this model
> save(m1, file = "my_model1.rda")
> 
> ## a month later, new observations are available: 
> newdf <- data.frame(x = rnorm(20))
> ## load the model
> load("my_model1.rda")
> ## predict for the new `x`s in `newdf`
> predict(m1, newdata = newdf)
        1         2         3         4         5         6 
6.1370366 6.5631503 2.9808845 5.2464261 4.6651015 3.4475255 
        7         8         9        10        11        12 
6.7961764 5.3592901 3.3691800 9.2506653 4.7562096 3.9067537 
       13        14        15        16        17        18 
2.0423691 2.4764664 3.7308918 6.9999064 2.0081902 0.3256407 
       19        20 
5.4247548 2.6906722 

Jeśli chciałbym to zautomatyzować, prawdopodobnie wykonałbym w skrypcie następujące czynności:

## data
df <- data.frame(x = rnorm(20))
df <- transform(df, y = 5 + (2.3 * x) + rnorm(20))

## check if model exists? If not, refit:
if(file.exists("my_model1.rda")) {
    ## load model
    load("my_model1.rda")
} else {
    ## (re)fit the model
    m1 <- lm(y ~ x, data = df)
}

## predict for new observations
## new observations
newdf <- data.frame(x = rnorm(20))
## predict
predict(m1, newdata = newdf)

Oczywiście kod generujący dane zostałby zastąpiony kodem ładującym rzeczywiste dane.

Aktualizacja wcześniej dopasowanego modelu o nowe obserwacje

Jeśli chcesz ponownie dopasować model, korzystając z dodatkowych nowych obserwacji. Wtedy update()jest to przydatna funkcja. Wszystko, co robi, to ponownie dopasować model, dodając jeden lub więcej zaktualizowanych argumentów modelu. Jeśli chcesz uwzględnić nowe obserwacje w danych używanych do dopasowania modelu, dodaj nowe obserwacje do ramki danych przekazanej do argumentu 'data', a następnie wykonaj następujące czynności:

m2 <- update(m1, . ~ ., data = df)

gdzie m1jest oryginalne, zapisane dopasowanie modelu, . ~ .to zmiana formuły modelu, co w tym przypadku oznacza uwzględnienie wszystkich istniejących zmiennych zarówno po lewej, jak i prawej stronie ~(innymi słowy, nie wprowadzaj żadnych zmian w formule modelu) i dfjest ramka danych używana do dopasowania oryginalnego modelu, rozszerzona o nowo dostępne obserwacje.

Oto działający przykład:

> set.seed(123)
> df <- data.frame(x = rnorm(20))
> df <- transform(df, y = 5 + (2.3 * x) + rnorm(20))
> ## model
> m1 <- lm(y ~ x, data = df)
> m1

Call:
lm(formula = y ~ x, data = df)

Coefficients:
(Intercept)            x  
      4.960        2.222  

> 
> ## new observations
> newdf <- data.frame(x = rnorm(20))
> newdf <- transform(newdf, y = 5 + (2.3 * x) + rnorm(20))
> ## add on to df
> df <- rbind(df, newdf)
> 
> ## update model fit
> m2 <- update(m1, . ~ ., data = df)
> m2

Call:
lm(formula = y ~ x, data = df)

Coefficients:
(Intercept)            x  
      4.928        2.187

Inni wspominali w komentarzach formula(), które wyciągają wzór z dopasowanego modelu:

> formula(m1)
y ~ x
> ## which can be used to set-up a new model call
> ## so an alternative to update() above is:
> m3 <- lm(formula(m1), data = df)

Jeśli jednak dopasowanie modelu obejmuje dodatkowe argumenty, takie jak 'family'lub 'subset'argumenty w bardziej złożonych funkcjach dopasowania modelu. Jeśli update()dla funkcji dopasowania modelu dostępne są metody (które są stosowane w przypadku wielu typowych funkcji dopasowania, takich jak glm()), zapewnia to prostszy sposób aktualizacji dopasowania modelu niż wyodrębnianie i ponowne użycie formuły modelu.

Jeśli zamierzasz wykonać całe modelowanie i przewidywanie przyszłości w języku R, tak naprawdę nie ma sensu wyodrębniać modelu za pomocą PMML lub podobnego.

Gavin Simpson
źródło
1
+1 i jeśli uprzejmie powstrzymałbyś się przed edytowaniem swoich odpowiedzi, aby pasowały do ​​odpowiedzi, którą przygotowywałem ... ;-)
Joris Meys
@Joris ain't precognition a bitch! ;-) +1 updateode mnie
Gavin Simpson
1
To naprawdę świetna odpowiedź. Mam nadzieję, że ktoś wybierze odpowiedzi SO [r], takie jak ta, i złoży je razem jako samouczek.
JD Long,
1
Doskonała odpowiedź. Dziękuję za przykłady, które podałeś.
nhern121
1
Dokładnie to, czego szukałem. Chcę zrobić +1000 ... Dziękuję
Adjeiinfo
7

Jeśli używasz tej samej nazwy ramki danych i zmiennych, możesz (przynajmniej dla lm()i glm()) użyć tej funkcji updatena zapisanym modelu:

Df <- data.frame(X=1:10,Y=(1:10)+rnorm(10))

model <- lm(Y~X,data=Df)
model

Df <- rbind(Df,data.frame(X=2:11,Y=(10:1)+rnorm(10)))

update(model)

Jest to oczywiście bez przygotowania danych i tak dalej. Po prostu ponownie wykorzystuje zestaw specyfikacji modelu. Należy pamiętać, że jeśli w międzyczasie zmienisz kontrasty, nowy model zostanie zaktualizowany o nowe, a nie stary.

Tak więc użycie skryptu jest w większości przypadków lepszą odpowiedzią. Można by uwzględnić wszystkie kroki w wygodnej funkcji, która po prostu pobiera ramkę danych, dzięki czemu można pobrać skrypt, a następnie użyć tej funkcji na dowolnym nowym zbiorze danych. Zobacz także odpowiedź Gavina.

Joris Meys
źródło