1. Kütüphanelerin Yüklenmesi

Analiz için gerekli olan kütüphaneler yükleniyor.

library(tidyverse)
# tidyverse paketi veri manipülasyonu ve okuma işlemleri için yükleniyor. Python'daki pandas kütüphanesine karşılık gelir.

library(ggplot2)
# ggplot2 paketi görselleştirme işlemleri için yükleniyor. Python'daki matplotlib ve seaborn kütüphanelerine benzer işlevler sunar.

library(corrplot)
# corrplot paketi korelasyon matrislerini görselleştirmek için kullanılır.

library(caTools)
# caTools paketi veri setini train ve test olarak bölmek için kullanılır.

library(car)
# car paketi VIF (Variance Inflation Factor) testini hesaplamak için gereklidir. Çoklu bağıntı problemini tespit etmeye yarar.

library(lmtest)
# lmtest paketi Breusch-Pagan ve Durbin-Watson gibi istatistiksel testleri yapmak için kullanılır.

# install.packages("fastDummies") 
# Not: Paket zaten yüklüyse install satırını yorum satırı yapabilirsiniz.
# fastDummies paketi kategorik değişkenleri dummy değişkenlere dönüştürmek için yükleniyor.

library(fastDummies)
# fastDummies paketi one-hot encoding işlemi için aktif hale getiriliyor.

2. Veri Yükleme ve Genel Bakış

df <- read.csv("insurance.csv")
# Kullanıcıdan bir CSV dosyası seçmesi isteniyor ve bu dosya df isimli bir veri çerçevesine yükleniyor.

cat("Veri Seti Boyutu:", dim(df), "\n")
## Veri Seti Boyutu: 1338 7
# Veri setinin boyutu yani satır ve sütun sayısı ekrana yazdırılıyor.

print(head(df))
##   age    sex    bmi children smoker    region   charges
## 1  19 female 27.900        0    yes southwest 16884.924
## 2  18   male 33.770        1     no southeast  1725.552
## 3  28   male 33.000        3     no southeast  4449.462
## 4  33   male 22.705        0     no northwest 21984.471
## 5  32   male 28.880        0     no northwest  3866.855
## 6  31 female 25.740        0     no southeast  3756.622
# Veri setinin ilk 6 satırı ekrana yazdırılarak veriye genel bir bakış sağlanıyor.

3. Eksik Veri ve Aykırı Değer Analizi

cat("\n--- Eksik Veri Sayıları ---\n")
## 
## --- Eksik Veri Sayıları ---
# Eksik veri kontrolü için bir başlık yazdırılıyor.

print(colSums(is.na(df)))
##      age      sex      bmi children   smoker   region  charges 
##        0        0        0        0        0        0        0
# Her sütundaki eksik veri sayısı hesaplanıp ekrana yazdırılıyor.

numeric_cols <- c("age", "bmi", "children", "charges")
# Sayısal değişkenlerin isimleri bir vektörde toplanıyor. Bu değişkenler üzerinde aykırı değer analizi yapılacak.

cat("\n--- Aykırı Değer Analizi (IQR) ---\n")
## 
## --- Aykırı Değer Analizi (IQR) ---
# Aykırı değer analizi için başlık yazdırılıyor.

for(col in numeric_cols) {
  # Sayısal her sütun için döngü başlatılıyor.
  
  Q1 <- quantile(df[[col]], 0.25)
  # Birinci çeyrek değeri yani %25'lik dilim hesaplanıyor.
  
  Q3 <- quantile(df[[col]], 0.75)
  # Üçüncü çeyrek değeri yani %75'lik dilim hesaplanıyor.
  
  IQR <- Q3 - Q1
  # Çeyrekler arası açıklık IQR hesaplanıyor. Bu değer aykırı değer tespitinde kullanılır.
  
  lower <- Q1 - 1.5 * IQR
  # Alt sınır hesaplanıyor. Bu sınırın altındaki değerler aykırı kabul edilir.
  
  upper <- Q3 + 1.5 * IQR
  # Üst sınır hesaplanıyor. Bu sınırın üstündeki değerler aykırı kabul edilir.
  
  outliers <- df[[col]][df[[col]] < lower | df[[col]] > upper]
  # Alt veya üst sınırın dışında kalan değerler outliers vektörüne atanıyor.
  
  cat(col, ":", length(outliers), "adet aykırı değer bulundu.\n")
  # Her değişken için bulunan aykırı değer sayısı ekrana yazdırılıyor.
}
## age : 0 adet aykırı değer bulundu.
## bmi : 9 adet aykırı değer bulundu.
## children : 0 adet aykırı değer bulundu.
## charges : 139 adet aykırı değer bulundu.

4. Veri Ön İşleme (Encoding)

df <- df %>%
  mutate(
    sex_encoded = ifelse(sex == "male", 1, 0),
    smoker_encoded = ifelse(smoker == "yes", 1, 0)
  )
# sex değişkeni için male ise 1, female ise 0 değeri atanıyor. smoker değişkeni için yes ise 1, no ise 0 değeri atanıyor. Bu işlem binary encoding olarak bilinir.

df <- dummy_cols(df, select_columns = "region", remove_first_dummy = TRUE)
# region değişkeni için one-hot encoding yapılıyor. remove_first_dummy parametresi ile ilk dummy değişken çıkarılarak çoklu bağıntı probleminden kaçınılıyor.

names(df) <- make.names(names(df))
# Sütun isimlerindeki boşluk, tire gibi karakterler R'ın kurallarına uygun hale getiriliyor.

5. Görselleştirme ve Korelasyon

selected_cols <- c("age", "bmi", "children", "charges", "sex_encoded", "smoker_encoded")
# Korelasyon analizi için kullanılacak sayısal sütunlar seçiliyor.

cor_matrix <- cor(df[, selected_cols])
# Seçilen sütunlar arasındaki korelasyon matrisi hesaplanıyor.

corrplot(cor_matrix, method = "color", type = "upper", 
         addCoef.col = "black", tl.col = "black", title = "Korelasyon Matrisi")

# Korelasyon matrisi renkli bir ısı haritası şeklinde görselleştiriliyor. Sadece üst üçgen gösteriliyor ve korelasyon katsayıları siyah yazı ile ekleniyor.

ggplot(df, aes(x = smoker, y = charges, fill = smoker)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "Sigara Kullanımına Göre Maliyet Dağılımı")

# Sigara kullanan ve kullanmayan kişilerin sigorta maliyetlerinin dağılımı kutu grafiği ile görselleştiriliyor.

6. Veri Setini Bölme (Train/Test Split)

df$sex    <- as.factor(df$sex)
# sex değişkeni faktör tipine dönüştürülüyor. Bu kategorik değişkenlerin modelde doğru işlenmesini sağlar.

df$smoker <- as.factor(df$smoker)
# smoker değişkeni faktör tipine dönüştürülüyor.

df$region <- as.factor(df$region)
# region değişkeni faktör tipine dönüştürülüyor.

set.seed(145)
# Rastgele sayı üreteci için tohum değeri belirleniyor. Bu sonuçların tekrarlanabilir olmasını sağlar.

sampleindx <- sample(1:nrow(df), size = 0.80 * nrow(df))
# Veri setinin satır numaralarından rastgele %80'i seçiliyor. Bu indeksler train seti için kullanılacak.

trainset <- df[sampleindx, ]
# Seçilen indekslerdeki satırlar train setine atanıyor.

testset  <- df[-sampleindx, ]
# Seçilmeyen indekslerdeki satırlar test setine atanıyor.

cat("Train Set Boyutu:", nrow(trainset), "\n")
## Train Set Boyutu: 1070
# Train setindeki satır sayısı ekrana yazdırılıyor.

cat("Test Set Boyutu :", nrow(testset), "\n")
## Test Set Boyutu : 268
# Test setindeki satır sayısı ekrana yazdırılıyor.

7. Modelleme

model1 <- lm(charges ~ age + bmi + children + sex + smoker + region, data = trainset)
# Lineer regresyon modeli oluşturuluyor. charges bağımlı değişken, diğerleri bağımsız değişkenler olarak kullanılıyor.

summary(model1)
## 
## Call:
## lm(formula = charges ~ age + bmi + children + sex + smoker + 
##     region, data = trainset)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -11042.9  -2762.4   -847.2   1332.2  25944.7 
## 
## Coefficients:
##                   Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     -12392.959   1057.582 -11.718  < 2e-16 ***
## age                263.996     12.802  20.622  < 2e-16 ***
## bmi                331.190     30.483  10.865  < 2e-16 ***
## children           469.982    149.108   3.152  0.00167 ** 
## sexmale            -75.009    357.784  -0.210  0.83398    
## smokeryes        23748.810    448.020  53.008  < 2e-16 ***
## regionnorthwest      9.984    507.536   0.020  0.98431    
## regionsoutheast   -645.795    510.743  -1.264  0.20636    
## regionsouthwest   -551.467    513.830  -1.073  0.28340    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 5832 on 1061 degrees of freedom
## Multiple R-squared:  0.7642, Adjusted R-squared:  0.7624 
## F-statistic: 429.9 on 8 and 1061 DF,  p-value: < 2.2e-16
# Model özeti ekrana yazdırılıyor. Katsayılar, p-değerleri, R-kare değeri gibi istatistikler görülebilir.

8. Varsayım Kontrolleri

cat("\n--- VIF Değerleri ---\n")
## 
## --- VIF Değerleri ---
# VIF analizi için başlık yazdırılıyor.

vif_values <- vif(model1)
# Her bağımsız değişken için VIF değerleri hesaplanıyor. VIF değeri yüksek olan değişkenler çoklu bağıntı problemi yaşıyor demektir.

print(vif_values)
##              GVIF Df GVIF^(1/(2*Df))
## age      1.017100  1        1.008514
## bmi      1.097589  1        1.047659
## children 1.004480  1        1.002237
## sex      1.006471  1        1.003230
## smoker   1.010381  1        1.005177
## region   1.092154  3        1.014800
# VIF değerleri ekrana yazdırılıyor.

if(any(vif_values > 5)) cat("UYARI: 5'ten büyük VIF değeri var!\n") else cat("Multicollinearity sorunu görünmüyor.\n")
## Multicollinearity sorunu görünmüyor.
# Eğer herhangi bir VIF değeri 5'ten büyükse uyarı mesajı, değilse sorun olmadığına dair mesaj yazdırılıyor.

residuals <- residuals(model1)
# Modelin kalıntıları yani gerçek değerler ile tahmin edilen değerler arasındaki farklar hesaplanıyor.

shapiro_res <- shapiro.test(residuals[1:5000])
# Kalıntıların normal dağılıma uyup uymadığını test etmek için Shapiro-Wilk testi yapılıyor. R'da maksimum 5000 gözlem ile sınırlı.

cat("\n--- Shapiro-Wilk Normallik Testi ---\n")
## 
## --- Shapiro-Wilk Normallik Testi ---
# Shapiro-Wilk testi için başlık yazdırılıyor.

print(shapiro_res)
## 
##  Shapiro-Wilk normality test
## 
## data:  residuals[1:5000]
## W = 0.90372, p-value < 2.2e-16
# Test sonucu ekrana yazdırılıyor. p-değeri 0.05'ten küçükse kalıntılar normal dağılmıyor demektir.

cat("\n--- Breusch-Pagan Testi ---\n")
## 
## --- Breusch-Pagan Testi ---
# Breusch-Pagan testi için başlık yazdırılıyor.

print(bptest(model1))
## 
##  studentized Breusch-Pagan test
## 
## data:  model1
## BP = 120.92, df = 8, p-value < 2.2e-16
# Hata terimlerinin varyansının sabit olup olmadığını test eden Breusch-Pagan testi yapılıyor. p-değeri küçükse heteroskedastisite var demektir.

cat("\n--- Durbin-Watson Testi ---\n")
## 
## --- Durbin-Watson Testi ---
# Durbin-Watson testi için başlık yazdırılıyor.

print(dwtest(model1))
## 
##  Durbin-Watson test
## 
## data:  model1
## DW = 1.9543, p-value = 0.2265
## alternative hypothesis: true autocorrelation is greater than 0
# Hata terimleri arasında otokorelasyon olup olmadığını test eden Durbin-Watson testi yapılıyor. Değer 2'ye yakınsa otokorelasyon yok demektir.

par(mfrow = c(2, 2))
# Grafik penceresini 2x2'lik bir ızgaraya bölerek 4 grafiği aynı anda göstermeye hazırlıyor.

plot(model1)

# Modelin varsayım kontrolü için dört standart grafik çizdiriliyor. Residuals vs Fitted, Normal Q-Q, Scale-Location ve Residuals vs Leverage grafikleri oluşur.

par(mfrow = c(1, 1))
# Grafik penceresini tekrar normal tek grafik moduna döndürüyor.

9. Test Seti Performans Değerlendirmesi

predictions <- predict(model1, newdata = testset)
# Eğitilmiş model kullanılarak test seti üzerinde tahminler yapılıyor.

rmse_val <- sqrt(mean((testset$charges - predictions)^2))
# Root Mean Squared Error hesaplanıyor. Tahmin hatalarının ortalama büyüklüğünü gösterir.

mae_val <- mean(abs(testset$charges - predictions))
# Mean Absolute Error hesaplanıyor. Tahmin hatalarının mutlak değerlerinin ortalamasıdır.

r2_val <- summary(lm(predictions ~ testset$charges))$r.squared
# Test seti için R-kare değeri hesaplanıyor. Modelin açıklama gücünü gösterir.

cat("\n--- Test Seti Performansı ---\n")
## 
## --- Test Seti Performansı ---
# Test seti performans metrikleri için başlık yazdırılıyor.

cat("RMSE:", round(rmse_val, 2), "\n")
## RMSE: 6918.29
# RMSE değeri yuvarlanarak ekrana yazdırılıyor.

cat("MAE :", round(mae_val, 2), "\n")
## MAE : 4691.27
# MAE değeri yuvarlanarak ekrana yazdırılıyor.

cat("R²  :", round(r2_val, 4), "\n")
## R²  : 0.7036
# R-kare değeri yuvarlanarak ekrana yazdırılıyor.