2016-10-20 23 views
0

我希望能夠與h2o.glm進行邏輯迴歸,包括因素之間的一些相互作用。然而,簡單的使用h2o.interaction後跟h2o.glm最終會在迴歸中包含太多虛擬變量。這是一個可重現的例子。如何在R2H2o包中包含h2o.interaction和h2o.glm因子的相互作用

# model.matrix function in R returns a matrix 
# with the intercept, 1 dummy for Age, 1 dummy for Sex, and 1 dummy for Age:Sex 
colnames(model.matrix(Survived ~ Age + Sex + Age:Sex, data = Titanic)) 
[1] "(Intercept)"  "AgeAdult"   "SexFemale"   "AgeAdult:SexFemale" 

# create an H2OFrame with the interaction of Age and Sex as a factor 
library(h2o) 
h2o.init() 
Titanic.hex <- as.h2o(Titanic) 
interact.hex <- h2o.cbind(Titanic.hex[,c("Survived","Age","Sex")] 
          ,h2o.interaction(Titanic.hex 
          ,factors = list(c("Age", "Sex")) 
          ,pairwise = T 
          ,max_factors = 99 
          ,min_occurrence = 1)) 

# Age_Sex interaction column has 4 levels 
h2o.levels(interact.hex$Age_Sex) 
[1] "Child_Male" "Child_Female" "Adult_Male" "Adult_Female" 

# Because Age_Sex interaction column has 4 levels 
# we end up with 3 dummies to represent Age:Sex 
interact.h2o.glm <- h2o.glm(2:ncol(interact.hex) 
          ,"Survived" 
          ,interact.hex 
          ,family = 'binomial' 
          ,lambda = 0) 
h2o.varimp(interact.h2o.glm)$names 
[1] "Age_Sex.Child_Female" "Age_Sex.Adult_Male" "Age_Sex.Adult_Female" "Sex.Male"    
[5] "Age.Child"   "" 

什麼是做與H2O因素之間的相互作用的好方法使得h2o.glm行爲就像model.matrix?在上面的示例中,我希望看到AgeSex之間的交互只有1個虛擬變量,而不是3個虛擬變量。

回答

0

背景:你所看到的是一種熱門編碼:線性模型只能處理數字,而不能處理類別。 (深入學習。)因此,它爲每個類別(即每個因子級別)創建一個布爾變量。例如。如果他們是男性,gender_male將爲1,否則爲0,而gender_female將爲1,如果他們是女性,則爲0。當您添加交互時,您看到的是對於每個可能的類別組合的布爾值。

H2O的深度學習算法有use_all_factor_levels作爲參數,默認爲true。如果將其設置爲false,則其中一個因素將隱式完成。對於兩級因素,這意味着您將只獲得一列,例如,男性爲0,女性爲1。這會讓你減少你期待的領域。

不幸的是h2o.glm()目前沒有這個選項,並且h2o.interaction()也沒有我能看到的。

您可以使用h2o.ifelse()h2o.cbind()自己模擬它。例如。

interact.hex <- h2o.cbind(
    Titanic.hex[,c("Class","Survived")], 
    h2o.ifelse(Titanic.hex$Age == "Adult", 1, 0), 
    h2o.ifelse(Titanic.hex$Sex == "Female", 1, 0) 
) 
interact.hex <- h2o.cbind(
    interact.hex, 
    h2o.ifelse(interact.hex$C1 == 1 && interact.hex$C10 == 1, 1, 0) 
) 

但是,這有點乏味,是不是,並且列可以做以後重命名。

+0

我也作爲單獨的答案添加了我的解決方法。 h2o.glm可以自動處理因素,但我必須做一個解決方法,以便實質上0 * 0 = 1 * 0 = 0 * 1 = 0.我的解決方法將3個級別0 * 0,1 * 0,0 * 1分解爲單一的水平。 – jmuhlenkamp

+0

@jmuhlenkamp我想你會發現上面的代碼更有效率(並給出相同的值?),因爲我只使用H2O內置函數。如果我已經正確地理解了你的解決方案,那麼是「有H2O製造錯誤的數據,然後用R代碼修復它」? –

+1

我的解決方案實際上只使用R代碼來製作level1字符矢量,然後應用h2o.ifelse來修復數據(我已更新我的ifelse爲h2o.ifelse以使其更清晰)。它絕不會將完整的數據從h2o傳回給R.對我來說也是可取的,因爲我的真實數據(未在此處發佈)具有許多類別的一些因素。在我的解決方法中,我只需要指定因素而不是具體的級別。 – jmuhlenkamp

0

發佈我自己的解決方法,做我想做的事。不過,我仍然很高興看到更優雅或內置的答案。

# create H2OFrame and interact as in the question 
Titanic.hex <- as.h2o(Titanic) 
interact.hex <- h2o.cbind(Titanic.hex[,c("Survived","Age","Sex")] 
          ,h2o.interaction(Titanic.hex 
          ,factors = list(c("Age", "Sex")) 
          ,pairwise = T 
          ,max_factors = 99 
          ,min_occurrence = 1)) 

# Define a function that collapses interaction levels 
collapse_level1_interacts <- function(df, column, col1, col2){ 
    level1 <- rbind(
    data.table::CJ(h2o.levels(df[,col1])[1], h2o.levels(df[,col2])) 
    ,data.table::CJ(h2o.levels(df[,col1]), h2o.levels(df[,col2])[1])) 
    level1 <- paste(level1$V1, level1$V2, sep='_') 
    df[,column] <- h2o.ifelse(df[,column] %in% level1, '00000', df[,column]) 
    return(df) 
} 

# Run the H2oFrame through the function 
interact.hex2 <- collapse_level1_interacts(interact.hex, "Age_Sex", "Age", "Sex") 

# Verify that we have only 2 levels for interaction 
h2o.levels(interact.hex2$Age_Sex) 
[1] "00000"  "Child_Male" 

# Verify that we have only 1 dummy for the interaction 
interact.h2o.glm <- h2o.glm(2:ncol(interact.hex2) 
          ,"Survived" 
          ,interact.hex2 
          ,family = 'binomial' 
          ,lambda = 0) 
h2o.varimp(interact.h2o.glm)$names 
[1] "Age.Child"   "Sex.Male"   "Age_Sex.Child_Male" "" 
相關問題