Analise amostral de despesas médicas de 2018 para um conjunto de pacientes espalhados nas regiÔes Sudeste, Sul, Nordeste e Norte do Brasil. Criacao de um modelo preditivo para a variåvel de despesas médicas para cada cluster do dataset.
O dataset possui o total de 1.338 observaçoes e 7 variåveis.
librarys <- c("tidyverse","corrplot","plotly","gridExtra","caTools")
lapply(librarys, require, character.only = TRUE)
## Loading required package: tidyverse
## ââ Attaching packages ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ tidyverse 1.3.0 ââ
## â ggplot2 3.3.2 â purrr 0.3.4
## â tibble 3.0.1 â dplyr 1.0.0
## â tidyr 1.1.0 â stringr 1.4.0
## â readr 1.3.1 â forcats 0.5.0
## ââ Conflicts âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ tidyverse_conflicts() ââ
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
## Loading required package: corrplot
## corrplot 0.84 loaded
## Loading required package: plotly
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
## Loading required package: gridExtra
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
## Loading required package: caTools
## [[1]]
## [1] TRUE
##
## [[2]]
## [1] TRUE
##
## [[3]]
## [1] TRUE
##
## [[4]]
## [1] TRUE
##
## [[5]]
## [1] TRUE
setwd("/home/sandro/BACKUP/Documents/projetos/prevendo_despesas_hospitalares")
getwd()
## [1] "/media/sandro/c4b35573-c8d2-4564-aa96-97bede91e199/BACKUP/Documents/projetos/prevendo_despesas_hospitalares"
df <- df <- read.csv("dataset.csv")
glimpse(df)
## Rows: 1,338
## Columns: 8
## $ X <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18âŠ
## $ idade <int> 19, 18, 28, 33, 32, 31, 46, 37, 37, 60, 25, 62, 23, 56, 27, 1âŠ
## $ sexo <int> 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0âŠ
## $ bmi <dbl> 27.9, 33.8, 33.0, 22.7, 28.9, 25.7, 33.4, 27.7, 29.8, 25.8, 2âŠ
## $ filhos <int> 0, 1, 3, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0âŠ
## $ fumante <int> 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0âŠ
## $ regiao <int> 1, 2, 2, 3, 3, 2, 2, 3, 4, 3, 4, 2, 1, 2, 2, 1, 4, 4, 1, 1, 4âŠ
## $ gastos <dbl> 16884.92, 1725.55, 4449.46, 21984.47, 3866.86, 3756.62, 8240.âŠ
apply(df, 2, function(x) any(is.na(x)))
## X idade sexo bmi filhos fumante regiao gastos
## FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
Como não hå valores NA no dataset, seguiremos o processo de pré-processamento dos dados.
Vamos mudar algumas das variåveis numéricas para variåveis categóricas
df2 <- df %>%
mutate(sexo = ifelse(sexo == 1,'masculino','feminino')) %>%
mutate(fumante = ifelse(fumante == 1,"sim","nao")) %>%
mutate(regiao = ifelse(regiao == 1,"sudeste",
ifelse(regiao == 2,"sul",
ifelse(regiao == 3,"nordeste","norte")))) %>%
mutate_if(is.character,as.factor) %>%
mutate_if(is.factor, toupper) %>%
rename_with(toupper) %>%
select(-X);glimpse(df2);head(df2)
## Rows: 1,338
## Columns: 7
## $ IDADE <int> 19, 18, 28, 33, 32, 31, 46, 37, 37, 60, 25, 62, 23, 56, 27, 1âŠ
## $ SEXO <chr> "FEMININO", "MASCULINO", "MASCULINO", "MASCULINO", "MASCULINOâŠ
## $ BMI <dbl> 27.9, 33.8, 33.0, 22.7, 28.9, 25.7, 33.4, 27.7, 29.8, 25.8, 2âŠ
## $ FILHOS <int> 0, 1, 3, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0âŠ
## $ FUMANTE <chr> "SIM", "NAO", "NAO", "NAO", "NAO", "NAO", "NAO", "NAO", "NAO"âŠ
## $ REGIAO <chr> "SUDESTE", "SUL", "SUL", "NORDESTE", "NORDESTE", "SUL", "SUL"âŠ
## $ GASTOS <dbl> 16884.92, 1725.55, 4449.46, 21984.47, 3866.86, 3756.62, 8240.âŠ
## IDADE SEXO BMI FILHOS FUMANTE REGIAO GASTOS
## 1 19 FEMININO 27.9 0 SIM SUDESTE 16884.92
## 2 18 MASCULINO 33.8 1 NAO SUL 1725.55
## 3 28 MASCULINO 33.0 3 NAO SUL 4449.46
## 4 33 MASCULINO 22.7 0 NAO NORDESTE 21984.47
## 5 32 MASCULINO 28.9 0 NAO NORDESTE 3866.86
## 6 31 FEMININO 25.7 0 NAO SUL 3756.62
p1 <- ggplot(df2) +
aes(x = IDADE) +
geom_histogram(bins = 30L, fill = "lightblue", color = "white") +
labs(y = "FrequĂȘncia",
title = "Consumo de planos de saĂșde por faixa etĂĄria (Brasil)",
x = "Faixa EtĂĄria")+
theme_minimal()
p2 <- ggplot(df2) +
aes(x = IDADE,fill=REGIAO) +
geom_histogram(bins = 30L,color = "white") +
theme_minimal()+
theme(legend.title = element_blank(), legend.position = "none")+
xlab("Faixa EtĂĄria")+
ggtitle("Consumo de planos de saĂșde por faixa etĂĄria (RegiĂ”es)")+
ylab("FrequĂȘncia")+
labs(fill = "RegiĂŁo")+
facet_wrap(vars(REGIAO))
gridExtra::grid.arrange(p1,p2,ncol=1,nrow=2)
19~20 anos Ă© a faixa que mais consome planos de saĂșde, se analisarmos por regiĂŁo, essa premissa segue sendo verdade, com exceção da regiĂŁo norte e sul que possuem a faixa dos 20 anos anos quase nula. JĂĄ a faixa dos 60 +, ao contrĂĄrio do que se imaginava, nĂŁo se apresenta como a maior faixa consumidora de planos de saĂșde, este fato se dar muito provavelmente ao preço aplicado em planos de saĂșde para essa faixa.
df_idade <- df2 %>%
group_by(IDADE,REGIAO) %>%
summarise(GASTOS = sum(GASTOS));df_idade
## `summarise()` regrouping output by 'IDADE' (override with `.groups` argument)
## # A tibble: 185 x 3
## # Groups: IDADE [47]
## IDADE REGIAO GASTOS
## <int> <chr> <dbl>
## 1 18 NORTE 241879.
## 2 18 SUL 247070.
## 3 19 NORDESTE 322308.
## 4 19 SUDESTE 233839.
## 5 19 SUL 106711.
## 6 20 NORDESTE 78388.
## 7 20 NORTE 47259.
## 8 20 SUDESTE 87276.
## 9 20 SUL 81708.
## 10 21 NORDESTE 40814.
## # ⊠with 175 more rows
options(scipen = 999)
p3 <- ggplot(df_idade)+
geom_col(aes(x=IDADE,y=GASTOS),fill = "lightblue")+
theme_minimal()+
labs(x="Faixa EtĂĄria",
y="Despesas Médicas",
title = "Despesas Médicas por faixa etåria (Brasil)")
p4 <- ggplot(df_idade,aes(x=IDADE,y=GASTOS,fill = REGIAO))+
geom_col(color = "white")+
facet_wrap(vars(REGIAO))+
theme_minimal()+
theme(legend.title = element_blank(), legend.position = "none")+
labs(x="Faixa EtĂĄria",
y="Despesas Médicas",
title = "Despesas Médicas por faixa etåria (RegiÔes)")
gridExtra::grid.arrange(p3,p4,nrow=2,ncol=1)
Aqui, vemos que as despesas mĂ©dicas ficam mais equilibradas conforme aumenta a faixa etĂĄria. Ou seja, beneficiĂĄrios de idades mais avançadas tendem a ter maiores gastos com planos de saĂșde, embora essa relação nĂŁo pareça ser muito forte. Isso reforça nossa hipotese de que, conforme a idade avança os planos de saĂșde tendem a ser mais caros.
df_corr1 <- df2 %>%
group_by(IDADE,REGIAO) %>%
summarise(GASTOS = sum(GASTOS))
## `summarise()` regrouping output by 'IDADE' (override with `.groups` argument)
p5 <- ggplot(df_corr1,aes(x=IDADE,y=GASTOS))+
geom_point()+
theme_minimal()+
labs(y='Despesas Médicas',
x='Idade',
title='Anålise correlação - Despesas Médicas x Idade')+
geom_smooth()
p6 <- ggplot(df_corr1,aes(x=IDADE,y=GASTOS,fill=REGIAO))+
geom_point()+
theme_minimal()+
facet_wrap(vars(REGIAO))+
labs(y='Despesas Médicas',
x='Idade',
title='Anålise correlação - Despesas Médicas x Idade')+
theme(legend.title = element_blank(), legend.position = "none")+
geom_smooth()
df_corrn <- df_corr1 %>%
filter(REGIAO == 'NORDESTE') %>%
group_by(IDADE,REGIAO) %>%
summarise(GASTOS = sum(GASTOS))
## `summarise()` regrouping output by 'IDADE' (override with `.groups` argument)
df_corrs <- df_corr1 %>%
filter(REGIAO == 'SUL') %>%
group_by(IDADE,REGIAO) %>%
summarise(GASTOS = sum(GASTOS))
## `summarise()` regrouping output by 'IDADE' (override with `.groups` argument)
df_corrsu <- df_corr1 %>%
filter(REGIAO == 'SUDESTE') %>%
group_by(IDADE,REGIAO) %>%
summarise(GASTOS = sum(GASTOS))
## `summarise()` regrouping output by 'IDADE' (override with `.groups` argument)
df_corrno <- df_corr1 %>%
filter(REGIAO == 'NORTE') %>%
group_by(IDADE,REGIAO) %>%
summarise(GASTOS = sum(GASTOS))
## `summarise()` regrouping output by 'IDADE' (override with `.groups` argument)
gridExtra::grid.arrange(p5,p6,ncol=1,nrow=2)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Brasil:
## [1] 0.2547014
Nordeste:
## [1] 0.2587151
Norte:
## [1] 0.2367626
Sudeste:
## [1] 0.2274243
Sul:
## [1] 0.326145
Analisando mais a fundo a correlação que levantamos sobre as hipóteses dos plots anteriores, vemos que existe uma correlação positiva fraca entre a idade dos beneficiårios e as despesas médicas. Coeficiente de correlação (quanto mais próximo de 1 mais positiva forte é a relacao):
A relação mais forte é a da região Sul.
df_sexo <- df2 %>%
group_by(SEXO) %>%
summarise(GASTOS = sum(GASTOS))%>%
mutate(freq = round(GASTOS/sum(GASTOS)*100, digits =2))
## `summarise()` ungrouping output (override with `.groups` argument)
df_sexo2 <- df2 %>%
group_by(SEXO,REGIAO) %>%
summarise(GASTOS = sum(GASTOS))%>%
mutate(freq = round(GASTOS/sum(GASTOS)*100, digits =2))
## `summarise()` regrouping output by 'SEXO' (override with `.groups` argument)
p9 <- ggplot(df_sexo2,aes(REGIAO,freq, fill = SEXO))+
geom_bar(stat = "identity", position = "dodge")+
scale_fill_brewer(palette = "Set4")+
labs(x="Genero",
y="Frequencia relativa",
title="Despesas mĂ©dicas por gĂȘnero - RegiĂ”es (%)",
caption="fi de despesas mĂ©dicas por gĂȘnero, (f=F/n)")+
theme_minimal();print(p9)
## Warning in pal_name(palette, type): Unknown palette Set4
Os homens consomem 6,28% mais planos de saĂșdes que as mulheres.
TambĂ©m Ă© possĂver ver que, nĂŁo hĂĄ um gĂȘnero dominante se analisarmos por regiĂ”es, No sudeste e no Sul, sĂŁo os homens que mais consomem planos de saĂșde, e no nordeste e norte sĂŁo as mulheres. Para ambos os casos, a frequencia relativa por genero Ă© bem equilibrada.
p10 <- ggplot(df2,aes(x=SEXO,y=GASTOS, fill = SEXO))+
geom_boxplot()+
theme_minimal()+
theme(legend.title = element_blank(), legend.position = "none")+
labs(x="GĂȘnero",
y="Despesas médicas",
title = "Boxplot por gĂȘnero")
p11 <- ggplot(df2,aes(x=SEXO,y=GASTOS, fill = SEXO))+
geom_boxplot()+
theme_minimal()+
theme(legend.title = element_blank(), legend.position = "none")+
labs(x="GĂȘnero",
y="Despesas médicas",
title = "Boxplot por gĂȘnero e por regiĂŁo")+
facet_wrap(vars(REGIAO))
gridExtra::grid.arrange(p10,p11)
Analisando o boxplot por gĂȘnero, Ă© possĂvel afirmar que as medidas de tendĂȘncia central para os ambos os sexo, se equiparam, ou seja, nĂŁo hĂĄ uma distribuiçao dominante se analisarmos por sexo.
Homens gastam mais com planos mĂ©dicos que as mulheres, mas essa diferença nĂŁo infere dominĂąncia sobre o gĂȘnero feminino.
Aqui vamos analisar se as variåveis numéricas estão correlacionadas às despesas médicas. Primeiro, vamos dar uma olhada novamente em nossos dados e se, for o caso, modificar alguma variåvel para a nossa correlação
head(df2)
## IDADE SEXO BMI FILHOS FUMANTE REGIAO GASTOS
## 1 19 FEMININO 27.9 0 SIM SUDESTE 16884.92
## 2 18 MASCULINO 33.8 1 NAO SUL 1725.55
## 3 28 MASCULINO 33.0 3 NAO SUL 4449.46
## 4 33 MASCULINO 22.7 0 NAO NORDESTE 21984.47
## 5 32 MASCULINO 28.9 0 NAO NORDESTE 3866.86
## 6 31 FEMININO 25.7 0 NAO SUL 3756.62
Vamos isolar a variavel e verificar se o fato de o beneficiårio ser fumante, implica no valor gasto com despesas médicas.
df3 <- df2 %>%
mutate(FUMANTE = ifelse(FUMANTE == 'SIM',1,0))
Em seguida vamos correlacionar as variåveis afim de encontrar algum relacionamento, isso nos ajudarå na construção do modelo preditivo
num_vars <- sapply(df3,is.numeric)
corr <- cor(df3[num_vars])
corrplot(corr,method = "color")
plot(df3$FUMANTE,df3$GASTOS)
HĂĄ algumas observacoes interessantes a serem feitas aqui: Ă possivel notar uma correlacao forte entre as variĂĄveis FUMANTE e GASTOS; A idade, como jĂĄ vimos, tambĂ©m possui correlação, embora moderada, hĂĄ alguma significancia para a construção do nosso modelo preditivo. HĂĄ ainda correlçao positiva fraca entre FILHOS e GASTOS. Ou seja, a medida que BMI, e o numero de filhos aumenta o valor do plano de saĂșde tende a ser mais caro.
dados de teste e de treino
df3 <- df2 %>%
mutate(bmi30 = ifelse(BMI >=30,1,0)) %>%
mutate(IDADE2 =IDADE *2);head(df3)
## IDADE SEXO BMI FILHOS FUMANTE REGIAO GASTOS bmi30 IDADE2
## 1 19 FEMININO 27.9 0 SIM SUDESTE 16884.92 0 38
## 2 18 MASCULINO 33.8 1 NAO SUL 1725.55 1 36
## 3 28 MASCULINO 33.0 3 NAO SUL 4449.46 1 56
## 4 33 MASCULINO 22.7 0 NAO NORDESTE 21984.47 0 66
## 5 32 MASCULINO 28.9 0 NAO NORDESTE 3866.86 0 64
## 6 31 FEMININO 25.7 0 NAO SUL 3756.62 0 62
sample <- sample.split(df2$IDADE, SplitRatio = 0.7)
treino <- subset(df3,sample == TRUE)
teste <- subset(df3, sample == FALSE)
modelo1 <- lm(GASTOS~.,treino);summary(modelo1)
##
## Call:
## lm(formula = GASTOS ~ ., data = treino)
##
## Residuals:
## Min 1Q Median 3Q Max
## -12616.4 -3462.0 -21.5 1613.0 25158.6
##
## Coefficients: (1 not defined because of singularities)
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -8126.08 1486.86 -5.465 0.0000000594 ***
## IDADE 249.71 13.65 18.291 < 0.0000000000000002 ***
## SEXOMASCULINO -250.34 379.54 -0.660 0.50969
## BMI 151.25 54.09 2.796 0.00528 **
## FILHOS 435.35 156.66 2.779 0.00556 **
## FUMANTESIM 24402.66 473.75 51.509 < 0.0000000000000002 ***
## REGIAONORTE 576.17 539.19 1.069 0.28553
## REGIAOSUDESTE -95.27 542.57 -0.176 0.86065
## REGIAOSUL 351.18 551.27 0.637 0.52425
## bmi30 2930.81 622.24 4.710 0.0000028529 ***
## IDADE2 NA NA NA NA
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 5797 on 931 degrees of freedom
## Multiple R-squared: 0.7783, Adjusted R-squared: 0.7761
## F-statistic: 363.1 on 9 and 931 DF, p-value: < 0.00000000000000022
modelo2 <- lm(GASTOS~IDADE+IDADE2+SEXO+FILHOS+REGIAO+bmi30*FUMANTE,treino);summary(modelo2)
##
## Call:
## lm(formula = GASTOS ~ IDADE + IDADE2 + SEXO + FILHOS + REGIAO +
## bmi30 * FUMANTE, data = treino)
##
## Residuals:
## Min 1Q Median 3Q Max
## -4587.4 -1764.0 -1252.8 -448.7 24251.3
##
## Coefficients: (1 not defined because of singularities)
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2428.32 526.50 -4.612 0.00000454 ***
## IDADE 259.47 10.07 25.755 < 0.0000000000000002 ***
## IDADE2 NA NA NA NA
## SEXOMASCULINO -341.57 281.18 -1.215 0.225
## FILHOS 489.98 116.09 4.221 0.00002674 ***
## REGIAONORTE 360.03 399.58 0.901 0.368
## REGIAOSUDESTE -485.06 401.55 -1.208 0.227
## REGIAOSUL 128.34 398.55 0.322 0.748
## bmi30 435.08 319.47 1.362 0.174
## FUMANTESIM 13385.06 527.93 25.354 < 0.0000000000000002 ***
## bmi30:FUMANTESIM 19686.50 705.30 27.912 < 0.0000000000000002 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4295 on 931 degrees of freedom
## Multiple R-squared: 0.8783, Adjusted R-squared: 0.8771
## F-statistic: 746.4 on 9 and 931 DF, p-value: < 0.00000000000000022
res <- residuals(modelo1)
res <- as.data.frame(res)
res <- as.data.frame(res);class(res)
## [1] "data.frame"
pr <- ggplot(res,aes(x=res))+
geom_histogram(aes(y=..density..),
fill = "grey", color = "black",
bins = 15)+
labs(x = "residuals",
y = "frequency")+
theme_minimal()+
stat_function(fun = dnorm, args = list(mean = mean(res$res), sd = sd(res$res)), color = "red", size = 1);print(pr)
Residuals: diferenca entre os valores observados e os valores previstos. Devem se parecer como uma distribuição normal, isso indica que a média da diferenca entre os valores previstos e os valores observadors é próximo de 0.
Std error: o ideal Ă© que este valor seja menor que o valor do coeficiente, mas nem sempre isso irĂĄ ocorrer.
Asteriscos: representam os nĂveis de significancia de acordo com p-value. Quanto mais asteriscos, maior a significancia,
T-value: define se o coeficiente da variĂĄvel Ă© significativo ou nĂŁo para o modelo. Ele Ă© usado para calcular o p-value e os nĂveis de significĂąncia.
P-value: representa a probabilidade que a variĂĄvel nao seja relevante. Deve ser o menor valor possĂvel. Se este valor for realmente pequeno, serĂĄ exibido em notação cientifica.
R-squared: ajuda a avaliar o nivel de precisao do nosso modelo, quanto maior melhor.
par(mfrow = c(2,2))
plot(modelo1, which = c(1:4), pch = 20)
GrĂĄfico 1: Temos os resĂduos em função dos valores estimados. Aqui observamos a independĂȘncia e a homocedasticidade, se os resĂduos se distribuem de maneira razoavelmente aleatĂłria e com mesma amplitude em torno do zero.
GrĂĄfico 2: Podemos avaliar a normalidade dos resĂduos. A linha diagonal pontilhada representa a distribuição normal teĂłrica, e os pontos a distribuição dos resĂduos observada. Espera-se que nĂŁo exista grande fuga dos pontos em relação Ă reta.
GrĂĄfico 3: Pode ser avaliado da mesma maneira que o primeiro, observando a aleatoriedade e amplitude, desta vez dos resĂduos padronizados.
GrĂĄfico 4: E o Ășltimo grĂĄfico permite visualizar as DistĂąncias de Cook das observaçÔes, uma medida de influĂȘncia que pode indicar a presença de outliers quando possui valor maior do que 1.
Aqui faremos a previsão dos dados de teste. O modelo treinado até aqui, irå prever os valores da variåvel GASTOS dos dados de teste.
predict1 <- predict(modelo1, teste)
## Warning in predict.lm(modelo1, teste): prediction from a rank-deficient fit may
## be misleading
previsto <- round(predict1, digits = 0)
result <- cbind(previsto, teste$GASTOS)
indexx <- c(1:397)
colnames(result) <- c("previsto","realizado")
result <- as.data.frame(result)
resultado <- cbind(indexx,result)
resultado_plot <- resultado%>%
select(indexx, previsto, realizado) %>%
gather(Type,value,-indexx)
Agora vamos comparar os dados previsto pelo nosso modelo de RegressĂŁo Linear MĂșltipla com os dados de teste, afim de termos uma vizualição grĂĄfica quanto ao desempenho do modelo criado em relação aos dados de teste.
grafico8 = ggplot(data = resultado_plot, aes(x = indexx, y = value))+
geom_line(aes(color = Type), size = 0.5) +
scale_color_manual(values = c("darkred","black")) +
ggtitle("Valor Previsto x Realizado")+
xlab("Index") +
ylab("Gastos") +
theme_light()
print(grafico8)
referĂȘncias:
www.datascienceacademy.com.br
www.medium.com