# Betimsel Analiz R'da analiz için önce veri seti kaynağı olarak [buradaki](https://www.kaggle.com/datasets/mariotormo/complete-pokemon-dataset-updated-090420) bağlantıyı kullandım. Sanırım son çıkan Arceus vb. yeniler yok ama temelde analiz için yeterli, sekiz jenerasyonu kapsıyor. Dosya menüsünden içe aktarabileceğiniz gibi aşağıdaki kod ile de csv dosyasını aktarmak mümkün. Ben Almanca ve Japonca adları ile ilk sütundaki sıra numalarını çıkarttım. Basit regresyonlarla veya analizlerle başlayıp nihayetinde ML için veri setinin rastgele bölüp eğitmek anlamlı olacak diye düşünüyorum. Kabaca ggplot, tidyverse, PerformanceAnalytics, rpart, ROCR, car paketleri ve muhtemelen fazlası gerekecek. ```R library(readr) pokedex <- read_csv("Downloads/archive/pokedex_(Update_04.21).csv", col_types = cols(...1 = col_skip(), german_name = col_skip(), japanese_name = col_skip())) ``` ```R colnames(pokedex) ``` ````` [1] "pokedex_number" "name" "generation" "status" "species" "type_number" "type_1" "type_2" "height_m" [10] "weight_kg" "abilities_number" "ability_1" "ability_2" "ability_hidden" "total_points" "hp" "attack" "defense" [19] "sp_attack" "sp_defense" "speed" "catch_rate" "base_friendship" "base_experience" "growth_rate" "egg_type_number" "egg_type_1" [28] "egg_type_2" "percentage_male" "egg_cycles" "against_normal" "against_fire" "against_water" "against_electric" "against_grass" "against_ice" [37] "against_fight" "against_poison" "against_ground" "against_flying" "against_psychic" "against_bug" "against_rock" "against_ghost" "against_dragon" [46] "against_dark" "against_steel" "against_fairy" ````` Pokédex'teki sırası, isim, jenerasyon, türü, boy/kilo/cinsiyet vb., yetenekler, hp, atak, savunma, özel atak vb. gibi birçok değişken ve diğer türlere karşı saldırılarının etkisini gösteren çeşitli katsayılar mevcut. Örneğin ggplot2 ile türlere göre dağılımı görmek istiyorum. Bu arada bu kısımda chatGPT el attı örneğin, kodu oluşturmasını istedim. İlgili kısım [burada](https://chat.openai.com/share/a717c888-2153-41c3-9f99-5b16f168869f). ```R library(ggplot2) # Define a custom color palette inspired by Pokemon brand colors pokemon_colors <- c("#A8A77A", "#EE8130", "#6390F0", "#F7D02C", "#7AC74C", "#96D9D6", "#C22E28", "#A33EA1", "#E2BF65", "#A98FF3", "#F95587", "#A6B91A", "#B6A136", "#735797", "#6F35FC", "#705746", "#D685AD", "#B7B7CE") # Count the number of Pokemon for each type type_counts <- table(pokedex$type_1) # Create a data frame with type and cumulative count type_data <- data.frame(type = names(type_counts), count = cumsum(type_counts)) # Sort the data frame by cumulative count in descending order type_data <- type_data[order(type_data$count, decreasing = TRUE), ] # Create the bar plot with custom colors ggplot(data = type_data, aes(x = type, y = count)) + geom_bar(stat = "identity", fill = pokemon_colors) + xlab("Pokemon Type") + ylab("Cumulative Count") + ggtitle("Distribution of Pokemon Types") + theme_minimal() + theme(axis.text.x = element_text(angle = 45, hjust = 1), panel.background = element_rect(fill = "#F2F2F2"), plot.background = element_rect(fill = "#F2F2F2"), plot.title = element_text(hjust = 0.5), axis.line = element_line(color = "#333333"), axis.text = element_text(color = "#333333"), axis.title = element_text(color = "#333333")) ``` ![[FzigICJWYAAwBnm.png]] Burada birincil türlerin (type_1) toplamlarının karşılaştırması görünüyor, aslında aynı anda iki tür olanlar da mevcut hatta birçoğu öyle, alttaki eleman gibi örneğin (bug + flying). ![[d8nn8jh-fd57990e-2362-4198-97fd-fa47243ec378.png|300]] Mesela en ağır üç Pokémon'a bakmak istiyorum. ```R # ağırlığa göre azalan şekilde dizdik sorted_pokedex <- pokedex[order(pokedex$weight_kg, decreasing = TRUE), ] # ilk üç satıra karşılık gelen isimleri çektik enagir3 <- sorted_pokedex[1:3, "name"] print(enagir3) ``` ````` # A tibble: 3 × 1 name <chr> 1 Cosmoem 2 Celesteela 3 Primal Groudon ````` Üsttekileri hiç duymadım, Groudon 7-8 sene önce Ruby'deydi sanırım ama o da değişmiş bir şeyler olmuş. Elimiz değmişken en kısalara da bakalım. ```R # boya göre artan şekilde dizdik sorted_pokedex <- pokedex[order(pokedex$height_m, decreasing = FALSE), ] # ilk üç satıra karşılık gelen isimleri çektik enkisa3 <- sorted_pokedex[1:3, "name"] print(enkisa3) ``` ````` # A tibble: 3 × 1 name <chr> 1 Joltik 2 Flabébé 3 Cutiefly ````` ![[R.0148fe7dbc27040e25787d677724d14c.png|100]] *En kısa buymuş.* # Regresyon Regresyonla ilgili farklı yaklaşımlar var. Mesela Python'da [burada](https://www.kaggle.com/code/mmetter/pokemon-data-analysis-tutorial/notebook) benzer bir seti savaş kazanma oranlarına göre incelemiş. Temel aldığı yaklaşım ise [R'da yapılmış](https://www.kaggle.com/code/rtatman/which-pokemon-win-the-most/notebook) ve detaylı bir analizi [paylaşmış](https://www.kaggle.com/code/mmetter/pokemon-data-analysis-tutorial/notebook). Ben makine öğrenmesi kısmında bu yoldan gitmeyeceğim ama [şurada](https://towardsdatascience.com/introduction-to-machine-learning-with-pokemon-ccb7c9d1351b) da efsanevi özelliğe sahip olmayı etkileyen faktörlere bakılmış ve model oluşturmuş, efsanevi olmak ya da olmamak tüm mesele olduğu için lojistik regresyon iş görmüş. ### Basit Regresyon: Mümkün mü? (Anlamlı mı?) Biz Red ya da Blue'yı oynarken ya da çizgi filmi izlerken atak, defans vb. değerlerine ya da savaştaki faktörlere bakmazdık ama bu oyunu profesyonel şekilde oynayanlar için oradaki virgülün sonrası bile çok önemliymiş turnuvalarda. Bizim elimizdeki veri setinde de doğrudan oyundaki performansı etkileyecek bazı değişkenler var. Bu arada oyunda kullandığınız top, kalan HP vb. birçok faktör de etkili, aslında hemen hemen random bir sürece bakıyoruz bazen. Benim aklıma ilk olarak yakalanma oranı ile bu değişkenler arasındaki ilişki gelmişti ama göründüğünden daha komplike bir mekanizma varmış. Örneğin ilk jenerasyonda status zehir, paraliz vb.; ballMode ise topun özelliğini (normal, great, ultra, safari hatta master için %100 ) ifade etmek üzere; $ p_0 = \frac{status}{ballMode+1} $ Üstteki fonksiyonu aşağıdaki f değerine yerleştirdiğimizde yakalama ihtimalini elde etmiş oluyoruz ki dataframe içinde catchRate de mevcut. $ p_1 = \frac{catchRate+1}{ballMode+1} x \frac{f+1}{256} $ Son jenerasyonda ise durum şu, arada yaklaşık yedi kez evrim geçiren bir fonksiyon bu: $ a = \dfrac{[3*HP_{max}] - 2*HP_{current}}{[3*HP_{max}]}*4096*darkGrass*rate_{modified}*bonus_{ball}*badgePenalty$ $ P = a*bonus_{level}*bonus_{status}*bonus_{misc} $ Sonuç olarak aslında catchRate değişkeninin rolü fazla değil ama modeli eğitmeyi denemek açısından faydalı olabilir. Üsttekilerle ilgili detaylı bilgi [şurada](https://bulbapedia.bulbagarden.net/wiki/Catch_rate) var, nasıl hesaplamışlar incelemek eğlenceli olabilir, acı çekmeyi seviyorsanız. Yine de dinamik olması ilgi çekici. ![[3160_pikachu_tears.png|100]] ### Regresyon Fikirlerine Devam Üstteki bağlantılardaki efsanevi olma özelliği aslında düz bir mantıkla en kolayıydı lojistik regresyon üstünden ki ML için de kullanmışlar. Farklı olsun mantığıyla her ne kadar yakalama olasılığını tek başına belirlemese de, diğer değişkenlerin ise catchRate üzerinde etkisi var mı diye bakmaya karar verdim. Aslında pokemon fiziksel bir tür ise atak ve defansı belirleyici olurken bazı türlerde sp. atk veya sp. defense öne çıkıyor. Fiziksel saldırıların hasarı ilk ikisiyle, türüne bağlı olanlar ise ikinci grup ile belirleniyor. Dönem dönem oyunlarda ve kart turnuvalarında belirli metalar oluşuyor yani. Atk., Sp Atk. Def. ve Sp. Def. ile HP toplamı "total_points" kolonunda yer alıyor veride. *Acaba bu kolondaki değerler ile catchRate arasında anlamlı bir ilişki var mı?* Regresyondan önce kısaca bir dağılıma bakmak gerekebilir. ```R library(car) # Normal dağılım için Shapiro-Wilk testi shapiro.test(pokedex$total_points) shapiro.test(pokedex$catch_rate) ``` ````` Shapiro-Wilk normality test data: pokedex$total_points W = 0.97756, p-value = 1.25e-11 Shapiro-Wilk normality test data: pokedex$catch_rate W = 0.83663, p-value < 2.2e-16 ````` Katsayı 1'e yaklaştıkça en azından toplam değer değişkeninde normal dağılıma yaklaşsak da p değerleri her ikisinde de o kadar düşük ki muhtemelen bu iki değişken normal bir dağılım izlemiyor, zaten beklenen bir şey çünkü veri setinin rasyonel bir şekilde belirlendiğini düşünmek hata olur. Bu analizin güvenilirliği açısından biraz sıkıntıya işaret etse de hemen alttaki grafikler bu sıkıntı için şu an üzülmek yerine en azından bir parça doğru kabul etsek ne olurdu diye düşünebileceğimizi gösteriyor (ileride dert etmek kaydıyla). Korelasyona da bakalım. ```R cor_result <- cor.test(pokedex$total_points, pokedex$catch_rate) print(cor_result) ``` ````` t = -33.976, df = 1025, p-value < 2.2e-16 alternative hypothesis: true correlation is not equal to 0 95 percent confidence interval: -0.7553329 -0.6976769 sample estimates: cor -0.7277883 ````` Aralarında negatif yönlü ve ciddi (-0.727, < 2.2e-16) bir korelasyon olduğunu görüyoruz, yani Pokémonun değerleri arttıkça yakalama katsayısı azalıyor. Bunu zaten bekliyorduk. Bakalım nasıl? Bu arada 18 N/A değeri diğer kolonlardaki bazı eksiklerden geliyordu ama hangisiydi unuttum. Dünyayı kurtarmadığımız için pek de dert etmedim şu an. ```R lm_model <- lm(catch_rate ~ total_points, data = pokedex) summary(lm_model) ``` ````` lm(formula = catch_rate ~ total_points, data = pokedex) Residuals: Min 1Q Median 3Q Max -157.337 -24.842 -5.802 30.262 277.670 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 294.17730 6.14744 47.85 <2e-16 *** total_points -0.45920 0.01352 -33.98 <2e-16 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 52.06 on 1025 degrees of freedom (18 observations deleted due to missingness) Multiple R-squared: 0.5297, Adjusted R-squared: 0.5292 F-statistic: 1154 on 1 and 1025 DF, p-value: < 2.2e-16 ````` Bakıldığı zaman F ve p değerleri bir ilişkiyi ifade ediyor, benzer şekilde katsayı da anlamlı, en azından değişimin %52'si hakkında bir fikrimiz var. Ne yazık ki dağılım ileride sıkıntı yaratabilir ve model işlevsiz kalabilir, sonraki aşamada çözmek lazım. ![[Rplotpk1.png]] ![[Rplotpk2.png]] Üstteki modeldeki değişkenler için ciddi derecede heteroskedasitisite sorunu olduğu için bir şekilde arındırmak gerekiyor, logaritma pek işe yaramadı ve Box-Cox denedim. Detaylı bilgi [burada](https://www.statisticshowto.com/probability-and-statistics/normal-distributions/box-cox-transformation/), aslında log mu yoksa kök kullanarak mı sorun daha iyi çözülüyor, o mantığa dayalı. ```R library(MASS) boxcox_model <- boxcox(lm(catch_rate ~ total_points, data = pokedex)) lambda <- boxcox_model$x[which.max(boxcox_model$y)] pokedex$transformed_catch_rate <- (pokedex$catch_rate^lambda - 1) / lambda lm_model <- lm(transformed_catch_rate ~ total_points, data = pokedex) ``` Brausch-Pagan ile bakıyoruz (üstteki model için p değeri 2.2e-16'dı). ```R library(lmtest) bp_test <- bptest(lm_model) print(bp_test) ``` ````` studentized Breusch-Pagan test data: lm_model BP = 1.6075, df = 1, p-value = 0.2048 ````` p değeri (0.2) > 0.05 yani en azından varyansla ilgili sorun giderilmiş gözüküyor (grafiğe bakınca mükemmel değil, neyse R kare biraz arttı bari). ````` lm(formula = transformed_catch_rate ~ total_points, data = pokedex) Residuals: Min 1Q Median 3Q Max -13.8447 -1.7755 0.4065 2.0538 16.1424 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 24.5210205 0.3766790 65.10 <2e-16 *** total_points -0.0310326 0.0008282 -37.47 <2e-16 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 3.19 on 1025 degrees of freedom (18 observations deleted due to missingness) Multiple R-squared: 0.578, Adjusted R-squared: 0.5776 F-statistic: 1404 on 1 and 1025 DF, p-value: < 2.2e-16 ````` ![[Rplotpk4.png]] En azından bu model temel alınarak ve üzerinde oynayarak bir şeyler denenebilir diye düşünüyorum. Modeli iyileştirme ya da belki bambaşka bir model oluşturma konusunda ML yardımcı olabilir, muhtemelen bazı önemli değişkenleri henüz dahil etmedim. # ML ve Model Arayışı