如何在R h2o包

时间:2016-10-20 03:23:20

标签: r h2o

我希望使用h2o.glm进行逻辑回归,包括因子之间的一些相互作用。但是,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个虚拟变量。

2 个答案:

答案 0 :(得分: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()自行模拟。 E.g。

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)
)

但这有点单调乏味,不是这样,而且这些专栏可以在之后重命名。

答案 1 :(得分: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" ""