library(summarytools)
library(tidyverse)
library(GGally)
library(mice)
library(ggpubr)
library(shiny)POS-GRADUAÇÃO - MBA Data Science em IA
Trabalho de Analise Exploratoria de Dados PD
1 Publicação
Este projeto está disponivel no github: https://github.com/echer/26E1-infnet-trabalho-pd-analise-exploratoria-de-dados.git
Esta disponível também no RPUB: https://rpubs.com/alanecher/1420896
2 Escolha da Base de Dados
A base escolhida foi o dataset de Detecção de Dengue (dados clinicos) - Disponível no kaggle: https://www.kaggle.com/datasets/aravind3505/dengue-detection-dataset-clinical-data
Motivo da escolha: Possui variáveis numéricas, dados faltantes, permite análise entre variáveis.
Resultados esperados: Identificar relações entre variáveis, analisar distribuição dos dados.
3 Pacotes
4 Carregamento da Base de Dados
dados <- read.csv("data/dataset.csv")
#View(dados)summary(dados) age gender hemoglobin_g_dl wbc_count
Min. : 3.0 Length:989 Min. :11.00 Min. : 2000
1st Qu.: 27.0 Class :character 1st Qu.:12.60 1st Qu.: 2600
Median : 40.0 Mode :character Median :13.70 Median : 3200
Mean : 42.2 Mean :13.71 Mean : 4338
3rd Qu.: 55.0 3rd Qu.:15.00 3rd Qu.: 6200
Max. :120.0 Max. :25.00 Max. :10900
NA's :24
differential_count rbc_count platelet_count
Min. :0.0000 Min. :0.0000 Min. : 10000
1st Qu.:1.0000 1st Qu.:1.0000 1st Qu.: 46000
Median :1.0000 Median :1.0000 Median : 93000
Mean :0.9393 Mean :0.9383 Mean :114702
3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:162500
Max. :1.0000 Max. :1.0000 Max. :500000
NA's :16
platelet_distribution_width dengue_label
Min. : 1.00 Min. :0.0000
1st Qu.: 14.00 1st Qu.:0.0000
Median : 17.80 Median :1.0000
Mean : 22.85 Mean :0.6512
3rd Qu.: 28.20 3rd Qu.:1.0000
Max. :215.00 Max. :1.0000
NA's :19
descr(dados)Descriptive Statistics
dados
N: 989
age dengue_label differential_count hemoglobin_g_dl platelet_count
----------------- -------- -------------- -------------------- ----------------- ----------------
Mean 42.20 0.65 0.94 13.71 114702.24
Std.Dev 20.94 0.48 0.24 1.48 89421.77
Min 3.00 0.00 0.00 11.00 10000.00
Q1 27.00 0.00 1.00 12.60 46000.00
Median 40.00 1.00 1.00 13.70 93000.00
Q3 55.00 1.00 1.00 15.00 162500.00
Max 120.00 1.00 1.00 25.00 500000.00
MAD 20.76 0.00 0.00 1.78 87473.40
IQR 28.00 1.00 0.00 2.40 116500.00
CV 0.50 0.73 0.25 0.11 0.78
Skewness 0.55 -0.63 -3.68 0.37 1.32
SE.Skewness 0.08 0.08 0.08 0.08 0.08
Kurtosis 0.00 -1.60 11.52 2.06 1.83
N.Valid 989.00 989.00 989.00 989.00 973.00
N 989.00 989.00 989.00 989.00 989.00
Pct.Valid 100.00 100.00 100.00 100.00 98.38
Table: Table continues below
platelet_distribution_width rbc_count wbc_count
----------------- ----------------------------- ----------- -----------
Mean 22.85 0.94 4338.03
Std.Dev 14.69 0.24 2344.53
Min 1.00 0.00 2000.00
Q1 14.00 1.00 2600.00
Median 17.80 1.00 3200.00
Q3 28.20 1.00 6200.00
Max 215.00 1.00 10900.00
MAD 7.12 0.00 1037.82
IQR 14.20 0.00 3600.00
CV 0.64 0.26 0.54
Skewness 5.23 -3.64 1.03
SE.Skewness 0.08 0.08 0.08
Kurtosis 58.80 11.25 -0.37
N.Valid 970.00 989.00 965.00
N 989.00 989.00 989.00
Pct.Valid 98.08 100.00 97.57
analyze_categorical <- function(column, label){
ggplot(data.frame(column), aes(x=column)) +
geom_bar(fill="lightblue") +
labs(
title=paste("Distribuição de", label),
x=label,
y="Frequência"
) +
theme_minimal()
}
analyze_numerical <- function(column, columnLabel){
Q0 <- min(column, na.rm = TRUE)
Q1 <- as.numeric(quantile(column, 0.25, na.rm = TRUE))
Q2 <- as.numeric(quantile(column, 0.50, na.rm = TRUE))
Q3 <- as.numeric(quantile(column, 0.75, na.rm = TRUE))
Q4 <- as.numeric(quantile(column, 1.00, na.rm = TRUE))
IQR_val <- IQR(column, na.rm = TRUE)
mean_val <- mean(column, na.rm = TRUE)
sd_val <- sd(column, na.rm = TRUE)
# binwidth automático (Freedman-Diaconis)
n <- length(column)
binwidth <- 2 * IQR_val / (n^(1/3))
LI <- Q1 - 1.5 * IQR_val
LS <- Q3 + 1.5 * IQR_val
cat("Média:",mean_val,"\n")
cat("Mediana:",Q2,"\n")
cat("Desvio padrão:",sd_val,"\n")
cat("Q1:",Q1,"\n")
cat("Q3:",Q3,"\n")
cat("IQR:",IQR_val,"\n")
# Boxplot
box <- ggplot(data.frame(column), aes(x = "", y = column)) +
geom_boxplot(fill = "lightblue") +
geom_hline(yintercept = LI, color = "red", linetype = "dashed") +
geom_hline(yintercept = LS, color = "blue", linetype = "dashed") +
geom_hline(yintercept = Q0, color = "orange", linetype = "dashed") +
geom_hline(yintercept = Q4, color = "orange", linetype = "dashed") +
annotate("text", x = 1.2, y = Q0, label = "(0%)") +
annotate("text", x = 1.2, y = Q1, label = paste("Q1 =", Q1)) +
annotate("text", x = 1.2, y = Q2, label = paste("Q2 =", Q2)) +
annotate("text", x = 1.2, y = Q3, label = paste("Q3 =", Q3)) +
annotate("text", x = 1.2, y = Q4, label = "(100%)") +
annotate("text", x = 1.2, y = LI, label = paste("Limite Inf:", round(LI,2))) +
annotate("text", x = 1.2, y = LS, label = paste("Limite Sup:", round(LS,2))) +
labs(title = paste("Boxplot -", columnLabel),
y = columnLabel,
x = "")+
scale_y_continuous(labels = scales::comma)
# Histograma
hist <- ggplot(data.frame(column), aes(x = column)) +
geom_histogram(binwidth = binwidth,
aes(y=..density..),
fill = "lightblue",
color = "black") +
geom_density(color="darkblue", size=1) +
geom_vline(xintercept=mean_val,
color="red",
linetype="dashed") +
geom_vline(xintercept=Q2,
color="green",
linetype="dashed") +
labs(title = paste("Histograma -", columnLabel),
x = columnLabel,
y = "Frequência")+
scale_x_continuous(labels = scales::comma)
qqplot <- ggqqplot(column)
shapiro_test <- shapiro.test(column)
print(box)
print(hist)
print(qqplot)
print(shapiro_test)
}4.1 Análise de Colunas com Dados Nullos
As colunas com dados nullos foram poucas:
wbc_count: 24
platelet_count: 16
platelet_distribution_width: 19
colSums(is.na(dados)) age gender
0 0
hemoglobin_g_dl wbc_count
0 24
differential_count rbc_count
0 0
platelet_count platelet_distribution_width
16 19
dengue_label
0
4.2 Completude de dados
Os dados estão em sua maioria preenchidos a nao ser pelos poucos dados faltantes das colunas acima.
Na minha visão, a completude impacta diretamente a análise exploratória, pois a presença de dados faltantes reduz a quantidade de informações disponíveis e pode comprometer os resultados.
Durante a análise, percebo que valores ausentes podem distorcer medidas estatísticas, dificultar a identificação de padrões e influenciar a interpretação dos dados.
platelet_count: 98%
platelet_distribution_width: 98%
wbc_count: 97%
age: 100%
hemoglobin_g_dl: 100%
differential_count: 100%
dengue_label: 100%
gender: 100%
rbc_count: 100%
colMeans(!is.na(dados)) age gender
1.0000000 1.0000000
hemoglobin_g_dl wbc_count
1.0000000 0.9757331
differential_count rbc_count
1.0000000 1.0000000
platelet_count platelet_distribution_width
0.9838220 0.9807887
dengue_label
1.0000000
4.3 Análise da Variável Age
A variável age apresenta alguns outliers acima do limite superior, incluindo um valor próximo de 120 anos. Apesar disso, média e mediana são próximas, indicando que os dados não são muito assimétricos.
analyze_numerical(dados$age, "Age")Média: 42.19919
Mediana: 40
Desvio padrão: 20.94111
Q1: 27
Q3: 55
IQR: 28
Shapiro-Wilk normality test
data: column
W = 0.97524, p-value = 6.081e-12
4.4 Análise da Variável Hemoglobin Level
A variável apresenta outliers acima do limite superior, com valores próximos de 25. Mesmo assim, média e mediana são próximas, indicando baixa assimetria.
analyze_numerical(dados$hemoglobin_g_dl, "Hemoglobin Level")Média: 13.71294
Mediana: 13.7
Desvio padrão: 1.484111
Q1: 12.6
Q3: 15
IQR: 2.4
Shapiro-Wilk normality test
data: column
W = 0.94491, p-value < 2.2e-16
4.5 Análise da Variável White Blood Cell Count
A variável apresenta outliers e dados faltantes. A diferença entre média e mediana indica leve assimetria, e a distribuição não parece normal.
analyze_numerical(dados$wbc_count, "White Blood Cell Count")Média: 4338.031
Mediana: 3200
Desvio padrão: 2344.53
Q1: 2600
Q3: 6200
IQR: 3600
Shapiro-Wilk normality test
data: column
W = 0.80885, p-value < 2.2e-16
4.6 Análise da Variável Platelet Count
A variável apresenta outliers e dados faltantes. A diferença entre média e mediana indica assimetria nos dados.
analyze_numerical(dados$platelet_count, "Platelet Count")Média: 114702.2
Mediana: 93000
Desvio padrão: 89421.77
Q1: 46000
Q3: 162500
IQR: 116500
Shapiro-Wilk normality test
data: column
W = 0.87991, p-value < 2.2e-16
4.7 Análise da Variável Variation in Platelet
A variável apresenta alguns outliers e dados faltantes, mas média e mediana próximas indicam baixa assimetria.
analyze_numerical(dados$platelet_distribution_width, "Variation in Platelet")Média: 22.84887
Mediana: 17.8
Desvio padrão: 14.69287
Q1: 14
Q3: 28.2
IQR: 14.2
Shapiro-Wilk normality test
data: column
W = 0.65462, p-value < 2.2e-16
4.8 Análise da Variável Dengue
A variável mostra a distribuição dos casos com e sem dengue.
analyze_categorical(dados$dengue_label, "Target Variable")4.9 Análise da Variável Gender
A variável apresenta a distribuição de gênero na base, podendo indicar possível desbalanceamento.
analyze_categorical(dados$gender, "Gender")4.10 Análise da Variável Differential Count
A variável apresenta a distribuição das categorias relacionadas à contagem diferencial. A análise permite observar a frequência de cada grupo e identificar possíveis desbalanceamentos.
dados$differential_count = as.factor(dados$differential_count)
analyze_categorical(dados$differential_count, "Diff White Blood Cell Count")4.11 Análise da Variável Red Blood Cell Count
A variável apresenta a distribuição das categorias relacionadas à contagem de glóbulos vermelhos. É possível observar a proporção entre os grupos e verificar possíveis diferenças entre eles.
dados$rbc_count = as.factor(dados$rbc_count)
analyze_categorical(dados$rbc_count, "Red Blood Cell Count")5 Remoção de colunas categóricas
dados <- dados[, sapply(dados, is.numeric)]6 Tratamento de Valores Nullos
Para tratar os dados faltantes, foi utilizada a técnica de imputação por meio do pacote MICE. O método utilizado foi o Predictive Mean Matching (PMM), que estima valores ausentes com base em valores observados semelhantes, preservando a distribuição dos dados. Foram realizadas 5 imputações (m=5). O parâmetro seed foi utilizado para garantir a reprodutibilidade dos resultados.
dados = complete(mice(dados, m=5, method="pmm", seed=123))
iter imp variable
1 1 wbc_count platelet_count platelet_distribution_width
1 2 wbc_count platelet_count platelet_distribution_width
1 3 wbc_count platelet_count platelet_distribution_width
1 4 wbc_count platelet_count platelet_distribution_width
1 5 wbc_count platelet_count platelet_distribution_width
2 1 wbc_count platelet_count platelet_distribution_width
2 2 wbc_count platelet_count platelet_distribution_width
2 3 wbc_count platelet_count platelet_distribution_width
2 4 wbc_count platelet_count platelet_distribution_width
2 5 wbc_count platelet_count platelet_distribution_width
3 1 wbc_count platelet_count platelet_distribution_width
3 2 wbc_count platelet_count platelet_distribution_width
3 3 wbc_count platelet_count platelet_distribution_width
3 4 wbc_count platelet_count platelet_distribution_width
3 5 wbc_count platelet_count platelet_distribution_width
4 1 wbc_count platelet_count platelet_distribution_width
4 2 wbc_count platelet_count platelet_distribution_width
4 3 wbc_count platelet_count platelet_distribution_width
4 4 wbc_count platelet_count platelet_distribution_width
4 5 wbc_count platelet_count platelet_distribution_width
5 1 wbc_count platelet_count platelet_distribution_width
5 2 wbc_count platelet_count platelet_distribution_width
5 3 wbc_count platelet_count platelet_distribution_width
5 4 wbc_count platelet_count platelet_distribution_width
5 5 wbc_count platelet_count platelet_distribution_width
Verificamos novamente se existem valores nullos
colSums(is.na(dados)) age hemoglobin_g_dl
0 0
wbc_count platelet_count
0 0
platelet_distribution_width dengue_label
0 0
7 Análise de pares
ggpairs(
dados,
lower = list(
continuous = wrap("points") +
scale_x_continuous(labels = scales::comma) +
scale_y_continuous(labels = scales::comma)
),
diag = list(
continuous = wrap("densityDiag") +
scale_x_continuous(labels = scales::comma)
),
upper = list(
continuous = wrap("cor", size = 4)
)
)+ theme(axis.text = element_text())A partir da análise visual da matriz de espalhamento as maiores correlações foram encontradas entre platelet_count e wbc_count, seguidas pelas relações com dengue_label e platelet_distribution_width, platelet_count e dengue_label, e platelet_count e platelet_distribution_width. As demais variáveis apresentam baixa correlação.
1. platelet_count × wbc_count → corr ≈ 0.749
2. platelet_distribution_width × dengue_label → corr ≈ -0.651
3. platelet_count × dengue_label → corr ≈ -0.577
4. platelet_count × platelet_distribution_width → corr ≈ 0.456
8 Resultado da Análise
8.1 Distribuições normais
Com base na análise, observei que as variáveis age e hemoglobin_g_dl apresentam comportamento mais próximo de uma distribuição normal, com menor assimetria. Por outro lado, as variáveis wbc_count, platelet_count e platelet_distribution_width apresentam comportamento semelhante, com assimetria e presença de valores extremos, afastando-se da normalidade.
8.2 Histogramas
A partir da análise dos histogramas, observa-se que as variáveis age e hemoglobin_g_dl apresentam distribuição mais próxima da simétrica, com concentração de valores centrais e baixa assimetria. Por outro lado, as variáveis wbc_count, platelet_count e platelet_distribution_width apresentam comportamento semelhante, com assimetria à direita, indicando maior concentração de valores baixos e presença de cauda para valores elevados.
8.3 Justificativa dos Bins
O número de bins utilizado nos histogramas foi definido automaticamente com base na regra de Freedman-Diaconis, considerando a variabilidade e o tamanho da amostra. Essa abordagem foi aplicada de forma consistente para todas as variáveis, garantindo um equilíbrio entre detalhamento e clareza visual, independentemente das diferenças de escala e dispersão entre elas.
8.4 Shapiro-Wilk
O teste de Shapiro-Wilk indicou p-values menores que 0.05 para todas as variáveis, sugerindo não normalidade. No entanto, como a base de dados possui um número elevado de observações, o teste tende a ser muito sensível. Dessa forma, a análise foi complementada com histogramas e gráficos Q-Q, que indicaram que algumas variáveis apresentam comportamento próximo à normalidade, conforme descrito acima.
9 Dashboard Interativo
Foi desenvolvido um dashboard interativo utilizando o pacote Shiny, permitindo a seleção de variáveis numéricas da base de dados, o usuário pode escolher a variável a ser analisada, definir a cor do gráfico de linha e ajustar os limites dos eixos X e Y, possibilitando uma visualização dinâmica dos dados.
ui <- fluidPage(
titlePanel("Dashboard - Análise de Dados"),
sidebarLayout(
sidebarPanel(
selectInput("variavel", "Selecione a variável:",
choices = names(dados)[sapply(dados, is.numeric)]),
selectInput("cor", "Escolha a cor:",
choices = c("blue", "red", "green", "black")),
numericInput("xmin", "Limite inferior X:", value = 1),
numericInput("xmax", "Limite superior X:", value = 100),
numericInput("ymin", "Limite inferior Y:", value = 0),
numericInput("ymax", "Limite superior Y:", value = 100000)
),
mainPanel(
plotOutput("grafico")
)
)
)
server <- function(input, output) {
output$grafico <- renderPlot({
var <- dados[[input$variavel]]
df <- data.frame(x = 1:length(var), y = var)
ggplot(df, aes(x = x, y = y)) +
geom_line(color = input$cor) +
xlim(input$xmin, input$xmax) +
ylim(input$ymin, input$ymax) +
labs(title = paste("Gráfico de", input$variavel),
x = "Índice",
y = input$variavel)
})
}
shinyApp(ui = ui, server = server)