A demência é uma condição complexa que afeta milhões de pessoas em todo o mundo. A compreensão das variáveis que influenciam o desenvolvimento da demência é crucial para a previsão e identificação de causas. Neste projeto, estou explorando técnicas de Data Mining para identificar variáveis importantes que podem ajudar a prever a demência em pacientes e relações significativas entre as mesmas para determinar impactos
O conjunto de dados utilizado neste estudo contém informações de pacientes que foram avaliados quanto a diversos fatores que podem estar relacionados ao desenvolvimento da demência.
Os dados foram consumidos do Oasis Open Access Series of Imaging Studies (OASIS).
Os dados, no entanto, foram encontrados no Kaggle em: Kaggle Dataset.
Este dataset é composto por 373 observações e inclui as seguintes variáveis principais:
| Variável | Descrição |
|---|---|
| Class | Classe do paciente (ex: demência ou não demência), que é o alvo de previsão. |
| Age | Idade do paciente em anos, um fator crítico para a avaliação de risco de demência. |
| Years of Education | Anos de educação formal do paciente, que pode impactar a cognição e o desenvolvimento da demência. |
| SES | Status socioeconômico do paciente, classificado em uma escala de 1 a 5. |
| Normalize Whole Brain Volume (nWBV) | Volume total do cérebro normalizado, um indicador importante da saúde cerebral. |
| Atlas Scaling Factor (ASF) | Fator de escalonamento do atlas, que pode influenciar medições cerebrais. |
| Gender (M.F) | Gênero do paciente (masculino ou feminino), que pode influenciar a prevalência de demência. |
Cada uma dessas variáveis desempenha um papel crucial na análise e pode fornecer insights valiosos sobre os fatores que influenciam o desenvolvimento da demência em pacientes.
Neste estudo, adotou-se uma abordagem de data mining utilizando Random Forests para identificar variáveis significativas relacionadas às previsões de demência. O objetivo é detectar variáveis que capturem os resíduos redutíveis, fornecendo insights valiosos para a compreensão do fenômeno. A hipótese central do trabalho investiga a relação entre a importância das variáveis identificadas e a compreensão da demência.
Para alcançar esses objetivos, os seguintes passos foram seguidos:
Através dessa estratégia, espera-se elucidar as relações complexas entre as variáveis e contribuir para uma melhor compreensão dos fatores que influenciam a demência.
Uma consideração importante neste estudo é o desbalanceamento dos dados. Dada a natureza dos dados, que apresenta um pequeno desbalanceamento entre as classes, a estratégia adotada consiste em atribuir pesos às classes desbalanceadas. Essa abordagem é recomendada em literatura acadêmica para situações em que o desbalanceamento é moderado, em vez de utilizar técnicas como SMOTE (Synthetic Minority Over-sampling Technique) ou undersampling, que podem não ser adequadas neste contexto
## Group M.F Age EDUC SES nWBV ASF
## 1 Nondemented M 87 14 2 0.696 0.883
## 2 Nondemented M 88 14 2 0.681 0.876
#Dados long_format, estamos com dados corretos
#Tirando grupo converted (não é nosso foco de estudo)
df = df[df$Group %in% c("Nondemented", "Demented"), ]
#Fatorando Grupos para melhor leitura de Random Forest
df$Group <- as.factor(df$Group)
levels(df$Group)## [1] "Demented" "Nondemented"
## Group M.F Age EDUC
## Demented :146 Length:336 Min. :60.00 Min. : 6.0
## Nondemented:190 Class :character 1st Qu.:71.00 1st Qu.:12.0
## Mode :character Median :76.00 Median :14.0
## Mean :76.71 Mean :14.5
## 3rd Qu.:82.00 3rd Qu.:16.0
## Max. :98.00 Max. :23.0
##
## SES nWBV ASF
## Min. :1.000 Min. :0.6440 Min. :0.876
## 1st Qu.:2.000 1st Qu.:0.7007 1st Qu.:1.097
## Median :2.000 Median :0.7310 Median :1.190
## Mean :2.546 Mean :0.7302 Mean :1.194
## 3rd Qu.:3.000 3rd Qu.:0.7560 3rd Qu.:1.293
## Max. :5.000 Max. :0.8370 Max. :1.587
## NA's :19
#NA's
df$SES <- ifelse(is.na(df$SES) & df$Group == "Demented", 3,
ifelse(is.na(df$SES) & df$Group == "Nondemented", 2, df$SES))
####Análise Univariada####
plot1 <- flexplot(nWBV ~ 1, data = df)+theme_cowplot()
plot2 <- flexplot(M.F ~ 1, data = df)+theme_cowplot()
plot3 <- flexplot(Age ~ 1, data = df)+theme_cowplot()
plot4 <- flexplot(EDUC ~ 1, data = df)+theme_cowplot()
plot5 <- flexplot(SES ~ 1, data = df)+theme_cowplot()
plot_grid(plot1, plot2, plot3, plot4, plot5, ncol = 2)####Análises Multivariadas####
plot6 <- flexplot(nWBV ~ Group, data =df)+
labs(title = 'Distribuição do volume cerebral por Grupo')+theme_cowplot()
plot7 <- flexplot(Age ~ Group, data = df)+theme_cowplot()
plot8 <- flexplot(EDUC ~ Group | M.F, data = df)+theme_cowplot()
plot9 <- flexplot(nWBV ~ Age + Group, data =df, method='lm')+labs(title = 'Volume Cerebral ao passar dos anos',
subtitle = 'Parece haver uma correlação negativa mais forte para\n Não Dementes')+theme_cowplot()
plot_grid(plot6, plot7, plot8, plot9, ncol = 2)## # A tibble: 2 × 2
## Group contagem
## <fct> <int>
## 1 Demented 146
## 2 Nondemented 190
## [1] 1.30137
As análises univariadas realizadas neste estudo proporcionaram algumas observações importantes sobre o conjunto de dados. A seguir, são destacados os principais achados:
As análises multivariadas realizadas neste estudo revelaram alguns pontos de atenção relevantes para a compreensão dos fatores associados à demência. A seguir, são apresentados os principais achados:
A Floresta Aleatória é uma técnica poderosa de aprendizado de máquina que se baseia em métodos de bagging (amostragem bootstrap). Este método envolve a construção de diversas árvores de decisão usando preditores e registros aleatórios
O algoritmo de Random Forest opera de acordo com os seguintes passos:
Para realizar a previsão, utiliza-se a moda das previsões das árvores (no caso de classificação) ou a média dos erros quadráticos médios (RMSE) das árvores (no caso de regressão)
As Florestas Aleatórias são particularmente úteis, pois apresentam:
Resistência ao Overfitting: Devido à sua capacidade heurística e à redução do ruído, essas árvores são menos propensas ao sobreajuste
Análise de Importância das Variáveis: Como destacado em Estatística Prática por Peter Bruce e Andrew Bruce, as florestas aleatórias possuem a habilidade de determinar automaticamente quais preditores são importantes e descobrir relacionamentos complexos entre eles (Bruce, P. & Bruce, A., 2017).
Alguns hiperparâmetros são críticos para otimizar o desempenho do modelo de Random Forest. Segundo o artigo Hyperparameters and Tuning Strategies for Random Forest de Philipp Probst, Marvin Wright e Anne-Laure Boulesteix (2019), os seguintes pontos são importantes:
A compreensão e o ajuste desses hiperparâmetros são fundamentais para maximizar a performance do modelo de Random Forest e garantir resultados eficazes em tarefas de predição e análise de dados.
| Hyperparameter | Description | Typical Default Values |
|---|---|---|
| mtry | Number of drawn candidate variables in each split | √p, p/3 for regression |
| sample size | Number of observations that are drawn for each tree | n |
| replacement | Draw observations with or without replacement | TRUE (with replacement) |
| node size | Minimum number of observations in a terminal node | 1 for classification, 5 for regression |
| number of trees | Number of trees in the forest | 500, 1000 |
| splitting rule | Splitting criteria in the nodes | Gini impurity, p-value, random |
Para a análise deste estudo, a abordagem proposta envolve a aplicação do algoritmo Random Forest, seguindo as etapas abaixo:
Seleção de Preditores: Inicialmente, aplicaremos uma Random Forest utilizando todos os preditores disponíveis para identificar as quatro variáveis mais importantes.
Otimização de Hiperparâmetros: Após a seleção
inicial, realizaremos ajustes nos hiperparâmetros, começando pelo
parâmetro mtry. Utilizaremos a validação cruzada k-fold
para comparar o erro Out-Of-Bag (OOB) entre os conjuntos de treino e
teste, buscando identificar o valor que minimiza os erros sem apresentar
grandes variações.
Ajuste do Tamanho do Nó: Em seguida, iremos
determinar um valor adequado para o node size, também por
meio de validação cruzada k-fold. O foco será encontrar um valor que
reduza principalmente os falsos positivos, visto que nosso estudo busca
aprimorar a previsão de demência.
Determinação do Número de Árvores: Utilizaremos o erro OOB para identificar a quantidade ideal de árvores a serem incluídas no modelo. Com isso, poderemos criar um modelo final, que será utilizado para avaliar as variáveis mais importantes em relação à demência.
Avaliação do Modelo: Para estabelecer uma margem de confiança, realizaremos a avaliação do modelo em um conjunto de dados separado, utilizando a matriz de confusão, além de métricas como recall, precisão e AUC (Área Sob a Curva) para mensurar a qualidade do algoritmo desenvolvido.
A meta é garantir que o modelo não capture ruído, apresentando, assim, uma boa capacidade de generalização tanto em dados de treino quanto em dados de teste.
#Random Forest para Data Minning
rf <- randomForest(Group ~ ., data = df,
importance = TRUE,
classwt = c("Demented" = 1.30, "Nondemented" = 1)
)
#Primeiro iniciamos uma árvore default para capturar váriáveis que por relevânica
#enviesam a árvore
importance(rf)## Demented Nondemented MeanDecreaseAccuracy MeanDecreaseGini
## M.F 21.90538 23.95016 30.70302 10.44251
## Age 16.40750 20.14685 26.01306 27.64481
## EDUC 30.05843 28.45831 40.05451 24.41765
## SES 19.20951 23.12670 29.56808 14.75985
## nWBV 31.50208 38.25146 45.92296 43.39856
## ASF 25.74422 27.88980 38.31485 39.26315
##
## Call:
## randomForest(formula = Group ~ ., data = df, importance = TRUE, classwt = c(Demented = 1.3, Nondemented = 1))
## Type of random forest: classification
## Number of trees: 500
## No. of variables tried at each split: 2
##
## OOB estimate of error rate: 13.1%
## Confusion matrix:
## Demented Nondemented class.error
## Demented 123 23 0.1575342
## Nondemented 21 169 0.1105263
#As variáveis nWBV, EDUC, ASF e M.F são as mais relevantes.
#Agora, vamos construir um novo modelo de Random Forest com a 4 variáveis
#mais importantes e melhorar a qualidade preditiva generalizada
####### MTRY #######
resultados <- data.frame(mtry = integer(), oob_error = double(),
test_error = double())
for (mtry in 1:4) {
oob_errors <- double(4)
test_errors <- double(4)
for (i in 1:10) {
set.seed(i) # para reprodutibilidade
fold_indices <- sample(rep(1:10, length.out = nrow(df)))
treino <- df[fold_indices != i, ]
teste <- df[fold_indices == i, ]
rf <- randomForest(Group ~ nWBV + EDUC + ASF + M.F,
data = treino, mtry = mtry,
classwt = c("Demented" = 1.3, "Nondemented" = 1))
oob_errors[i] <- rf$err.rate[nrow(rf$err.rate), "OOB"]
pred <- predict(rf, teste)
test_errors[i] <- mean(pred != teste$Group)
}
mean_oob_error <- mean(oob_errors)
mean_test_error <- mean(test_errors)
resultados <- rbind(resultados, data.frame(mtry = mtry,
oob_error = mean_oob_error,
test_error = mean_test_error))
}
print(resultados)## mtry oob_error test_error
## 1 1 0.2394116 0.2294118
## 2 2 0.1779228 0.1874332
## 3 3 0.1818886 0.1785205
## 4 4 0.1855223 0.1875223
ggplot(resultados, aes(x = mtry)) +
geom_line(aes(y = oob_error, color = "Erro OOB"), size = 1) +
geom_line(aes(y = test_error, color = "Erro de Teste"), size = 1) +
geom_point(aes(y = oob_error, color = "Erro OOB"), size = 3) +
geom_point(aes(y = test_error, color = "Erro de Teste"), size = 3) +
labs(title = "Comparação entre Erro OOB e Erro de Teste",
x = "Valores de mtry",
y = "Taxa de Erro",
color = "Tipo de Erro") +
theme_minimal() +
scale_color_manual(values = c("Erro OOB" = "steelblue", "Erro de Teste" = "tomato")) +
theme(plot.title = element_text(hjust = 0.5))##### Nodesize #####
k_folds <- 10
nodesizes <- 1:10
resultados_node <- data.frame(nodesize = integer(),
treino_oob_error = double(),
teste_oob_error = double())
for (nodesize in nodesizes) {
treino_oob_errors <- double(k_folds)
teste_oob_errors <- double(k_folds)
folds <- sample(1:k_folds, nrow(df), replace = TRUE)
for (i in 1:k_folds) {
treino <- df[folds != i, ]
teste <- df[folds == i, ]
rf_model <- randomForest(Group ~ nWBV + EDUC + ASF + M.F,
data = treino,
nodesize = nodesize, importance = TRUE,
mtry = 3, classwt = c("Demented" = 1.3, "Nondemented" = 1))
treino_oob_errors[i] <- rf_model$err.rate[nrow(rf_model$err.rate), "OOB"]
predicoes_teste <- predict(rf_model, teste)
teste_oob_errors[i] <- mean(predicoes_teste != teste$Group)
}
treino_oob_mean <- mean(treino_oob_errors)
teste_oob_mean <- mean(teste_oob_errors)
resultados_node <- rbind(resultados_node,
data.frame(nodesize = nodesize,
treino_oob_error = treino_oob_mean, teste_oob_error = teste_oob_mean))
}
ggplot(resultados_node, aes(x = nodesize)) +
geom_line(aes(y = treino_oob_error, color = "Erro OOB de Treino"), size = 1) +
geom_line(aes(y = teste_oob_error, color = "Erro OOB de Teste"), size = 1) +
geom_point(aes(y = treino_oob_error, color = "Erro OOB de Treino"), size = 3) +
geom_point(aes(y = teste_oob_error, color = "Erro OOB de Teste"), size = 3) +
labs(title = "Comparação entre Erro OOB de Treino e Erro OOB de Teste",
x = "Tamanho do Nó (nodesize)",
y = "Taxa de Erro",
color = "Tipo de Erro") +
theme_minimal() +
scale_color_manual(values = c("Erro OOB de Treino" = "steelblue", "Erro OOB de Teste" = "tomato")) +
theme(plot.title = element_text(hjust = 0.5))#### Quantidade de Árvores ####
modelo_1 = randomForest(Group ~ nWBV + EDUC + ASF + M.F, importance=TRUE, nodesize = 2,
mtry = 3, data=df, classwt = c("Demented" = 1.3, "Nondemented" = 1))
error_df = data.frame(error_rate = modelo_1$err.rate[, 'OOB'],
num_tress = 1:modelo_1$ntree)
ggplot(error_df, aes(x = num_tress, y = error_rate)) +
geom_line(color = "steelblue", size = 1.2) +
geom_point(color = "tomato", size = 0.75) +
labs(
title = "Taxa de Erro em Função do Número de Árvores",
x = "Número de Árvores",
y = "Taxa de Erro"
) +
theme_classic() +
theme(
plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
axis.title.x = element_text(size = 12, face = "bold"),
axis.title.y = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 10)
)## [1] 484
#### Modelo final ####
modelo_final = randomForest(Group ~ nWBV + EDUC + ASF + M.F,
importance=TRUE, nodesize = 2,
mtry = 3, data=df,ntrees = 484,
classwt = c("Demented" = 1.3, "Nondemented" = 1))
#### Avaliação do Modelo ####
indices <- sample(1:nrow(df), size = 0.8 * nrow(df))
treino <- df[indices, ]
teste <- df[-indices, ]
# Treinando o modelo com os dados de treinamento
rf_model <- randomForest(Group ~ nWBV + EDUC + ASF + M.F,
importance=TRUE, nodesize = 2,
mtry = 3, data=treino,ntrees = 484,
classwt = c("Demented" = 1.3, "Nondemented" = 1))
print(modelo_final)##
## Call:
## randomForest(formula = Group ~ nWBV + EDUC + ASF + M.F, data = df, importance = TRUE, nodesize = 2, mtry = 3, ntrees = 484, classwt = c(Demented = 1.3, Nondemented = 1))
## Type of random forest: classification
## Number of trees: 500
## No. of variables tried at each split: 3
##
## OOB estimate of error rate: 18.15%
## Confusion matrix:
## Demented Nondemented class.error
## Demented 118 28 0.1917808
## Nondemented 33 157 0.1736842
#Taxa de erro de 18.01%
#Erros de classe balanceados
### Precisão vs Recall vs ROC/AUC ###
predicoes_teste <- predict(rf_model, teste)
probabilidades_teste <- predict(rf_model, teste, type = "prob")[,2]
matriz_confusao_teste <- table(Predito = predicoes_teste, Real = teste$Group)
print(matriz_confusao_teste)## Real
## Predito Demented Nondemented
## Demented 29 2
## Nondemented 6 31
precisao_teste <- sum(predicoes_teste == "Demented" & teste$Group == "Demented") / sum(predicoes_teste == "Demented")
recall_teste <- sum(predicoes_teste == "Demented" & teste$Group == "Demented") / sum(teste$Group == "Demented")
cat("Precisão (teste):", precisao_teste, "\n")## Precisão (teste): 0.9354839
## Recall (teste): 0.8285714
roc_curve_teste <- roc(teste$Group, probabilidades_teste, levels = c("Nondemented", "Demented"), direction = ">")
plot(roc_curve_teste, col = "blue", lwd = 2, main = "Curva ROC - Conjunto de Teste")## AUC (teste): 0.9714286
Primeiramente, as decisões de hiperparâmetros foram orientadas pelas seguintes observações:
mtry foi definido como 3,
dado que apresentou o menor erro no conjunto de teste.node size foi ajustado para
2, o que resultou em uma melhoria expressiva no
erro.O modelo final alcançou uma acurácia de aproximadamente 18%, o que, ao contrário do esperado, demonstrou uma capacidade de distinguir entre casos de demência e não demência de forma consistente, especialmente nos dados de treino. Durante o treinamento com a amostra OOB, o modelo apresentou erros proporcionais, indicando uma boa capacidade de classificação entre ambas as classes (demência e não demência)
Nos dados de treino, o modelo também mostrou alta precisão e um bom recall, fatores importantes para nosso estudo, além de uma AUC que reflete um ajuste satisfatório do modelo
Em conclusão, o algoritmo se mostra eficaz para previsões e pode ser aprimorado com mais dados de treinamento e ajustes de thresholds, dependendo do foco desejado (por exemplo, maior precisão). A partir disso, é possível confiar com razoável segurança nas duas variáveis mais importantes identificadas pelo modelo, aplicando-as para insights e previsões futuras
## Demented Nondemented MeanDecreaseAccuracy MeanDecreaseGini
## nWBV 33.44698 37.87868 48.99775 54.66721
## EDUC 45.62709 30.27025 50.79612 33.27878
## ASF 36.20329 34.69626 49.31092 61.20963
## M.F 18.72153 23.46936 28.65333 10.22689
#variáveis importantes ASF e EDUC e nWBV
varImpPlot(modelo_final, type=1, col='black', las=1, bty='n', cex=1, pch=19,
main = "Importância na acurácia")varImpPlot(modelo_final, type=2, col='black', las=1, bty='n', cex=1, pch=19,
main = "Importância na Pureza")##
## Call:
## randomForest(formula = Group ~ nWBV + EDUC + ASF + M.F, data = df, importance = TRUE, nodesize = 2, mtry = 3, ntrees = 484, classwt = c(Demented = 1.3, Nondemented = 1))
## Type of random forest: classification
## Number of trees: 500
## No. of variables tried at each split: 3
##
## OOB estimate of error rate: 18.15%
## Confusion matrix:
## Demented Nondemented class.error
## Demented 118 28 0.1917808
## Nondemented 33 157 0.1736842
Diante do contexto da análise, inicialmente consideramos a aplicação de regressão logística para investigar o impacto das variáveis de interesse, ASF (Atlas Scaling Factor) e EDUC (anos de educação), sobre o risco de demência. A regressão logística permitiria o cálculo de odds ratios, fornecendo insights diretos sobre a relação entre alterações nessas variáveis e o desfecho de demência. No entanto, ao analisarmos as distribuições de ASF entre pacientes com e sem demência, notamos uma considerável sobreposição. Essa sobreposição indica que uma regressão logística pode não ser capaz de capturar as nuances da relação entre essas variáveis e o desfecho desejado
Após uma análise mais aprofundada, optei por selecionar nWBV (Normalized White Matter Volume) como uma das variáveis preditoras, uma vez que demonstrou um desempenho superior na previsão de pacientes não dementes. Por outro lado, EDUC se destacou na previsão de pacientes com demência. Embora ASF e nWBV apresentem resultados bastante semelhantes em termos de divisões e acurácia, o nWBV provou ser mais eficaz na previsão de casos não dementes. Assim, a escolha final de variáveis preditoras para o modelo será EDUC e nWBV
Para lidar com a complexidade observada, optamos pelo uso de árvores de decisão, que são altamente interpretáveis e permitem uma análise mais flexível das interações entre as variáveis. Árvores de decisão oferecem a vantagem de divisões sequenciais baseadas em critérios de pureza, o que nos ajuda a identificar padrões mais detalhados e interações complexas entre nWBV, EDUC e demência
Para evitar overfitting, faremos uma poda da árvore de decisão, identificando o valor ideal de cp (complexity parameter) através de validação cruzada. Esse processo permite controlar o tamanho da árvore, reduzindo a variância e melhorando a capacidade de generalização do modelo
Uma árvore de decisão utiliza um processo de decisão a partir de um nó raiz com a maior pureza possível. Ela desce progressivamente aos nós filhos, onde cada decisão é uma sequência de condições “if-then-else”. Essas divisões são realizadas por um processo de repartição recursiva, conforme descrito a seguir:
As funções de impureza mais comuns para medir a homogeneidade das partições são:
A Impureza de Gini mede a probabilidade de que um item selecionado aleatoriamente seja classificado incorretamente se for rotulado aleatoriamente, com base na distribuição das classes na partição. A fórmula é dada por:
\[ I(A) = 1 - \sum_{i=1}^{k} p_i^2 \]
onde \(p_i\) representa a proporção de elementos da classe \(i\) na partição \(A\). A impureza de Gini varia de 0 (impureza mínima, ou seja, todos os elementos pertencem à mesma classe) até um valor máximo que ocorre quando as classes estão perfeitamente distribuídas.
A Entropia mede o nível de desordem ou incerteza em uma partição. Quanto mais homogênea a partição, menor a entropia. A fórmula para a entropia é:
\[ I(A) = - \sum_{i=1}^{k} p_i \log_2(p_i) \]
onde \(p_i\) é a proporção de elementos da classe \(i\) na partição \(A\). A entropia é máxima quando todas as classes estão equilibradas (com \(p_i = \frac{1}{k}\) para todos os \(i\)) e é zero quando todos os elementos pertencem a uma única classe.
Suponha que temos uma partição com duas classes: Classe A e Classe B. Considere a seguinte distribuição:
Podemos calcular a Impureza de Gini e a Entropia dessa partição.
Primeiro, calculamos as proporções para cada classe:
A Impureza de Gini é calculada como:
\[ I_{\text{Gini}} = 1 - (p_{\text{Classe A}}^2 + p_{\text{Classe B}}^2) \]
Substituindo os valores:
\[ I_{\text{Gini}} = 1 - (0.3^2 + 0.7^2) = 1 - (0.09 + 0.49) = 1 - 0.58 = 0.42 \]
A Entropia é calculada como:
\[ I_{\text{Entropia}} = - \left( p_{\text{Classe A}} \log_2(p_{\text{Classe A}}) + p_{\text{Classe B}} \log_2(p_{\text{Classe B}}) \right) \]
Substituindo os valores:
\[ I_{\text{Entropia}} = - \left( 0.3 \cdot \log_2(0.3) + 0.7 \cdot \log_2(0.7) \right) \]
Calculando cada termo:
Assim, temos:
\[ I_{\text{Entropia}} \approx - (-0.521 - 0.361) = 0.882 \]
Esses valores indicam que a partição é parcialmente homogênea, pois ambos os valores de impureza não são zero. Quanto menores esses valores, mais homogênea será a partição.
Uma desvantagem das árvores de decisão é seu caráter “greedy”, ou seja, elas tendem a otimizar localmente em vez de globalmente. Além disso, árvores de decisão não podadas são propensas ao overfitting e apresentam limitações para extrapolações, especialmente em contextos com dataset drift.
Para garantir uma árvore otimizada para nosso foco em demência, utilizaremos a validação cruzada para selecionar o parâmetro de complexidade (cp) que minimize falsos negativos, garantindo que o modelo seja preciso na identificação de casos de demência. Após podar a árvore, avaliaremos a relação de ASF e EDUC com demência, utilizando a árvore final para obter insights sobre a importância e a influência dessas variáveis em nossa análise
#foco é determinar um cp (poda) que desenvolva um ávore com o minimo de #falsos positivos possíveis
#já que queremos avaliar como as variáveis de relacionam com Demência com
#mais assertividade
k <- 5
cp_values <- seq(0.05, 0.1, by = 0.01)
fn_results <- data.frame(cp = numeric(), mean_fn = numeric())
# Loop para testar cada valor de cp
for (cp in cp_values) {
# Função para calcular o número de falsos negativos em cada fold
false_negative_fold <- function(train_indices, test_indices) {
train_data <- df[train_indices, ]
test_data <- df[test_indices, ]
tree_model <- rpart(Group ~ nWBV + EDUC, data = train_data, method = "class", control = rpart.control(cp = cp),
weights = train_data$weights)
predictions <- predict(tree_model, test_data, type = "class")
# Calculando os falsos negativos
confusion <- table(test_data$Group, predictions)
fn <- if ("Demented" %in% rownames(confusion) & "Nondemented" %in% colnames(confusion)) {
confusion["Demented", "Nondemented"]
} else {
0
}
return(fn)
}
folds <- createFolds(df$Group, k = k, list = TRUE, returnTrain = TRUE)
fn_list <- sapply(folds, function(fold) false_negative_fold(fold, setdiff(1:nrow(df), fold)))
mean_fn <- mean(fn_list)
fn_results <- rbind(fn_results, data.frame(cp = cp, mean_fn = mean_fn))
}
best_cp <- fn_results[which.min(fn_results$mean_fn), "cp"]
cat("Melhor valor de cp:", best_cp, "\n")## Melhor valor de cp: 0.05
### Árvore Final ###
final_tree <- rpart(Group ~ nWBV + EDUC, data = df,
weights = df$weights)
##Podando Árvore##
pruned_tree <- prune(final_tree, cp = 0.05)
rpart.plot(
pruned_tree,
type = 3,
extra = 104,
box.palette = "Blues",
shadow.col = "gray",
fallen.leaves = TRUE,
cex = 0.8,
main = "Árvore de Decisão e probabilidades de Demência"
)## Call:
## rpart(formula = Group ~ nWBV + EDUC, data = df, weights = df$weights)
## n= 336
##
## CP nsplit rel error xerror xstd
## 1 0.2191781 0 1.0000000 1.0000000 0.06223443
## 2 0.1643836 1 0.7808219 0.7808219 0.05944378
## 3 0.0500000 2 0.6164384 0.6164384 0.05559891
##
## Variable importance
## nWBV EDUC
## 53 47
##
## Node number 1: 336 observations, complexity param=0.2191781
## predicted class=Nondemented expected loss=0.4345238 P(node) =1
## class counts: 146 190
## probabilities: 0.435 0.565
## left son=2 (178 obs) right son=3 (158 obs)
## Primary splits:
## nWBV < 0.7335 to the left, improve=18.27393, (0 missing)
## EDUC < 12.5 to the left, improve=10.65985, (0 missing)
## Surrogate splits:
## EDUC < 17.5 to the left, agree=0.542, adj=0.025, (0 split)
##
## Node number 2: 178 observations, complexity param=0.1643836
## predicted class=Demented expected loss=0.4101124 P(node) =0.5297619
## class counts: 105 73
## probabilities: 0.590 0.410
## left son=4 (138 obs) right son=5 (40 obs)
## Primary splits:
## EDUC < 16.5 to the left, improve=15.685910, (0 missing)
## nWBV < 0.7145 to the left, improve= 1.559516, (0 missing)
##
## Node number 3: 158 observations
## predicted class=Nondemented expected loss=0.2594937 P(node) =0.4702381
## class counts: 41 117
## probabilities: 0.259 0.741
##
## Node number 4: 138 observations
## predicted class=Demented expected loss=0.2971014 P(node) =0.4107143
## class counts: 97 41
## probabilities: 0.703 0.297
##
## Node number 5: 40 observations
## predicted class=Nondemented expected loss=0.2 P(node) =0.1190476
## class counts: 8 32
## probabilities: 0.200 0.800
#### Curva AUC ####
predictions_prob <- predict(pruned_tree, df, type = "prob")[, "Demented"]
roc_curve <- roc(df$Group, predictions_prob,
levels = c("Nondemented", "Demented"),
direction = "<")
plot(roc_curve, main = "Curva ROC", col = "blue", lwd = 2)## AUC: 0.7310743
### Resultados
p <- flexplot(nWBV ~ EDUC + Group, data = df, method = 'quadratic')+
labs(
title = 'Decision Tree',
x = 'Years of Education',
y = 'Brain Volume (nWBV)'
) + theme_classic()
p +
geom_hline(yintercept = 0.73, color = "black",
linetype = "dashed") +
geom_segment(aes(x = 17, xend = 17, y = min(nWBV), yend = 0.73),
color = "black", linetype = "dashed")+
annotate("label", x = 10, y = 0.8, label = "Probabilidade de\n 74% de Nao demente",
color = "steelblue", fill = "lightgray", size = 2.5, hjust = 0) +
annotate("label", x = 7, y = 0.67, label = "Probabilidade de\n 75% de Demencia",
color = "#F8766D", fill = "lightgray", size = 2.5, hjust = 0) Podemos observar que, ao realizar a previsão, obtivemos um AUC de 0.73, indicando uma capacidade moderada de previsão. Embora esse valor não seja excepcional, é suficientemente alto para sugerir que indivíduos com nWBV inferior a 0.73 e EDUC abaixo de 17 apresentam uma probabilidade de 75% de desenvolver demência. Esse resultado não é desanimador, considerando que um AUC de 0.73 demonstra um poder preditivo razoável
Essa abordagem faz sentido, pois volumes cerebrais reduzidos, combinados a níveis educacionais baixos, podem afetar significativamente a capacidade cognitiva e levar ao deterioramento cerebral, aumentando o risco de demência nos pacientes. Para aqueles com um volume cerebral acima de 0.73, a probabilidade de desenvolver demência pode ser influenciada por uma gama de outras variáveis, sugerindo que a relação entre os preditores e o desfecho é multifacetada
Também podemos notar uma relação não linear negativa entre nWBV e EDUC em não dementes e uma relação levemente positiva de nWBV com EDUC, isso pode indicar que paciente com demência e mais anos de educação possuem suas variâncias explicadas por uma outra variável não considerada
Análises Multivariadas:
Identificou-se que o volume cerebral e a educação são fatores significativos na predição da demência
O volume cerebral apresentou uma distribuição normal, mas sua capacidade preditiva foi limitada.
A relação entre idade e demência não é linear após os 60 anos, e a baixa escolaridade está associada a um maior risco de demência
Escolha do Modelo:
Optou-se por árvores de decisão em vez de regressão logística, devido à capacidade interpretativa e à análise de relações complexas entre variáveis
As distribuições de ASF (Atlas Scaling Factor) e EDUC apresentavam sobreposição, tornando a árvore uma escolha mais adequada
Configurações do Modelo:
Parâmetro mtry definido em 3 para otimizar a previsão
Node size ajustado para 2 a fim de reduzir falsos positivos
Quantidade de árvores fixada em 484 para minimizar o erro OOB
Resultados:
O modelo final apresentou uma acurácia de aproximadamente 18% e um AUC de 0.73, indicando uma capacidade moderada de previsão
Variáveis nWBV e EDUC emergiram como preditoras relevantes
Indivíduos com volumes cerebrais abaixo de 0.73 e níveis educacionais inferiores a 17 apresentavam uma probabilidade de 75% de desenvolver demência
Em resumo, as decisões tomadas, fundamentadas em análises estatísticas e na escolha de modelos apropriados, permitiram identificar variáveis-chave e obter insights significativos sobre a predição de demência. Apesar das limitações, os resultados fornecem uma base sólida para futuras investigações e intervenções focadas na prevenção da demência
Zhang, Y., & Huang, R. (2020). “A Study of the Effect of Education on Dementia Risk.” Journal of Alzheimer’s Disease, 78(2), 345-356.
Smith, M. A., & McCarthy, J. (2018). “Cerebral Volume and its Impact on Cognitive Function in Aging.” Neuropsychology Review, 28(3), 293-309.