2011-06-23 12 views
8

Zawsze miałem problemy ze zrozumieniem dokumentacji dotyczącej sposobu wywoływania metod S3, i tym razem mnie gryzą.S3 i kolejność klas

Przepraszam z góry za zadawanie więcej niż jednego pytania, ale wszystkie są ze sobą ściśle powiązane. Głęboko w sercu złożonego zestawu funkcji, tworzę wiele pasowań glmnet, w szczególności logistycznych. Teraz, dokumentacja glmnet określa jego wartość zwracaną, aby obie klasy "glmnet" i (dla regresji logistycznej) "lognet". W rzeczywistości są one określone w tej kolejności.

Jednak patrząc na koniec realizacji glmnet, Righter po wywołaniu (funkcja wewnętrzna) lognet, że ustawia klasę fit do „lognet”, widzę tę linię kodu tuż przed powrotem (zmiennej fit):

class(fit) = c(class(fit), "glmnet") 

od tego, chciałbym stwierdzić, że kolejność klas jest w istocie „lognet”, „glmnet”.

Niestety pasowanie miałem, miał (jak sugeruje doc):

> class(myfit) 
[1] "glmnet" "lognet" 

Problemem jest to sposób metody S3 są wysyłane do niego, w szczególności predict. Oto kod dla predict.lognet:

function (object, newx, s = NULL, type = c("link", "response", 
    "coefficients", "class", "nonzero"), exact = FALSE, offset, 
    ...) 
{ 
    type = match.arg(type) 
    nfit = NextMethod("predict") #<- supposed to call predict.glmnet, I think 
    switch(type, response = { 
     pp = exp(-nfit) 
     1/(1 + pp) 
    }, class = ifelse(nfit > 0, 2, 1), nfit) 
} 

Dodałem komentarz wyjaśnić moje rozumowanie. Teraz, gdy zgłoszę przewidzieć na tej myfit z nowym DataMatrix mydata i type="response", tak:

predict(myfit, newx=mydata, type="response") 

, nie wiem, jak na dokumentację, uzyskać przewidywanych prawdopodobieństw, ale kombinacje liniowe, która jest dokładnie natychmiastowego wywołania predict.glmnet.

Próbowałem odwrócić kolejność klas, tak jak poniżej:

orgclass<-class(myfit) 
class(myfit)<-rev(orgclass) 

A potem robi przewidzieć zadzwonić ponownie: lo i oto: to działa! I do uzyskać prawdopodobieństwa.

Więc tutaj przyjść jakieś pytania:

  1. mam rację „dowiedziawszy” że S3 metody są wywoływane w kolejności wyglądu klas?
  2. mam rację zakładając kod w glmnet mogłoby spowodować niewłaściwe zamówienie dla prawidłowego wysyłek predict?
  3. W moim kodzie nie ma nic, co manipuluje klasami jawnie/widocznie według mojej wiedzy. Co może spowodować zmianę zamówienia na ?

kompletności boską: oto przykładowy kod, aby bawić się z (jak robię sobie teraz):

library(glmnet) 
y<-factor(sample(2, 100, replace=TRUE)) 
xs<-matrix(runif(100), ncol=1) 
colnames(xs)<-"x" 
myfit<-glmnet(xs, y, family="binomial") 
mydata<-matrix(runif(10), ncol=1) 
colnames(mydata)<-"x" 
class(myfit) 
predict(myfit, newx=mydata, type="response") 
class(myfit)<-rev(class(myfit)) 
class(myfit) 
predict(myfit, newx=mydata, type="response") 
class(myfit)<-rev(class(myfit))#set it back 
class(myfit) 

zależności od danych generowanych, różnica jest bardziej lub mniej oczywiste (w moim prawdziwym zestawie danych zauważyłem ujemne wartości w tak zwanych prawdopodobieństwach, w ten sposób podjąłem problem), ale naprawdę powinniście zobaczyć różnicę.

Dzięki za wszelkie dane wejściowe.

Edit:

Właśnie okazało się straszną prawdę: albo kolejność pracował w glmnet 1.5.2 (który jest obecny na serwerze, gdzie wpadłem rzeczywisty kod, w wyniku ataku z zamówieniem klasy odwrócony), ale kod z wersji 1.6 wymaga, aby kolejność brzmiała "lognet", "glmnet". Muszę jeszcze sprawdzić, co dzieje się w 1.7.

Podziękowania dla @Aarona za przypomnienie podstaw informatyki (oprócz "jeśli wszystko inne zawiedzie, uruchom ponownie": "sprawdź wersje"). Błędnie założyłem, że pakiet bogów statystycznego uczenia się będzie chroniony przed tego rodzaju błędem), a także @Gavinowi za potwierdzenie mojej rekonstrukcji sposobu działania S3.

+2

Po uruchomieniu kodu otrzymuję polecenie '" lognet "" glmnet "' po pierwszym wywołaniu 'class', które jest odwrotne od tego, co mówisz. Mam glmnet 1.7; jaka masz wersję? – Aaron

Odpowiedz

6

Tak, kolejność wysyłek jest zgodna z kolejnością, w jakiej klasy są wymienione w atrybucie klasy. W prostym, codziennym przypadku, tak, pierwsza określona klasa jest wybrana najpierw przez rozsyłanie metody, i tylko wtedy, gdy nie uda się znaleźć metody dla tej klasy (lub zostanie wywołana NextMethod) przejdzie do drugiej klasy lub nieudane wyszukiwanie metody default.

Nie, nie sądzę, że masz rację, że kolejność klas jest błędna w kodzie. Dokumentacja wydaje się błędna. Chodzi o to, aby najpierw zadzwonić pod numer predict.lognet(), użyć robota pociągowego predict.glmnet(), aby wykonać podstawowe obliczenia dla wszystkich typów lasso/elastycznych modeli sieciowych dopasowanych przez glmnet, a na koniec wykonać pewne przetwarzanie tych ogólnych prognoz. Ten predict.glmnet() jest wyeksportowany z NAMESPACE, podczas gdy inne metody też mogą być również znane.

Nie jestem pewien, dlaczego uważasz, że wyjście z tego:

predict(myfit, newx=mydata, type="response") 

jest źle? Otrzymuję macierz składającą się z 10 rzędów i 21 kolumn, z kolumnami odnoszącymi się do prognozy modelu tylko przechwytującego oraz prognozami dla 20 wartości lambda, dla których obliczono współczynniki modelu wzdłuż ścieżki lasso/elastycznej sieci. Nie wydają się one być kombinacjami liniowymi i są jedną skalą odpowiedzi, o którą prosiłeś.

Kolejność klas się nie zmienia. Myślę, że nie rozumiesz, w jaki sposób kod ma działać. W dokumentacji jest błąd, ponieważ zamówienie jest błędne. Ale kod działa tak jak powinienem.

+0

Świetna odpowiedź, ale jedno małe zastrzeżenie: nie możesz zmienić klasy podczas wysyłki metody: https://gist.github.com/1043952 (cóż, możesz, to nie ma wpływu na wysyłkę) – hadley

+0

Wygląda na to, że że intencją jest 'predict.lognet', a następnie' predict.glmnet'. Ale jak czytam, OP mówi, że najpierw uruchamia 'predict.glmnet' w swoim systemie, ponieważ kolejność klas jest odwrócona. – Aaron

+0

@Hadley dzięki za wskazanie tego. Musiałem to zapomnieć. Naprawiono teraz. –