2015-08-10 4 views
1

У меня есть набор данных, содержащийся в dataframe daf, который я разделяю на учебные и тестовые данные на основе даты, например. поездить по датам ниже 20090000 и проверять даты выше. Для этого мы разделили исходный фрейм данных на daf_train и daf_test.Обработка неизвестных уровней фактора в R GLM

Я использую GLM и имеют коэффициент в модели daf$city. Возникает вопрос, что daf_test иногда содержит новый город, который не был замечен в daf_train.

Я имею в виду лучший способ обойти это сделать что-то вроде

levels(daf_train$city) = levels(daf$city) 

в prewarn его обо всех возможных городах.

Мне бы хотелось, чтобы GLM признал, что для городов, которые раньше не были замечены, возьмите в среднем факторные коэффициенты для городов. Если бы все коэффициенты предыдущих коэффициентов имели нулевое значение, я думаю, что это будет достаточно хорошо.

Как бы я изменить код, чтобы сделать это

mylogit = glm(Y ~ X + factor(city), data=daf_train, family=binomial(link='logit')) 
predictions = predict(mylogit, daf_test, type='response') 

Note, действительно уродливые и нон общий способ сделать это (я тоже довольно новый для R поэтому, возможно, это будет также беспорядок с объектом GLM) является

cityLevels = levels(factor(daf$city)) 
daf_train$city = factor(daf_train$city, cityLevels) 

# daf_train$city now has all the levels of the overall dataset 
# But if we train a GLM now, it will ignore any levels without observations 

# Instead we split the factor into binary variables 
train_data = cbind(daf_train, model.matrix(~ 0 + city, daf_train)) 
# Remove the factor variable 
train_data$city = NULL 

# Now train the GLM 
mylogit = glm(Y ~., data = train_data, family=binomial(link='logit')) 

# This gives us coefficient values for all factors in the training set 
# Any factors not in the training set get coefficient values of NA 

# Finally we must convert the factor coefficients to have zero mean 
offset = mean(mylogit$coefficients[-1:-34]) 
mylogit$coefficients[-1:-34] = mylogit$coefficients[-1:-34] - offset 
mylogit$coefficients[1] = mylogit$coefficients[1] + offset 

# Yeuch, this required us to know where in our coefficients vector our cities started (34) 
+1

Не уверен, что вы решите проблему, если используете «уровень», как описано. Я думаю, что модель не будет давать никаких коэффициентов для уровней, которые не включены в ваш набор поездов. Я решил эту проблему в прошлом, используя (тщательно) красивую стратифицированную выборку, основанную на уровнях этой переменной. Таким образом, все уровни включаются как в тестовый, так и в тренировочный набор. – AntoniosK

+0

Я не совсем уверен, что понимаю, но в моем случае я бы не хотел, чтобы новый город в тестовом наборе когда-либо видел GLM. Я просто хочу, чтобы он знал, что если он увидит новый город, присвойте нулю все факторы. – rwolst

+0

Например, если у вас было три города в наборе обучения с оценкой параметров glm 0 (по умолчанию), 0,1, -0,4; и в тестовом наборе четыре города (один новый); вы хотите, чтобы четвертая оценка параметра была средней (0, 0,1, -0,4) = -0,1? – Whitebeard

ответ

1

Я думаю, что это то, что вы ищете. Все еще довольно уродливо, но я думаю, что это немного более общий, чем ваш код. Дайте мне знать, если он пропустит отметку, и я могу изменить или удалить.

# dummy data 
set.seed(321) 
daf_train <- data.frame(x = runif(100, min=10, max=50), 
         y = runif(100), 
         city = sample(c("city1", "city2", "city3"), size=100, replace=TRUE)) 

set.seed(321) 
daf_test <- data.frame(x = runif(30, min=10, max=50), 
         y = runif(30), 
         city = sample(c("city1", "city2", "city3", "city4"), size=30, replace=TRUE)) 

daf_train$city <- factor(daf_train$city, levels=levels(daf_test$city)) 


# cities in test set but not train set 
(newcity <- sort(unique(daf_test$city))[!sort(unique(daf_test$city)) %in% unique(daf_train$city)]) 
[1] city4 
Levels: city1 city2 city3 city4 

# fit model with city1, city2, city3 
xreg <- cbind(x=daf_train$x, model.matrix(~ 0 + city, data=daf_train)) 

mylogit = glm(y ~ xreg, data=daf_train, family=binomial(link='logit')) 

newxreg <- cbind(x=daf_test$x, model.matrix(~ 0 + city, data=daf_test)) 

# mean of city coefficients 
if (length(newcity) > 0) { 

    # coefficients from model 
    citycoef <- coef(mylogit)[grepl("city", names(coef(mylogit)))] 

    # calculate coefficient for new city(cities) 
    citycoef_offset <- mean(citycoef, na.rm=TRUE) 

    # repeat for all new cities 
    citycoef[is.na(citycoef)] <- citycoef_offset 

    # center coefficients 
    citycoef <- scale(citycoef, center=TRUE, scale=FALSE)[, 1] 

    # replace city coefficients from model 
    modelcoef <- coef(mylogit) 

    # add offset to intercept 
    modelcoef[["(Intercept)"]] <- modelcoef[["(Intercept)"]] + citycoef_offset 

    # all new coefficients 
    modelcoef[match(names(citycoef), names(modelcoef))] <- citycoef 

    # Beta0 + Beta1x... 
    pcoef <- modelcoef[["(Intercept)"]] + 
    newxreg %*% 
    modelcoef[!names(modelcoef) == "(Intercept)"] 

    #predicted response 
    predictions <- unlist(lapply(pcoef, function(x) exp(x)/(1 + exp(x)))) 


} else { 
    predictions <- predict(mylogit, daf_test, type="response") 
} 
Смежные вопросы