Introdução

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.

Refinamento dos Dados

# 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"

Análise dos Dados

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.

Gráfico 1 - Radius_SE boxplot

#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.

Gráfico 2 - Scatterplot Worst_Radius x Mean_Radius

#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.

Modelo Preditivo

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

Conclusão

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.