2016-10-20 22 views
0

Я хочу установить логистическую регрессию с h2o.glm, включая некоторые взаимодействия между факторами. Однако простое использование h2o.interaction, за которым следует h2o.glm, заканчивается включением слишком большого количества фиктивных переменных в регрессию. Вот воспроизводимый пример.Как включить взаимодействие факторов с h2o.interaction и h2o.glm в пакете R h2o

# 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? В приведенном выше примере я хотел бы увидеть только 1 фиктивную переменную для взаимодействия между Age и Sex вместо 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" "" 

 Смежные вопросы

  • Нет связанных вопросов^_^