O projeto desenvolvido corresponde a primeira etapa do processo seletivo da RedFox para a vaga de Cientista de Dados. O principal objetivo desse projeto é avaliar a capacidade do candidato, como cientista de dados, de entendimento do problema e desenvolvimento da sua respectiva solução.
Neste desafio a missão é criar um ou mais modelo(s) preditivo(s) utilizando a bases de dados provenientes do UCI Machine Learning Repository, relacionado ao temas de saúde. O banco de dados utilizado no desafio foi o wdbc, que significa Wisconsin Diagnostic Breast Cancer.
Esse banco de dados é composto por características como média, máximo, mínimo de diferentes variáveis do núcleo da células da mama como perímetro, área, raio, simetria, suavidade, entre outros. Além disso, o banco possui o diagnostico final do tumor analisado (M = malignant, B = benign) e o número de identificação dos pacientes.
Portanto, é perceptível que pode-se criar um modelos de classificação de aprendizado de máquinas. Já que, a variável dependente (diagnosis) é uma variável categórica que possui duas categorias que representam o tipo do tumor: maligno (malignant) ou benigno (benign).
Como primeiro passo para se realizar uma análise de dados, deve-se ler o banco de dados e fazer uma avaliação básica de suas variáveis e realizar algum tipo de refinamento, caso seja necessário.
# Set working directory
setwd("C:/Users/olive/Desktop/RedFox")
# Read dataset
df <- read.table('wdbc.data', sep=',')
# Dataset variables caracteristic
print(str(df))
## 'data.frame': 569 obs. of 32 variables:
## $ V1 : int 842302 842517 84300903 84348301 84358402 843786 844359 84458202 844981 84501001 ...
## $ V2 : Factor w/ 2 levels "B","M": 2 2 2 2 2 2 2 2 2 2 ...
## $ V3 : num 18 20.6 19.7 11.4 20.3 ...
## $ V4 : num 10.4 17.8 21.2 20.4 14.3 ...
## $ V5 : num 122.8 132.9 130 77.6 135.1 ...
## $ V6 : num 1001 1326 1203 386 1297 ...
## $ V7 : num 0.1184 0.0847 0.1096 0.1425 0.1003 ...
## $ V8 : num 0.2776 0.0786 0.1599 0.2839 0.1328 ...
## $ V9 : num 0.3001 0.0869 0.1974 0.2414 0.198 ...
## $ V10: num 0.1471 0.0702 0.1279 0.1052 0.1043 ...
## $ V11: num 0.242 0.181 0.207 0.26 0.181 ...
## $ V12: num 0.0787 0.0567 0.06 0.0974 0.0588 ...
## $ V13: num 1.095 0.543 0.746 0.496 0.757 ...
## $ V14: num 0.905 0.734 0.787 1.156 0.781 ...
## $ V15: num 8.59 3.4 4.58 3.44 5.44 ...
## $ V16: num 153.4 74.1 94 27.2 94.4 ...
## $ V17: num 0.0064 0.00522 0.00615 0.00911 0.01149 ...
## $ V18: num 0.049 0.0131 0.0401 0.0746 0.0246 ...
## $ V19: num 0.0537 0.0186 0.0383 0.0566 0.0569 ...
## $ V20: num 0.0159 0.0134 0.0206 0.0187 0.0188 ...
## $ V21: num 0.03 0.0139 0.0225 0.0596 0.0176 ...
## $ V22: num 0.00619 0.00353 0.00457 0.00921 0.00511 ...
## $ V23: num 25.4 25 23.6 14.9 22.5 ...
## $ V24: num 17.3 23.4 25.5 26.5 16.7 ...
## $ V25: num 184.6 158.8 152.5 98.9 152.2 ...
## $ V26: num 2019 1956 1709 568 1575 ...
## $ V27: num 0.162 0.124 0.144 0.21 0.137 ...
## $ V28: num 0.666 0.187 0.424 0.866 0.205 ...
## $ V29: num 0.712 0.242 0.45 0.687 0.4 ...
## $ V30: num 0.265 0.186 0.243 0.258 0.163 ...
## $ V31: num 0.46 0.275 0.361 0.664 0.236 ...
## $ V32: num 0.1189 0.089 0.0876 0.173 0.0768 ...
## NULL
Através dessa primeira análise se pode notar que o banco de dados possui 568 observações para cada uma das suas 32 variáveis. Dessas variáveis, 31 são numéricas e apenas 1 é categórica. Após essa análise inicial, deve-se verificar se o banco de dados possui valores ausente (NA – missing values).
# Load package
library(naniar)
# Get missing values (NA) summary
NA_df <- as.data.frame(miss_var_summary(df))
# Print NA dataframe
print(NA_df)
## variable n_miss pct_miss
## 1 V1 0 0
## 2 V2 0 0
## 3 V3 0 0
## 4 V4 0 0
## 5 V5 0 0
## 6 V6 0 0
## 7 V7 0 0
## 8 V8 0 0
## 9 V9 0 0
## 10 V10 0 0
## 11 V11 0 0
## 12 V12 0 0
## 13 V13 0 0
## 14 V14 0 0
## 15 V15 0 0
## 16 V16 0 0
## 17 V17 0 0
## 18 V18 0 0
## 19 V19 0 0
## 20 V20 0 0
## 21 V21 0 0
## 22 V22 0 0
## 23 V23 0 0
## 24 V24 0 0
## 25 V25 0 0
## 26 V26 0 0
## 27 V27 0 0
## 28 V28 0 0
## 29 V29 0 0
## 30 V30 0 0
## 31 V31 0 0
## 32 V32 0 0
A tabela NA_df criada mostra que o banco de dados não possui valores ausentes, logo não é necessário refinar o banco de dados.
Para se ter um banco de dados mais organizado, deve-se nomear as variáveis (colunas) de acordo com sua respectiva definição, de modo que ela se trone mais fácil de ser reconhecida. De acordo com o Wisconsin Diagnostic Breast Cancer, as variáveis abaixo representam:
V1 - ID number
V2 - Cancer Diagnosis
V3 - Cell nucleus Mean Radius
V13 - Cell nucleus Radius SE
V23 - Cell nucleus Worst Radius
# Name dataframe variables
colnames(df)[c(1, 2, 3, 13, 23)] <-
c('ID', 'Diagnosis', 'Mean_Radius', 'Radius_SE', 'Worst_Radius')
# Diagnosis levels names
levels(df$Diagnosis) <- c('Benign', 'Malignant')
# Print names
print(names(df))
## [1] "ID" "Diagnosis" "Mean_Radius" "V4"
## [5] "V5" "V6" "V7" "V8"
## [9] "V9" "V10" "V11" "V12"
## [13] "Radius_SE" "V14" "V15" "V16"
## [17] "V17" "V18" "V19" "V20"
## [21] "V21" "V22" "Worst_Radius" "V24"
## [25] "V25" "V26" "V27" "V28"
## [29] "V29" "V30" "V31" "V32"
Nesta etapa, será analisado como os dados se comportam. Para isso, deve ser criado gráficos que mostrem como as variáveis do banco de dados se correlacionam. O primeiro gráfico criado mostra a diferença entre diagnósticos para a variável que representa o raio SE da célula.
#Load packages
library(ggplot2)
library(plotly)
#Plot graphic
Plot1 <- ggplot(df,aes(x=Diagnosis, y=Radius_SE, color=Diagnosis)) +
geom_boxplot()+
theme_minimal() +
scale_color_manual(values=c('blue','red'))
ggplotly(Plot1)
Observa-se com o Gráfico 1 criado que as células que possuem menor raio SE são provinientes de tumores benignos, já os as que possuem maior raio SE são de tumores malignos.
#Plot graphic
Plot2 <- ggplot(df, aes(x=Mean_Radius, y=Worst_Radius, fill=Diagnosis))+
geom_point() +
scale_fill_manual(values=c('blue','red'))
ggplotly(Plot2)
Já o Gráfico 2 mostra a relação entre o pior raio e a sua média. Pode-se perceber que quanto maior for o valor do raio das células maior a probabilidade de ser um tumor maligno.
O algoritmo escolhido para ser usado no modelo preditivo foi o Naive Bayes, que é baseado no “Teorema de Bayes”. Esse algoritmo é muito utilizado em processamento de linguagem natural e diagnósticos médicos.
Antes de começar a criar o modelo, deve-se excluir as variáveis que não possuem significância ou que representam valores que vão prejudicar o modelo de alguma forma. A variável ID serve apenas como identificação logo deve ser retirada do banco de dados.
# Exclude ID variable
df$ID <- NULL
Decidiu-se separar o banco de dados em uma porcentagem de 80% os valores para serem usados como treino do modelo e 20% para o teste do mesmo. Assim, pode-se verificar se o modelo se adequo corretamente ao banco de dados.
# Split dataset into training and test set
library(caTools)
split <- sample.split(df$Diagnosis, SplitRatio = 0.8)
training_set <- subset(df, split == TRUE)
test_set <- subset(df, split == FALSE)
Por fim, deve aplicar o modelo e verificar sua performance com uma matriz de confusão e também com a eficiência do modelo.
# Load package
library(e1071)
# Create de predictve model
classifier <- naiveBayes(x = training_set[-1],
y = training_set$Diagnosis)
# Predicting the test set results
y_pred <- predict(classifier, newdata = test_set[-1])
# Making the confusion Matrix
cm <- table(test_set[, 1], y_pred)
# Print confusion matrix
print(cm)
## y_pred
## Benign Malignant
## Benign 64 7
## Malignant 3 39
# Efficiency
eff <- y_pred == test_set$Diagnosis
# Print efficiency
print(summary(eff))
## Mode FALSE TRUE
## logical 10 103
O modelo preditivo demostrou ter se adequado bem ao banco de dados, seus resultados tiveram uma eficiência maior que 90%.
É importante destacar que, como se trata de um diagnóstico médico o erro conhecido como falso negativo tem maior peso na avaliação do modelo, neste caso, o erro de detectar um tumor maligno como benigno. Por isso, para se obter melhores resultados é recomendado utilizar um modelo preditivo que leve em consideração esse fato citado.