Introdução à Análise de Dados e Modelação Estatística

Lab#2 – Modelos de regressão linear

Autor

Paulo Soares

Data de Publicação

28 de maio de 2025

1 Diabetes

Foram registados os valores de 10 variáveis clínicas para cada um de 442 doentes de diabetes, assim como uma medida quantitativa da progressão da doença ao fim de um ano (Y).

Os dados encontram-se disponíveis em:

https://web.tecnico.ulisboa.pt/paulo.soares/iadme/dados/diabetes.txt (18.1KB),

e a descrição das variáveis (em Inglês) pode ser lida aqui.

1.1 Leitura e análise exploratória

  1. Leia o ficheiro de dados para o R e inspecione a data frame criada. Melhore a estrutura dos dados, reparando possíveis incorreções.

    url <- "https://web.tecnico.ulisboa.pt/paulo.soares/iadme/dados/diabetes.txt"
    db <- read.delim(url)
    str(db)
    'data.frame':   442 obs. of  11 variables:
     $ AGE: int  59 48 72 24 50 23 36 66 60 29 ...
     $ SEX: int  2 1 2 1 1 1 2 2 2 1 ...
     $ BMI: num  32.1 21.6 30.5 25.3 23 22.6 22 26.2 32.1 30 ...
     $ BP : num  101 87 93 84 101 89 90 114 83 85 ...
     $ S1 : int  157 183 156 198 192 139 160 255 179 180 ...
     $ S2 : num  93.2 103.2 93.6 131.4 125.4 ...
     $ S3 : num  38 70 41 40 52 61 50 56 42 43 ...
     $ S4 : num  4 3 4 5 4 2 3 4.55 4 4 ...
     $ S5 : num  4.86 3.89 4.67 4.89 4.29 ...
     $ S6 : int  87 69 85 89 80 68 82 92 94 88 ...
     $ Y  : int  151 75 141 206 135 97 138 63 110 310 ...
    db$SEX <- as.factor(db$SEX)
    summary(db)
          AGE       SEX          BMI             BP              S1     
     Min.   :19.0   1:235   Min.   :18.0   Min.   : 62.0   Min.   : 97  
     1st Qu.:38.2   2:207   1st Qu.:23.2   1st Qu.: 84.0   1st Qu.:164  
     Median :50.0           Median :25.7   Median : 93.0   Median :186  
     Mean   :48.5           Mean   :26.4   Mean   : 94.6   Mean   :189  
     3rd Qu.:59.0           3rd Qu.:29.3   3rd Qu.:105.0   3rd Qu.:210  
     Max.   :79.0           Max.   :42.2   Max.   :133.0   Max.   :301  
           S2              S3             S4             S5             S6       
     Min.   : 41.6   Min.   :22.0   Min.   :2.00   Min.   :3.26   Min.   : 58.0  
     1st Qu.: 96.0   1st Qu.:40.2   1st Qu.:3.00   1st Qu.:4.28   1st Qu.: 83.2  
     Median :113.0   Median :48.0   Median :4.00   Median :4.62   Median : 91.0  
     Mean   :115.4   Mean   :49.8   Mean   :4.07   Mean   :4.64   Mean   : 91.3  
     3rd Qu.:134.5   3rd Qu.:57.8   3rd Qu.:5.00   3rd Qu.:5.00   3rd Qu.: 98.0  
     Max.   :242.4   Max.   :99.0   Max.   :9.09   Max.   :6.11   Max.   :124.0  
           Y      
     Min.   : 25  
     1st Qu.: 87  
     Median :140  
     Mean   :152  
     3rd Qu.:212  
     Max.   :346  
  2. Analise a associação entre a variável resposta, Y, e cada uma das restantes variáveis, recorrendo a medidas numéricas e a representações gráficas.

    library(ggplot2)
    library(dplyr)
    
    db |>
        tidyr::pivot_longer(-c(Y, SEX), names_to = "Covariável",
                                        values_to = "Valor") |>
        ggplot() +
            geom_point(aes(Valor, Y, color = SEX), size = 1/3) + 
            facet_wrap(~ Covariável, scales = "free_x") +
            theme_light() +
            theme(legend.position = "top")

    db |> 
        select(-SEX) |>
        cor()
             AGE     BMI      BP      S1      S2       S3      S4      S5      S6
    AGE  1.00000  0.1851  0.3354 0.26006  0.2192 -0.07518  0.2038  0.2708  0.3017
    BMI  0.18508  1.0000  0.3954 0.24978  0.2612 -0.36681  0.4138  0.4462  0.3887
    BP   0.33543  0.3954  1.0000 0.24246  0.1855 -0.17876  0.2577  0.3935  0.3904
    S1   0.26006  0.2498  0.2425 1.00000  0.8967  0.05152  0.5422  0.5155  0.3257
    S2   0.21924  0.2612  0.1855 0.89666  1.0000 -0.19646  0.6598  0.3184  0.2906
    S3  -0.07518 -0.3668 -0.1788 0.05152 -0.1965  1.00000 -0.7385 -0.3986 -0.2737
    S4   0.20384  0.4138  0.2577 0.54221  0.6598 -0.73849  1.0000  0.6179  0.4172
    S5   0.27077  0.4462  0.3935 0.51550  0.3184 -0.39858  0.6179  1.0000  0.4647
    S6   0.30173  0.3887  0.3904 0.32572  0.2906 -0.27370  0.4172  0.4647  1.0000
    Y    0.18789  0.5865  0.4415 0.21202  0.1741 -0.39479  0.4305  0.5659  0.3825
              Y
    AGE  0.1879
    BMI  0.5865
    BP   0.4415
    S1   0.2120
    S2   0.1741
    S3  -0.3948
    S4   0.4305
    S5   0.5659
    S6   0.3825
    Y    1.0000
    GGally::ggcorr(db)

    GGally::ggpairs(db) + theme_light()

1.2 Regressão linear no

  1. A função lm é usada no R para ajustar modelos de regressão, incluindo os modelos multivariados. Use essa função para ajustar um MRLS com a covariável BMI e explore o objeto devolvido pela função.

    modelo <- lm(Y ~ BMI, data = db)
    modelo
    
    Call:
    lm(formula = Y ~ BMI, data = db)
    
    Coefficients:
    (Intercept)          BMI  
         -117.8         10.2  
    sm <- summary(modelo)
    sm
    
    Call:
    lm(formula = Y ~ BMI, data = db)
    
    Residuals:
        Min      1Q  Median      3Q     Max 
    -164.92  -43.57   -8.65   46.34  154.88 
    
    Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
    (Intercept) -117.773     18.019   -6.54  1.8e-10 ***
    BMI           10.233      0.674   15.19  < 2e-16 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 62.5 on 440 degrees of freedom
    Multiple R-squared:  0.344, Adjusted R-squared:  0.342 
    F-statistic:  231 on 1 and 440 DF,  p-value: <2e-16
    sm$coefficients
                Estimate Std. Error t value  Pr(>|t|)
    (Intercept)  -117.77    18.0189  -6.536 1.752e-10
    BMI            10.23     0.6738  15.187 3.466e-42
    sm$sigma
    [1] 62.52
    sm$r.squared
    [1] 0.3439
  2. Calcule intervalos de confiança a 96% para os parâmetros de regressão e para o valor esperado da variável resposta para pessoas em que os valores de BMI são iguais a 25 e 40.

    confint(modelo, level = 0.96)
                     2 %   98 %
    (Intercept) -154.890 -80.66
    BMI            8.845  11.62
    novos_dados <- data.frame(BMI = c(25, 40))
    predict(modelo, novos_dados, level = 0.96, interval = "confidence")
        fit   lwr   upr
    1 138.1 131.6 144.5
    2 291.6 271.7 311.4
    predict(modelo, novos_dados, level = 0.96, interval = "prediction")
        fit     lwr   upr
    1 138.1   9.123 267.0
    2 291.6 161.255 421.8

1.3 A especificação de modelos

No R, os modelos são especificados numa forma simbólica compacta. Da documentação:

The ~ operator is basic in the formation of such models. An expression of the form y ~ model is interpreted as a specification that the response y is modelled by a linear predictor specified symbolically by model. Such a model consists of a series of terms separated by + operators. The terms themselves consist of variable and factor names separated by : operators. Such a term is interpreted as the interaction of all the variables and factors appearing in the term.

Defina os seguintes modelos:

  1. um modelo de primeira ordem com todas as covariáveis exceto SEX;

    f1 <- Y ~ . - SEX
    
    terms(f1, data = db)
    Y ~ (AGE + SEX + BMI + BP + S1 + S2 + S3 + S4 + S5 + S6) - SEX
    attr(,"variables")
    list(Y, AGE, SEX, BMI, BP, S1, S2, S3, S4, S5, S6)
    attr(,"factors")
        AGE BMI BP S1 S2 S3 S4 S5 S6
    Y     0   0  0  0  0  0  0  0  0
    AGE   1   0  0  0  0  0  0  0  0
    SEX   0   0  0  0  0  0  0  0  0
    BMI   0   1  0  0  0  0  0  0  0
    BP    0   0  1  0  0  0  0  0  0
    S1    0   0  0  1  0  0  0  0  0
    S2    0   0  0  0  1  0  0  0  0
    S3    0   0  0  0  0  1  0  0  0
    S4    0   0  0  0  0  0  1  0  0
    S5    0   0  0  0  0  0  0  1  0
    S6    0   0  0  0  0  0  0  0  1
    attr(,"term.labels")
    [1] "AGE" "BMI" "BP"  "S1"  "S2"  "S3"  "S4"  "S5"  "S6" 
    attr(,"order")
    [1] 1 1 1 1 1 1 1 1 1
    attr(,"intercept")
    [1] 1
    attr(,"response")
    [1] 1
    attr(,".Environment")
    <environment: R_GlobalEnv>
  2. um modelo para o logaritmo da variável resposta que inclua as variáveis BMI e BP e a sua interação;

    f2 <- log(Y) ~ BMI * BP
    terms(f2, data = db)
    log(Y) ~ BMI * BP
    attr(,"variables")
    list(log(Y), BMI, BP)
    attr(,"factors")
           BMI BP BMI:BP
    log(Y)   0  0      0
    BMI      1  0      1
    BP       0  1      1
    attr(,"term.labels")
    [1] "BMI"    "BP"     "BMI:BP"
    attr(,"order")
    [1] 1 1 2
    attr(,"intercept")
    [1] 1
    attr(,"response")
    [1] 1
    attr(,".Environment")
    <environment: R_GlobalEnv>
  3. um modelo com as covariáveis S1 até S6 e todas as suas interações de segunda ordem;

    f3 <- Y ~ (S1 + S2 + S3 + S4 + S5 + S6)^2
    terms(f3, data = db)
    Y ~ (S1 + S2 + S3 + S4 + S5 + S6)^2
    attr(,"variables")
    list(Y, S1, S2, S3, S4, S5, S6)
    attr(,"factors")
       S1 S2 S3 S4 S5 S6 S1:S2 S1:S3 S1:S4 S1:S5 S1:S6 S2:S3 S2:S4 S2:S5 S2:S6
    Y   0  0  0  0  0  0     0     0     0     0     0     0     0     0     0
    S1  1  0  0  0  0  0     1     1     1     1     1     0     0     0     0
    S2  0  1  0  0  0  0     1     0     0     0     0     1     1     1     1
    S3  0  0  1  0  0  0     0     1     0     0     0     1     0     0     0
    S4  0  0  0  1  0  0     0     0     1     0     0     0     1     0     0
    S5  0  0  0  0  1  0     0     0     0     1     0     0     0     1     0
    S6  0  0  0  0  0  1     0     0     0     0     1     0     0     0     1
       S3:S4 S3:S5 S3:S6 S4:S5 S4:S6 S5:S6
    Y      0     0     0     0     0     0
    S1     0     0     0     0     0     0
    S2     0     0     0     0     0     0
    S3     1     1     1     0     0     0
    S4     1     0     0     1     1     0
    S5     0     1     0     1     0     1
    S6     0     0     1     0     1     1
    attr(,"term.labels")
     [1] "S1"    "S2"    "S3"    "S4"    "S5"    "S6"    "S1:S2" "S1:S3" "S1:S4"
    [10] "S1:S5" "S1:S6" "S2:S3" "S2:S4" "S2:S5" "S2:S6" "S3:S4" "S3:S5" "S3:S6"
    [19] "S4:S5" "S4:S6" "S5:S6"
    attr(,"order")
     [1] 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    attr(,"intercept")
    [1] 1
    attr(,"response")
    [1] 1
    attr(,".Environment")
    <environment: R_GlobalEnv>
  4. um modelo com as covariáveis BMI, BP e (S1+S2+S3).

    f4 <- Y ~ BMI + BP + I(S1 + S2 + S3)
    terms(f4, data = db)
    Y ~ BMI + BP + I(S1 + S2 + S3)
    attr(,"variables")
    list(Y, BMI, BP, I(S1 + S2 + S3))
    attr(,"factors")
                    BMI BP I(S1 + S2 + S3)
    Y                 0  0               0
    BMI               1  0               0
    BP                0  1               0
    I(S1 + S2 + S3)   0  0               1
    attr(,"term.labels")
    [1] "BMI"             "BP"              "I(S1 + S2 + S3)"
    attr(,"order")
    [1] 1 1 1
    attr(,"intercept")
    [1] 1
    attr(,"response")
    [1] 1
    attr(,".Environment")
    <environment: R_GlobalEnv>

Notas

  1. a matriz de delineamento pode ser obtida com a função model.matrix.

    md1 <- model.matrix(f1, data = db)
    # Retirar o comentário da linha abaixo se gostar de olhar para grandes matrizes.
    # md1
  2. as fórmulas também podem ser escritas como texto.

    f <- paste("Y ~", paste0("V", 1:20, collapse = " + "))
    terms(formula(f))
    Y ~ V1 + V2 + V3 + V4 + V5 + V6 + V7 + V8 + V9 + V10 + V11 + 
        V12 + V13 + V14 + V15 + V16 + V17 + V18 + V19 + V20
    attr(,"variables")
    list(Y, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, 
        V14, V15, V16, V17, V18, V19, V20)
    attr(,"factors")
        V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20
    Y    0  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0
    V1   1  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0
    V2   0  1  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0
    V3   0  0  1  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0
    V4   0  0  0  1  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0
    V5   0  0  0  0  1  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0
    V6   0  0  0  0  0  1  0  0  0   0   0   0   0   0   0   0   0   0   0   0
    V7   0  0  0  0  0  0  1  0  0   0   0   0   0   0   0   0   0   0   0   0
    V8   0  0  0  0  0  0  0  1  0   0   0   0   0   0   0   0   0   0   0   0
    V9   0  0  0  0  0  0  0  0  1   0   0   0   0   0   0   0   0   0   0   0
    V10  0  0  0  0  0  0  0  0  0   1   0   0   0   0   0   0   0   0   0   0
    V11  0  0  0  0  0  0  0  0  0   0   1   0   0   0   0   0   0   0   0   0
    V12  0  0  0  0  0  0  0  0  0   0   0   1   0   0   0   0   0   0   0   0
    V13  0  0  0  0  0  0  0  0  0   0   0   0   1   0   0   0   0   0   0   0
    V14  0  0  0  0  0  0  0  0  0   0   0   0   0   1   0   0   0   0   0   0
    V15  0  0  0  0  0  0  0  0  0   0   0   0   0   0   1   0   0   0   0   0
    V16  0  0  0  0  0  0  0  0  0   0   0   0   0   0   0   1   0   0   0   0
    V17  0  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   1   0   0   0
    V18  0  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   1   0   0
    V19  0  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   1   0
    V20  0  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   1
    attr(,"term.labels")
     [1] "V1"  "V2"  "V3"  "V4"  "V5"  "V6"  "V7"  "V8"  "V9"  "V10" "V11" "V12"
    [13] "V13" "V14" "V15" "V16" "V17" "V18" "V19" "V20"
    attr(,"order")
     [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
    attr(,"intercept")
    [1] 1
    attr(,"response")
    [1] 1
    attr(,".Environment")
    <environment: R_GlobalEnv>

1.4 Ajustamento de modelos

Ajuste o modelo definido em 1.3 a. e analise os resultados.

model1 <- lm(f1, data = db)

summary(model1)

Call:
lm(formula = f1, data = db)

Residuals:
    Min      1Q  Median      3Q     Max 
-147.04  -39.03   -4.17   38.20  152.40 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -363.899     68.142   -5.34  1.5e-07 ***
AGE           -0.121      0.220   -0.55    0.583    
BMI            6.004      0.721    8.32  1.1e-15 ***
BP             0.951      0.225    4.23  2.9e-05 ***
S1            -0.981      0.582   -1.68    0.093 .  
S2             0.658      0.539    1.22    0.223    
S3             0.514      0.794    0.65    0.518    
S4             4.660      6.037    0.77    0.441    
S5            68.947     15.927    4.33  1.9e-05 ***
S6             0.203      0.277    0.73    0.465    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 55 on 432 degrees of freedom
Multiple R-squared:  0.501, Adjusted R-squared:  0.49 
F-statistic: 48.1 on 9 and 432 DF,  p-value: <2e-16
par(mfrow = c(2, 2))
plot(model1)

par(mfrow = c(1, 1))

1.5 Treino e teste

  1. Comece por separar o conjunto de dados em dois, o conjunto de treino e o conjunto de teste. Este último deve incluir 20% das observações, sorteadas ao acaso mas de uma forma reprodutível.

    set.seed(2025)
    
    n <- nrow(db)
    indices <- sample(n, size = 0.2 * n)
    
    db.teste <- db[indices,]
    db.treino <- db[-indices,]
    
    # Alternativa com dplyr
    # db.teste <- slice_sample(db, prop = 0.2)
    # db.treino <- anti_join(db, db.teste)

    Nota: seria razoável investigar se há diferenças notórias entre os dois conjuntos.

    summary(db.treino)
    summary(db.teste)
  2. Use o modelo anterior para predizer o valor da variável resposta de cada observação no conjunto de teste. Avalie o poder preditivo do modelo usando a raíz do desvio quadrático médio (root mean square error) entre os valores preditos e observados da variável resposta.

    \[RMSE = \sqrt{\frac{\sum_{i=1}^n \left(y_i-\hat{y}_i\right)^2}{n}}\]

    observado <- db.teste$Y
    
    treino <- lm(f1, data = db.treino)
    pred <- predict(treino, db.teste)
    desv <- pred - observado
    
    summary(desv)
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    -126.24  -46.67    1.56   -4.16   38.72   95.14 
    rmse <- sqrt(mean(desv^2))
    rmse
    [1] 55.09
    res <- data.frame(Y = observado, Desvios = desv, Predições = pred)
    
    ggplot(res) +
        geom_abline(intercept = 0, slope = 1) +
        geom_point(aes(Y, Predições), color = "tomato") +
        coord_fixed() +
        theme_light()

    ggplot(res) +
        geom_hline(yintercept = 0) +
        geom_point(aes(Y, Desvios), color = "tomato") +
        theme_light()

    Comentário

    O modelo tem um fraco poder preditivo. Temos de fazer melhor!