Inicialmente, vamos instalar e carregar os pacotes que serão usados:
install.packages("DT", repos = "https://cloud.r-project.org/")
library(dplyr)
library(readr)
library(stringr)
library(DT)
library(janitor)
Após isso, vamos carregar os datasets que vamos utilizar:
url1 <- "https://raw.githubusercontent.com/michaellomuscio/Exploring-Data/master/PokemonData.csv"
df1 <- read_csv(url1)
url2 <- "https://www.dropbox.com/scl/fi/yr4srrbfd2jsx281kxk0u/pokemon.csv?rlkey=aujmk34bb06mu0qb7s90ehe4a&st=24oxpb16&dl=1"
df2 <- read_csv(url2)
Aqui vamos usar dois datasets para conseguir todas as informações necessárias para algumas demonstrações e análises.
Neste passo, vamos unir as principais colunas de cada um dos datasets. O segundo dataset será utilizado principalmente para complementar o primeiro com informações mais técnicas. Embora o segundo contenha quase todos os dados, o primeiro apresenta informações mais consistentes, por isso será adotado como dataset principal.
df_pokemon <- df1 %>%
select(everything()) %>%
inner_join(
df2 %>% select(name, classfication, experience_growth, percentage_male, is_legendary, starts_with("against_"), capture_rate),
by = c("Name" = "name")
)
Aqui temos uma organização geral desse dataframe que será utilizado, ajustando as nomenclaturas e os tipos de algumas das colunas:
df_pokemon <- df_pokemon %>%
mutate(is_legendary = as.logical(is_legendary)) %>%
mutate(classfication = as.factor(classfication)) %>%
mutate(Generation = factor(Generation, levels = sort(unique(Generation)), ordered = TRUE)) %>%
mutate(capture_rate = as.double(capture_rate)) %>%
rename(CaptureRate = capture_rate) %>%
rename(Classification = classfication) %>%
rename(ExpGrowth = experience_growth) %>%
rename(ID = Num) %>%
rename_with(~ str_replace_all(., "_([a-z])", function(x) toupper(sub("_", "", x))))
str(df_pokemon)
Aqui nós temos a primeiro coluna adicinal do nosso dataframe:
mythical_names <- c("Jirachi", "Darkrai", "Arceus", "Victini", "Diancie", "Volcanion")
df_pokemon <- df_pokemon %>%
# Pequeno ajuste, apenas porque alguns pokemon míticos estavam sendo tratados como lendários e vice-versa
mutate(Legendary = case_when(
Name %in% mythical_names ~ FALSE,
Name == "Cresselia" ~ TRUE,
TRUE ~ Legendary)) %>%
mutate(isLegendary = !Legendary & isLegendary) %>%
rename(Mythical = isLegendary)
Embora essas duas colunas (“Legendary” e “isLegendary”) dos dataframes originais pareçam ter a mesma função, elas tem uma pequena variação de significado:
df_pokemon %>%
filter(Legendary) %>%
select(Name, Type1, Type2, Legendary, Generation) %>%
datatable(
options = list(
pageLength = 5,
autoWidth = TRUE
),
caption = "Pokémon Lendários")
De fato, em geral Pokémon Míticos são entendidos como sendo um subconjunto dos Pokémon Lendários. A diferenciação entre eles é puramente determinada por como eles são apresentados nos jogos. (Bulbapedia contributors 2025c) O entendimento geral da comunidade é que os Míticos se difeririam dos Lendários por serem tão incrivelmente raros no mundo de Pokémon que poucas pessoas realmente acreditam na sua existência.(Bulbapedia contributors 2025d) Tradicionalmente, os Míticos, ao contrário dos Lendários que em geral podem ser obtidos normalmente no decorrer do jogos, só poderiam ser obtidos por meio de eventos de distribuição oficiais.
df_pokemon %>%
filter(Mythical)%>%
select(Name, Type1, Type2, Mythical, Generation) %>%
datatable(
options = list(
pageLength = 5,
autoWidth = TRUE
),
caption = "Pokémon Míticos")
Há ainda uma terceira categoria para classificação de Pokémon, essa sendo um tanto mais matemática que as demais. Trata-se da divisão de Pokémon Pseudo-Lendários. (Bulbapedia contributors 2025e)
Essa classificação não é oficial, sendo apenas um termo cunhado pela comunidade para definir um pequeno grupo de Pokémon que não são lendários ou míticos mas que obdecem alguns critérios: \[ \text{PseudoLegendary}_i = \begin{cases} \text{TRUE}, & \text{se } \begin{aligned}[t] & \text{TotalStats}_i \ge 600 \;\land\; \neg \text{Legendary}_i \;\land\; \neg \text{Mythical}_i \\[4pt] & \land\; \text{ExpGrowth}_i = 1{,}250{,}000 \;\land\; \text{FinalStageOfThreeStageLine}_i \end{aligned} \\[10pt] \text{FALSE}, & \text{caso contrário} \end{cases} \]
Sendo:
df_pokemon <- df_pokemon %>%
mutate(PseudoLegendary = (rowSums(across(c(5:10)), na.rm = TRUE) >= 600) & !Legendary & !Mythical & ExpGrowth == 1250000) %>%
select(ID, Generation, Name, Type1, Type2, Classification, HP, Attack, Defense, SpAtk, SpDef, Speed, Legendary, Mythical, PseudoLegendary, ExpGrowth, percentageMale, everything())
df_pokemon %>% filter(PseudoLegendary) %>% select(c(Name, ExpGrowth, Classification))
Esses critérios foram aqui usados (com exceção do último, já que os datasets não apresentavam essa informação e ela não foi necessária) para definir uma coluna adicional justamente para definir quais Pokémon são Pseudo-Lendários.
df_pokemon %>%
filter(PseudoLegendary)%>%
select(Name, Type1, Type2, PseudoLegendary, Generation) %>%
datatable(
options = list(
pageLength = 5,
autoWidth = TRUE
),
caption = "Pokémon Pseudo-Lendários")
Análisando os resultados advindos dessas databases podemos ver um pokémon que normalmente não é listado como um pseudo-lendário: Slaking.
Ele aparece na listagem anteriormente apresentada porque de fato ele cumpre todos os requisitos para ser um Pseudo-lendário. O único ponto que faz com que ele não seja considerado como tal pela comunidade é a sua habilidade “Truant” (livremente traduzido para “Gazeador”), que faz com que ele não seja um Pokémon tão forte quanto os demais.
Effect: Truant causes the ability-bearer to only attack every alternate turn. On the even turns, it will say the Pokémon is loafing around.
Em Pokémon, há várias tipagens diferentes para os Pokémon, isso não é apenas mais uma características deles como também é uma forma que definir quais são mais fortes entre si por natureza. (Bulbapedia contributors 2025f)
Cada tipo de Pokémon possui diferentes níveis de efetividade em relação a outros tipos. Além disso, um Pokémon pode ter até dois tipos, e as vantagens ou desvantagens se combinam, podendo se somar ou se anular conforme a combinação.
A efetividade total de um ataque de determinado tipo contra um Pokémon é calculada multiplicando as efetividades correspondentes a cada um dos tipos do Pokémon defensor. (Bulbapedia contributors 2025g)
\[ \text{TypeEffectiveness} = \text{EType1} \times \text{EType2} \] Sendo:
Por exemplo, um movimento do tipo Voador contra o Pokémon Parasect seria calculado como:
\[ \text{TypeEffectiveness} = 2\text{ (Voador x Inseto)} \times 2\text{ (Voador x Planta)} = 4 \]
df_pokemon %>%
filter(Name == "Parasect") %>%
select(Name, Type1, Type2, againstFlying) %>%
knitr::kable(
align = "c"
)
| Name | Type1 | Type2 | againstFlying |
|---|---|---|---|
| Parasect | Bug | Grass | 4 |
Ou mesmo, um ataque do tipo psíquico com o Pokémon Pangoro:
\[ \text{TypeEffectiveness} = 2\text{ (Psíquico x Lutador)} \times 0\text{ (Psíquico x Noturno)} = 0 \]
df_pokemon %>%
filter(Name == "Pangoro") %>%
select(Name, Type1, Type2, againstPsychic) %>%
knitr::kable(
align = "c"
)
| Name | Type1 | Type2 | againstPsychic |
|---|---|---|---|
| Pangoro | Fighting | Dark | 0 |
\[ \text{Damage} = \left( \frac {\frac{(2 \times \text{Level} \times \text{Critical})}{5} + 2) \times \text{Power} \times \frac{A}{D}}{50} + 2 \right) \times \text{STAB} \times \text{Type} \times \text{random} \]
\[ \text{Type} = \text{Type1 Effectiveness} + \text{Type2 Effectiveness} \]
Algumas mecânicas em Pokémon são determinadas por alguns fatores específicos mas também tem um pouco de aleatoriedade envolvida, vamos ver alguns adiante:
O dano causado por um ataque em Pokémon é determinado por uma fórmula que leva em consideração múltiplos fatores — como o nível do atacante, seu poder de ataque, o poder defensivo do alvo, o tipo do movimento e até elementos de aleatoriedade. (Bulbapedia contributors 2025b)
\[ \text{Damage} = \left( \frac{((2 \times \text{Level} / 5 + 2) \times \text{Power} \times \frac{A}{D})}{50} + 2 \right) \times \text{Modifier} \]
Sendo:
, que por sua vez: - STAB (Same Type Attack Bonus) é
1.5× se o tipo do ataque for o mesmo tipo do atacante.
- TypeEffectiveness é o multiplicador baseado nas
relações de tipo definito na seção de Tipagem (ex: 2×, 0.5×, 0×).
- Critical: se for um golpe crítico, multiplica o dano
por 1.5×.
- Random: fator aleatório entre 0.85 e
1.00.

A captura de um Pokémon selvagem depende de vários fatores, resumidos na seguinte fórmula(Bulbapedia contributors 2025a):
\[ a = \left(\frac{3 \times \text{MaxHP} - 2 \times \text{CurrentHP}}{3 \times \text{MaxHP}}\right) \times \text{CatchRate} \times \text{BallBonus} \times \text{StatusBonus} \]
Sendo:
Exemplos de modificadores de Pokébola comuns:
Se \(a \ge 255\), a captura é garantida; caso contrário, o jogo calcula a probabilidade real de sucesso com base em um número aleatório gerado internamente.
A aproximação usada nas gerações clássicas é dada por:
\[ \text{CaptureProbability} \approx \frac{\text{StatusCondition}}{\text{Ball} + 1} + \left(\frac{(\text{CatchRate} + 1)}{\text{Ball} + 1} \times \frac{(f + 1)}{256}\right) \]
onde:
\[ \text{StatusCondition} = \begin{cases} \frac{1}{2}, & \text{se estiver envenenado, queimado ou paralisado} \\[6pt] \frac{5}{2}, & \text{se estiver dormindo ou congelado} \\[6pt] 0, & \text{caso contrário} \end{cases} \]
\[ \text{Ball} = \begin{cases} 255, & \text{Poké Ball} \\[6pt] 200, & \text{Great Ball} \\[6pt] 150, & \text{Ultra ou Safari Ball} \end{cases} \]
O termo \(f\) depende dos pontos de vida e da bola utilizada, refletindo o quanto o Pokémon foi enfraquecido durante a batalha.
Em resumo, o processo de captura e de batalha combina fatores determinísticos — como HP atual, tipo de bola e condição de status — com um elemento de aleatoriedade.