Nesta etapa precisamos ler o arquivo de dados. Em geral ele está salvo como o .csv, mas pode ser outros formatos também.
Antes de rodar o código abaixo, use a função setwd()
para definir o diretório que se encontra o arquivo como o diretório
corrente.
library(tidyverse)
dir()
## [1] "base_teste.csv" "base_teste.rds"
## [3] "base_treino.csv" "base_treino.rds"
## [5] "base_treino_final.csv" "base_treino_final.rds"
## [7] "insurance.csv" "rsconnect"
## [9] "topico3-GET00217-script.R" "topico3-GET00217.html"
## [11] "topico3-GET00217.Rmd"
base = read_csv("insurance.csv")
base
## # A tibble: 1,338 × 9
## age sex bmi children smoker region charges married country
## <dbl> <chr> <dbl> <dbl> <chr> <chr> <dbl> <chr> <chr>
## 1 19 female 27.9 0 yes southwest 16885. yes usa
## 2 18 male 33.8 1 no southeast 1726. <NA> usa
## 3 28 male 33 3 no southeast 4449. yes usa
## 4 33 male 22.7 0 no northwest 21984. no usa
## 5 32 male 28.9 0 no northwest 3867. yes usa
## 6 31 female 25.7 0 no southeast 3757. yes usa
## 7 46 female 33.4 1 no southeast 8241. yes usa
## 8 37 female 27.7 3 no northwest 7282. yes usa
## 9 37 male 29.8 2 no northeast 6406. yes usa
## 10 60 female 25.8 0 no northwest 28923. <NA> usa
## # ℹ 1,328 more rows
glimpse(base)
## Rows: 1,338
## Columns: 9
## $ age <dbl> 19, 18, 28, 33, 32, 31, 46, 37, 37, 60, 25, 62, 23, 56, 27, 1…
## $ sex <chr> "female", "male", "male", "male", "male", "female", "female",…
## $ bmi <dbl> 27.900, 33.770, 33.000, 22.705, 28.880, 25.740, 33.440, 27.74…
## $ children <dbl> 0, 1, 3, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0…
## $ smoker <chr> "yes", "no", "no", "no", "no", "no", "no", "no", "no", "no", …
## $ region <chr> "southwest", "southeast", "southeast", "northwest", "northwes…
## $ charges <dbl> 16884.924, 1725.552, 4449.462, 21984.471, 3866.855, 3756.622,…
## $ married <chr> "yes", NA, "yes", "no", "yes", "yes", "yes", "yes", "yes", NA…
## $ country <chr> "usa", "usa", "usa", "usa", "usa", "usa", "usa", "usa", "usa"…
dim(base)
## [1] 1338 9
A base carregada tem 9 colunas e 1338 linhas. Cada linha (unidade amostral) representa um cliente e cada coluna (variável) uma característica desse cliente.
É preciso verificar quais as variáveis qualitativas e transformá-las
para o tipo factor
.
base$sex = as.factor(base$sex)
base$smoker = as.factor(base$smoker)
base$region = as.factor(base$region)
base$married = as.factor(base$married)
base$country = as.factor(base$country)
glimpse(base)
## Rows: 1,338
## Columns: 9
## $ age <dbl> 19, 18, 28, 33, 32, 31, 46, 37, 37, 60, 25, 62, 23, 56, 27, 1…
## $ sex <fct> female, male, male, male, male, female, female, female, male,…
## $ bmi <dbl> 27.900, 33.770, 33.000, 22.705, 28.880, 25.740, 33.440, 27.74…
## $ children <dbl> 0, 1, 3, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0…
## $ smoker <fct> yes, no, no, no, no, no, no, no, no, no, no, yes, no, no, yes…
## $ region <fct> southwest, southeast, southeast, northwest, northwest, southe…
## $ charges <dbl> 16884.924, 1725.552, 4449.462, 21984.471, 3866.855, 3756.622,…
## $ married <fct> yes, NA, yes, no, yes, yes, yes, yes, yes, NA, NA, yes, NA, N…
## $ country <fct> usa, usa, usa, usa, usa, usa, usa, usa, usa, usa, usa, usa, u…
Agora que a base já foi lida corretamente e as variáveis estão no seu formato ideal, vamos dividir a base em treino e teste. Todas as análises e ajustes dos modelos serão feitos na base de treino. A base de teste será usada somente mais pra frente, quando quisermos analisar o desempenho dos modelos com dados fora da amostra, isto é, dados que não foram usados no ajuste do modelo.
library(caret)
set.seed(123456789)
O pacote usado para isso é o caret
. Para garantir a
replicação do código é importante fixar a semente, já que o processo de
partição da base envolve sorteios aleatórios.
N = nrow(base) #numero de linhas da base
indices_treino = createDataPartition(1:N,p=0.75)[[1]]
base_treino = base |> slice(indices_treino)
base_teste = base |> slice(-indices_treino)
O hábito de salvar os objetos criados no R a cada etapa permite refazer algumas etapas sem precisar repetir as etapas iniciais, e, consequentemente, evita o retrabalho.
saveRDS(base_treino,file="base_treino.rds")
write_csv2(base_treino,file="base_treino.csv")
saveRDS(base_teste,file="base_teste.rds")
write_csv2(base_teste,file="base_teste.csv")
A partir de agora vamos usar somente a base de treino.
Antes de fazer qualquer análise estatistica em uma base de dados é preciso organizar, limpar e conhecer essa base. Por exemplo, precisamos verificar se a base possui ou não dados faltantes.
summary(base_treino)
## age sex bmi children smoker
## Min. :18.00 female:494 Min. :15.96 Min. :0.000 no :802
## 1st Qu.:27.00 male :512 1st Qu.:26.22 1st Qu.:0.000 yes:204
## Median :40.00 Median :30.25 Median :1.000
## Mean :39.39 Mean :30.63 Mean :1.087
## 3rd Qu.:51.00 3rd Qu.:34.80 3rd Qu.:2.000
## Max. :64.00 Max. :53.13 Max. :5.000
## NA's :1 NA's :1
## region charges married country
## northeast:241 Min. : 1122 no :301 usa :1005
## northwest:241 1st Qu.: 4763 yes :307 NA's: 1
## southeast:280 Median : 9333 NA's:398
## southwest:244 Mean :13183
## 3rd Qu.:16584
## Max. :63770
##
O simples comando summary
já nos mostra a existência ou
não de dados faltantes. Mas a biblioteca naniar
é mais
adequada para entneder melhor onde estão esses dados e tomar a melhor
decisão em relação à eles.
library(naniar)
base_treino |> gg_miss_var()
base_treino |> miss_var_summary()
## # A tibble: 9 × 3
## variable n_miss pct_miss
## <chr> <int> <dbl>
## 1 married 398 39.6
## 2 age 1 0.0994
## 3 bmi 1 0.0994
## 4 country 1 0.0994
## 5 sex 0 0
## 6 children 0 0
## 7 smoker 0 0
## 8 region 0 0
## 9 charges 0 0
Percebemos de cara que a variável married
contém muitos
dados faltantes. Quase 40% das entradas dessa variável são faltantes.
Isso é um percentual muito grande que justifica a retirada da
variável.
base_treino = base_treino |> select(-married)
base_treino |> gg_miss_var()
base_treino |> miss_var_summary()
## # A tibble: 8 × 3
## variable n_miss pct_miss
## <chr> <int> <dbl>
## 1 age 1 0.0994
## 2 bmi 1 0.0994
## 3 country 1 0.0994
## 4 sex 0 0
## 5 children 0 0
## 6 smoker 0 0
## 7 region 0 0
## 8 charges 0 0
Ainda temos dados faltantes, mas muito poucos. Um em cada uma das
seguintes variáveis: age
, bmi
e
country
. Podemos excluir as linhas que contém os dados
faltantes ou substituir eles pela média, caso a variável seja
quantitativa, ou a moda, caso a veriável seja qualitativa, da variável.
Aqui optei por retirar as linhas com NA restantes.
indice_na = is.na(base_treino$bmi)
base_treino = base_treino |> filter(!indice_na)
indice_na = is.na(base_treino$age)
base_treino = base_treino |> filter(!indice_na)
indice_na = is.na(base_treino$country)
base_treino = base_treino |> filter(!indice_na)
Os gráficos agora nos mostram que não restou nenhuma NA
na base.
base_treino |> gg_miss_var()
base_treino |> miss_var_summary()
## # A tibble: 8 × 3
## variable n_miss pct_miss
## <chr> <int> <dbl>
## 1 age 0 0
## 2 sex 0 0
## 3 bmi 0 0
## 4 children 0 0
## 5 smoker 0 0
## 6 region 0 0
## 7 charges 0 0
## 8 country 0 0
As variáveis estão na base para caracterizar e diferenciar os indivíduos (unidade amostrais). Se duas variáveis apresentam uma correlação muito grande, significa que as duas caracterizam os indivíduos de forma semelhate. De acordo com o princípio da parcimônia, “Se existe mais de uma explicação para uma dada observação, devemos adotar aquela mais simples”, devemos ficar com uma das duas variáveis.
cor(base_treino |> select(age, bmi, children, charges))
## age bmi children charges
## age 1.00000000 0.11507091 0.02382068 0.30716851
## bmi 0.11507091 1.00000000 0.01807609 0.17551576
## children 0.02382068 0.01807609 1.00000000 0.03028734
## charges 0.30716851 0.17551576 0.03028734 1.00000000
Outro caso que vamos analisar aqui é se existe uma variável com variablidade nula ou quase nula. Se a variável for a mesma, ou praticamente a mesma, entre todos os indivíduos, ela não agrega informação e também deve ser retirada
diag(cov(base_treino |> select(age, bmi, children, charges)))
## age bmi children charges
## 1.960621e+02 3.790117e+01 1.448206e+00 1.414954e+08
summary(base_treino |> select(sex,smoker,region,country))
## sex smoker region country
## female:491 no :800 northeast:241 usa:1003
## male :512 yes:203 northwest:239
## southeast:280
## southwest:243
Veja que a variável marriege
assume o mesmo valor para
todas as unidades amostrais. Dessa forma, tal variável deve ser retirada
da base.
base_treino = base_treino |> select(-country)
Uma breve análise descritiva já nos diz muito sobre os dados e é muito importante de ser realizada antes de qualquer modelagem estatística.
hist(base_treino$age)
hist(base_treino$bmi)
hist(base_treino$children)
hist(base_treino$charges)
barplot(table(base_treino$sex))
barplot(table(base_treino$smoker))
barplot(table(base_treino$region))
Para os métodos de redes neurais é sempre adequado padronizar as variáveies. Essa padronização pode ser feita de formas diferentes, como por exemplo,
\[ X_i = \dfrac{X_i - \bar{X}}{\sqrt{S^2}} \]
Que transforma a de forma que ela tenha média 0 e variância 1.
Outra possibilidade, muito usada também, é a transformação
\[X_i = \dfrac{X_i - \min(X)}{\max(X) - \min(X)}\]
que faz com que a variável transformada apresente valores somente entre 0 e 1. Esta opção é comum de ser usada para as variáveis de enteresse, que serão a saída da rede neural. Isso porque, em geral, a imagem da função de ativação de uma rede neural é um número limitado em um intervalo da reta. Nesse caso garantimos que a saída (transformada) será um número em \([0,1]\).
A transformação realizada aqui será a segunda apresentada. Mas poderia
base_treino_padronizada = base_treino |> mutate(
age = (age - min(age))/(max(age)-min(age)),
bmi = (bmi - min(bmi))/(max(bmi)-min(bmi)),
children = (children - min(children))/(max(children)-min(children)),
charges = (charges - min(charges))/(max(charges)-min(charges))
)
Em geral, as funções que rodam os métodos de redes neurais não aceita
as variáveis qualitativas passadas como factor
. É preciso
criar variáveis indicadoras que representem de forma numérica estas
variáveis qualitativas. Para isso será usada a função model.matrix
base_treino_final = as.matrix(model.matrix(~.,data = base_treino_padronizada)[,-1])
dim(base_treino_final)
## [1] 1003 9
colnames(base_treino_final)
## [1] "age" "sexmale" "bmi" "children"
## [5] "smokeryes" "regionnorthwest" "regionsoutheast" "regionsouthwest"
## [9] "charges"
COmo já comentado, é idnicado salvar os objetos criados a cada nova etapa do script.
saveRDS(base_treino_final,file="base_treino_final.rds")
write_csv(as.data.frame(base_treino_final),file="base_treino_final.csv")