Практический пример логистической регрессии, когда мы имеем дело со сводными данными вместо двоичных (0,1)

Мы предоставим пример того, как вы можете запустить логистическую регрессию в R, когда данные сгруппированы. Приведем случайную выборку данных из 200 наблюдений.

library(tidyverse)
set.seed(5)
df<-tibble(Gender = as.factor(sample(c("m","f"), 200, replace = TRUE, prob=c(0.6,0.4))),
           Age_Group = as.factor(sample(c("[<30]","[30-65]", "[65+]"), 200, replace = TRUE, prob=c(0.3,0.6,0.1))),
           Response = rbinom(200, 1, prob = 0.2))
df

Вывод:

# A tibble: 200 x 3
   Gender Age_Group Response
   <fct>  <fct>        <int>
 1 f      [65+]            0
 2 m      [30-65]          0
 3 m      [65+]            0
 4 m      [30-65]          0
 5 m      [<30]            0
 6 m      [<30]            0
 7 m      [30-65]          0
 8 m      [30-65]          0
 9 f      [<30]            1
10 f      [<30]            0
# ... with 190 more rows

Логистическая регрессия на неагрегированных данных

Модель логистической регрессии выглядит следующим образом:

model1<-glm(Response ~ Gender+Age_Group, data = df, family = binomial("logit"))
summary(model1)

Вывод:

Call:
glm(formula = Response ~ Gender + Age_Group, family = binomial("logit"), 
    data = df)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-0.7039  -0.6246  -0.6094  -0.5677   1.9754  

Coefficients:
                 Estimate Std. Error z value Pr(>|z|)   
(Intercept)      -1.32296    0.40899  -3.235  0.00122 **
Genderm           0.05402    0.38041   0.142  0.88707   
Age_Group[30-65] -0.26642    0.42010  -0.634  0.52596   
Age_Group[65+]   -0.47482    0.59460  -0.799  0.42455   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 188.56  on 199  degrees of freedom
Residual deviance: 187.83  on 196  degrees of freedom
AIC: 195.83

Number of Fisher Scoring iterations: 4

Логистическая регрессия агрегированных данных

Теперь предположим, что вы получили данные в агрегированной форме и вас попросили запустить логистическую регрессию. Во-первых, нам нужно сгенерировать агрегированные данные.

df_agg<-df%>%group_by(Gender, Age_Group)%>%summarise(Impressions=n(), Responses=sum(Response))%>%
  ungroup()%>%mutate(RR=Responses/Impressions)
df_agg

Вывод:

# A tibble: 6 x 5
  Gender Age_Group Impressions Responses    RR
  <fct>  <fct>           <int>     <int> <dbl>
1 f      [<30]              21         6 0.286
2 f      [30-65]            49         7 0.143
3 f      [65+]               9         1 0.111
4 m      [<30]              30         5 0.167
5 m      [30-65]            66        13 0.197
6 m      [65+]              25         4 0.16

Ниже мы представим три разных решения.

Логистическая регрессия с весами

m2<-glm(RR ~ Gender+Age_Group, data=df_agg, weights = Impressions, family = binomial("logit"))
summary(m2)

Вывод:

Call:
glm(formula = RR ~ Gender + Age_Group, family = binomial("logit"), 
    data = df_agg, weights = Impressions)

Deviance Residuals: 
      1        2        3        4        5        6  
 0.8160  -0.5077  -0.2754  -0.7213   0.4145   0.1553  

Coefficients:
                 Estimate Std. Error z value Pr(>|z|)   
(Intercept)      -1.32296    0.40899  -3.235  0.00122 **
Genderm           0.05402    0.38042   0.142  0.88707   
Age_Group[30-65] -0.26642    0.42010  -0.634  0.52596   
Age_Group[65+]   -0.47482    0.59460  -0.799  0.42455   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 2.4477  on 5  degrees of freedom
Residual deviance: 1.7157  on 2  degrees of freedom
AIC: 29.167

Number of Fisher Scoring iterations: 4

Логистическая регрессия с cbind

Нам нужно будет создать еще один столбец с именем No Responses, а затем мы можем использовать cbind:

df_agg$No_Responses <- df_agg$Impressions- df_agg$Responses
m3<-glm(cbind(Responses, No_Responses) ~ Gender+Age_Group, data=df_agg, family = binomial("logit"))
summary(m3)

Вывод:

Call:
glm(formula = cbind(Responses, No_Responses) ~ Gender + Age_Group, 
    family = binomial("logit"), data = df_agg)

Deviance Residuals: 
      1        2        3        4        5        6  
 0.8160  -0.5077  -0.2754  -0.7213   0.4145   0.1553  

Coefficients:
                 Estimate Std. Error z value Pr(>|z|)   
(Intercept)      -1.32296    0.40899  -3.235  0.00122 **
Genderm           0.05402    0.38042   0.142  0.88707   
Age_Group[30-65] -0.26642    0.42010  -0.634  0.52596   
Age_Group[65+]   -0.47482    0.59460  -0.799  0.42455   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 2.4477  on 5  degrees of freedom
Residual deviance: 1.7157  on 2  degrees of freedom
AIC: 29.167

Number of Fisher Scoring iterations: 4

Разверните агрегированные данные

Наконец, другим подходом будет преобразование совокупных данных в двоичную форму 0 и 1. Давайте сделаем это:

df2 <- df_agg %>% mutate(New_Response = map2(Responses, Impressions, 
                            ~ c(rep(1, .x), 
                                rep(0, .y - .x))))%>%unnest(cols = c(New_Response))
df2

Вывод:

# A tibble: 200 x 7
   Gender Age_Group Impressions Responses    RR No_Responses New_Response
   <fct>  <fct>           <int>     <int> <dbl>        <int>        <dbl>
 1 f      [<30]              21         6 0.286           15            1
 2 f      [<30]              21         6 0.286           15            1
 3 f      [<30]              21         6 0.286           15            1
 4 f      [<30]              21         6 0.286           15            1
 5 f      [<30]              21         6 0.286           15            1
 6 f      [<30]              21         6 0.286           15            1
 7 f      [<30]              21         6 0.286           15            0
 8 f      [<30]              21         6 0.286           15            0
 9 f      [<30]              21         6 0.286           15            0
10 f      [<30]              21         6 0.286           15            0
# ... with 190 more rows

И теперь мы можем работать так же, как вначале.

model4<-glm(New_Response ~ Gender+Age_Group, data = df2, family = binomial("logit"))
summary(model4)

Вывод:

Call:
glm(formula = New_Response ~ Gender + Age_Group, family = binomial("logit"), 
    data = df2)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-0.7039  -0.6246  -0.6094  -0.5677   1.9754  

Coefficients:
                 Estimate Std. Error z value Pr(>|z|)   
(Intercept)      -1.32296    0.40899  -3.235  0.00122 **
Genderm           0.05402    0.38041   0.142  0.88707   
Age_Group[30-65] -0.26642    0.42010  -0.634  0.52596   
Age_Group[65+]   -0.47482    0.59460  -0.799  0.42455   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 188.56  on 199  degrees of freedom
Residual deviance: 187.83  on 196  degrees of freedom
AIC: 195.83

Number of Fisher Scoring iterations: 4

Вывод

Для всех 4 моделей мы пришли к одинаковым коэффициентам и p-значениям. Однако в агрегированной форме мы получаем разные выходные данные относительно отклонения и оценки AIC по сравнению с двоичной формой.

Первоначально опубликовано на https://predictivehacks.com.