É um dataset do Kaggle no qual pode ser acessado aqui.
O Zoo Animal Classification Dataset consiste originalmente em 101 animais de um zoológico e 16 variáveis com diversas características que os descrevem (os atributos), além da classe a que cada animal pertence (o alvo).
Esse conjunto de dados original é frequentemente usado no aprendizado de máquina, pois é um exemplo completo, mas simples, para praticar problemas de classificação com classes de vários rótulos. No entanto, como ele fornece apenas cem linhas, alguns algoritmos de ML podem não funcionar bem. É exatamente aí que esse conjunto de dados estendido se encaixa.
Como um complemento ao conjunto de dados de classificação de animais do zoológico original, este conjunto de dados fornece:
No arquivo zoo2.csv temos várias colunas no qual significam:
Primeiramente carregamos nossos dados:
data <- read_csv(here::here("data/zoo2.csv"),
col_types = cols(
animal_name = col_character(),
hair = col_double(),
feathers = col_double(),
eggs = col_double(),
milk = col_double(),
airborne = col_double(),
aquatic = col_double(),
predator = col_double(),
toothed = col_double(),
backbone = col_double(),
breathes = col_double(),
venomous = col_double(),
fins = col_double(),
legs = col_double(),
tail = col_double(),
domestic = col_double(),
catsize = col_double(),
class_type = col_double()
))
glimpse(data)
## Rows: 43
## Columns: 18
## $ animal_name <chr> "turtle", "chameleon", "iguana", "lizard", "gecko", "pytho…
## $ hair <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ feathers <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ eggs <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ milk <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ airborne <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ aquatic <dbl> 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1…
## $ predator <dbl> 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0…
## $ toothed <dbl> 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1…
## $ backbone <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ breathes <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1…
## $ venomous <dbl> 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ fins <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0…
## $ legs <dbl> 4, 4, 4, 4, 4, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4…
## $ tail <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ domestic <dbl> 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1…
## $ catsize <dbl> 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0…
## $ class_type <dbl> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5…
E visualizamos um sumário sobre as colunas:
data %>%
summary()
## animal_name hair feathers eggs milk
## Length:43 Min. :0.00000 Min. :0 Min. :1 Min. :0
## Class :character 1st Qu.:0.00000 1st Qu.:0 1st Qu.:1 1st Qu.:0
## Mode :character Median :0.00000 Median :0 Median :1 Median :0
## Mean :0.02326 Mean :0 Mean :1 Mean :0
## 3rd Qu.:0.00000 3rd Qu.:0 3rd Qu.:1 3rd Qu.:0
## Max. :1.00000 Max. :0 Max. :1 Max. :0
## airborne aquatic predator toothed
## Min. :0.0000 Min. :0.0000 Min. :0.0000 Min. :0.0000
## 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:0.0000
## Median :0.0000 Median :0.0000 Median :0.0000 Median :0.0000
## Mean :0.1628 Mean :0.4651 Mean :0.3023 Mean :0.4419
## 3rd Qu.:0.0000 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. :1.0000 Max. :1.0000 Max. :1.0000 Max. :1.0000
## backbone breathes venomous fins
## Min. :0.0000 Min. :0.0000 Min. :0.0000 Min. :0.0000
## 1st Qu.:0.0000 1st Qu.:1.0000 1st Qu.:0.0000 1st Qu.:0.0000
## Median :1.0000 Median :1.0000 Median :0.0000 Median :0.0000
## Mean :0.5814 Mean :0.7674 Mean :0.1163 Mean :0.1628
## 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:0.0000 3rd Qu.:0.0000
## Max. :1.0000 Max. :1.0000 Max. :1.0000 Max. :1.0000
## legs tail domestic catsize
## Min. :0.000 Min. :0.0000 Min. :0.0000 Min. :0.0000
## 1st Qu.:0.000 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:0.0000
## Median :4.000 Median :0.0000 Median :0.0000 Median :0.0000
## Mean :3.209 Mean :0.4884 Mean :0.1163 Mean :0.3721
## 3rd Qu.:6.000 3rd Qu.:1.0000 3rd Qu.:0.0000 3rd Qu.:1.0000
## Max. :8.000 Max. :1.0000 Max. :1.0000 Max. :1.0000
## class_type
## Min. :3.000
## 1st Qu.:3.000
## Median :5.000
## Mean :4.837
## 3rd Qu.:6.000
## Max. :7.000
Assim como foi informado alguns dos atributos possuem somente um unico valor em todo o dataset, como é o caso do fearthes, eggs e milk. Outra observação, é que a variavel preditora class_type possui somente valores de 3 a 7.
data = data %>%
select(animal_name, hair, airborne, aquatic, predator, toothed, backbone, breathes, venomous, fins, legs, tail, domestic, catsize, class_type)
Olhemos então para o número de pernas (legs), por ser nossa única variável não-binária, em relação ao tipo de classe animal (class_type) temos:
data %>%
ggplot(aes(x = legs, y = class_type)) +
geom_count() +
labs(
title = "Tipo de classe (class_type) x número de pernas (legs)",
)
Vemos que algumas tipos de classe possuem somente uma caractéristica para seus indivíduos, em relação a quantidade de pernas, e outras possuem mais. O tipo de classe 6 possui seus indivíduos com 6 pernas e é uma característica exclusiva. Já o tipo de classe 5, possui indivíduos com 2 e 4 pernas, em que com 2 parece ser algum caso especial e único no dataset, e com 4 pernas temos outros tipos de classe que possuem essa característica. Podemos ver que o atributo legs pode ser um bom divisor inicial para determinar o tipo de classe. Mas será que realmente é um bom atributo? Criemos um modelo somente com essa variável para descobrir isso com o R².
data_t = data %>%
mutate(dec = as.factor(class_type))
bm <- glm(class_type ~ legs,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -75.56345158 -76.86110315 2.59530315 0.01688307 0.05857057 0.06025886
Vemos que o R² é muito baixo (0.016) usando somente legs. Diante disso, como escolher qual o melhor atributo? Criemos então vários modelos com todos os atributos e analisamos seus coeficientes e R²
bm <- glm(class_type ~ hair,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML
## -76.527324296 -76.861103153 0.667557714 0.004342624 0.015404713
## r2CU
## 0.015848751
bm <- glm(class_type ~ airborne,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -73.97038534 -76.86110315 5.78143562 0.03760963 0.12580515 0.12943147
bm <- glm(class_type ~ aquatic,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML
## -76.110172828 -76.861103153 1.501860648 0.009769965 0.034324084
## r2CU
## 0.035313470
bm <- glm(class_type ~ predator,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -74.1160933 -76.8611032 5.4900197 0.0357139 0.1198605 0.1233155
bm <- glm(class_type ~ toothed,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -68.0413751 -76.8611032 17.6394562 0.1147489 0.3364957 0.3461951
bm <- glm(class_type ~ backbone,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -45.1505244 -76.8611032 63.4211575 0.4125699 0.7712008 0.7934306
bm <- glm(class_type ~ breathes,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML
## -7.684881e+01 -7.686110e+01 2.459060e-02 1.599678e-04 5.717109e-04
## r2CU
## 5.881904e-04
bm <- glm(class_type ~ venomous,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML
## -76.682189824 -76.861103153 0.357826657 0.002327749 0.008287022
## r2CU
## 0.008525894
bm <- glm(class_type ~ fins,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -75.41111562 -76.86110315 2.89997507 0.01886504 0.06521739 0.06709727
bm <- glm(class_type ~ tail,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -43.5175803 -76.8611032 66.6870457 0.4338153 0.7879348 0.8106469
bm <- glm(class_type ~ domestic,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -73.86561549 -76.86110315 5.99097533 0.03897274 0.13005476 0.13380356
bm <- glm(class_type ~ catsize,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -70.31342588 -76.86110315 13.09535455 0.08518844 0.26253978 0.27010745
Observamos então que os melhores R² foram com tail (0.4338153), backbone (0.4125699) e toothed (0.1147489), montamos um modelo com os 3 e temos um R² de 0.54. Vemos que com isso, os fatores: ter cauda, ter espinha dosal ou ter dentes, ajuda bastante na classificação dos tipos. Mas e se adicionarmos mais variáveis, como fica o R²? Pegamos o 4º (catsize, R² 0.08518844) e 5º (domestic, R² 0.03897274) atributo com maior R² e analisamos o ganho.
bm <- glm(class_type ~ tail + backbone + toothed,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -34.8657468 -76.8611032 83.9907127 0.5463798 0.8581907 0.8829280
É observado que quase não há ganho, sendo assim, não importantes para nosso estudo que busca descrever quais as variáveis para o modelo de regressão que melhor explica o tipo de classe animal.
bm <- glm(class_type ~ tail + backbone + toothed + catsize + domestic,
data = data_t)
tidy(bm, conf.int = TRUE, exponentiate = TRUE) %>%
select(-statistic, -p.value)
pscl::pR2(bm)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML r2CU
## -34.6921696 -76.8611032 84.3378671 0.5486382 0.8593310 0.8841011