R’da lojistik regresyon çalıştırma

Lojistik regresyon, y kategorik bir değişken olduğunda y = f (x) regresyon eğrisini yerleştirmek için bir yöntemdir . Bu modelin tipik kullanımı, bir grup yordayıcı x verildiğinde y‘yi tahmin etmektir. bağımsız değişkenler sürekli, kategorik veya her ikisinin bir karışımı olabilir.

Kategorik değişken y , genel olarak farklı değerler alabilir. En basit senaryoda y , ikili değerdir. Bu y’nin 1 veya 0 değerini alabileceği anlamına gelir. Makine öğreniminde kullanılan klasik bir örnek e-posta sınıflandırmasıdır: kelime, bağlantı ve resim sayısı gibi her e-posta için bir dizi özellik verildiğinde, algoritma, e-postanın spam olup (1) olmadığına (0) karar vermelidir. Bu yazıda modele, tahmin edilecek değişken ikili olduğu için “binom lojistik regresyon” diyoruz, ancak lojistik regresyon, 2’den fazla değer alabilen bağımlı bir değişkeni tahmin etmek için de kullanılabilir. Bu ikinci durumda, modele “çok terimli lojistik regresyon” diyoruz. Örneğin tipik bir örnek, filmleri “Eğlenceli”, “sınır çizgisi” veya “sıkıcı” arasında sınıflandırmak olabilir.

R’de lojistik regresyon uygulaması

R, lojistik regresyon modelini uydurma işlemini çok kolaylaştırır. Çağrılacak fonksiyon glm() ve uydurma işlemi doğrusal regresyonda kullanılandan çok farklı değildir. Bu yazıda bir ikili lojistik regresyon modeli uyduracağım ve her adımı açıklayacağım.

Veri kümesi

Titanik veri seti üzerinde çalışacağız . Bu veri setlerinin çevrimiçi olarak farklı sürümleri mevcut, ancak Kaggle’da mevcut olanı kullanmanızı öneririm , çünkü neredeyse kullanıma hazır durumda (indirmek için Kaggle’a kaydolmanız gerekli).
Titanik veri seti  (eğitim amaçlı), bazı yolcularla (tam olarak 889) ilgili bir veri kümesi ve yarışmanın amacı, veri kümesindeki bazı özelliklere (hizmetin sınıfına , cinsiyet , yaş vb.) dayanarak yolcuların hayatta kalıp kalmamış olduklarını tahmin etmek (yolcu hayatta kaldıysa 1 ya da yoksa 0 gibi). Sizin de farkedebileceğiniz gibi, hem kategorik hem de sürekli değişkenler kullanacağız.

Veri temizleme işlemi

Gerçek bir veri kümesiyle çalışırken, bazı verilerin eksik veya kullanışsız olabileceğini dikkate almamız, bu nedenle veri kümesini analizimiz için hazırlamamız gerekir. İlk adım olarak csv verilerini read.csv() fonksiyonunu kullanarak yüklüyoruz . na.strings parametresinin c(“”) olduğundan emin olun. Bu, tüm eksik verilerin NA olarak kodlanmasını sağlayarak sonraki adımlarda bize yardımcı olacak.

training.data.raw <- read.csv('train.csv',header=T,na.strings=c(""))

Şimdi, eksik değerleri kontrol etmeli ve veri çerçevesinin her sütununa bağımsız değişken olarak iletilen fonksiyonu uygulayan sapply() fonksiyonunu kullanarak her değişken için kaç tekil değer olduğunu görmeliyiz.

sapply(training.data.raw,function(x) sum(is.na(x)))

PassengerId    Survived      Pclass        Name         Sex 
          0           0           0           0           0 
        Age       SibSp       Parch      Ticket        Fare 
        177           0           0           0           0 
      Cabin    Embarked 
        687           2 

sapply(training.data.raw, function(x) length(unique(x)))

PassengerId    Survived      Pclass        Name         Sex 
        891           2           3         891           2 
        Age       SibSp       Parch      Ticket        Fare 
         89           7           7         681         248 
      Cabin    Embarked 
        148           4

Eksik değerlerin görsel olarak incelenmesi yararlı olabilir: Amelia paketinde veri kümemizi çizecek ve eksik değerleri vurgulayacak missmap() şeklinde özel bir çizim işlevi mevcut.

library(Amelia)
missmap(training.data.raw, main = "Missing values vs observed")

Grafikten de gördüğümüz üzere “Cabin” değişkeninde çok fazla eksik değer var, bu yüzden onu kullanmayacağız. PassengerId’i de sadece bir dizin olduğu için bırakacağız. subset() fonksiyonunu kullanarak veri kümesinden yalnızca ilgileneceğimiz sütunları içeren bir alt küme oluşturuyoruz.

data <- subset(training.data.raw,select=c(2,3,5,6,7,8,10,12))

Eksik değerlerle ilgilenmek

Şimdi diğer eksik değerleri hesaba katmamız gerekiyor. R, genelleştirilmiş bir doğrusal modeli uydururken, fonksiyonunun içindeki bir parametreyi ayarlayarak eksik değerlerle kolayca başa çıkabiliyor. Ancak, ben NA’ları mümkün olduğunca “elle” değiştirmeyi tercih ediyorum . Bunu yapmanın farklı yolları mevcut, örneğin bilindik bir uygulama eksik değerleri mevcut değerlerin ortalaması, medyanı veya mevcut mod ile değiştirmektir. Ben ortalamayı kullanacağım.

 
data$Age[is.na(data$Age)] <- mean(data$Age,na.rm=T)

Kategorik değişkenler söz konusu olduğunda, read.table() veya read.csv() fonksiyonları varsayılan olarak kullanılması kategorik değişkenleri faktörler olarak kodlayacaktır. Faktör, R’nin kategorik değişkenleri nasıl ele aldığıdır. Aşağıdaki kod satırlarını kullanarak kodlamayı kontrol edebiliriz:

is.factor(data$Sex)
TRUE

is.factor(data$Embarked)
TRUE

R’nin kategorik değişkenlerle nasıl başa çıkacağını daha iyi anlamak için contrasts() fonksiyonunu kullanabiliriz . Bu fonksiyon bize değişkenlerin R tarafından nasıl kuklalaştırıldığını ve bir modelde nasıl yorumlanacağını gösterecektir.

contrasts(data$Sex)
       male
female    0
male      1

contrasts(data$Embarked)
  Q S
C 0 0
Q 1 0
S 0 1

Örneğin, cinsiyet değişkeninde bayanın referans olarak kullanılacağını görebilirsiniz. Embarked’daki eksik değerlere gelince, sadece iki tane olduğundan, bu iki satırı atacağız (eksik değerleri en çok tekrarlanan değer ile değiştirebilir ve verileri öylece saklayabiliriz).

data <- data[!is.na(data$Embarked),]
rownames(data) <- NULL

Model uydurma işlemine geçmeden önce , verilerin temizlenmesi ve biçimlendirilmesinin ne kadar önemli olduğunu tekrar söylemek isterim. Bu önişleme adımı genellikle modelin iyi bir uyum ve daha iyi öngörme yeteneği elde etmesi için çok önemlidir.

Model uydurma

Verileri iki parçaya ayırıyoruz: eğitim ve test seti. Eğitim seti, test seti üzerinde test edeceğimiz modelimizin elde edilmesinde kullanılacak.

train <- data[1:800,]
test <- data[801:889,]

Şimdi modeli yerleştirelim. glm() fonksiyonunda family = binomial parametresini belirttiğinizden emin olun.

 
model <- glm(Survived ~.,family=binomial(link='logit'),data=train)

summary() fonksiyonunu kullanarak modelimizin sonuçlarını görelim:

summary(model)

Call:
glm(formula = Survived ~ ., family = binomial(link = "logit"), 
    data = train)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-2.6064  -0.5954  -0.4254   0.6220   2.4165  

Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept)  5.137627   0.594998   8.635  < 2e-16 ***
Pclass      -1.087156   0.151168  -7.192 6.40e-13 ***
Sexmale     -2.756819   0.212026 -13.002  < 2e-16 ***
Age         -0.037267   0.008195  -4.547 5.43e-06 ***
SibSp       -0.292920   0.114642  -2.555   0.0106 *  
Parch       -0.116576   0.128127  -0.910   0.3629    
Fare         0.001528   0.002353   0.649   0.5160    
EmbarkedQ   -0.002656   0.400882  -0.007   0.9947    
EmbarkedS   -0.318786   0.252960  -1.260   0.2076    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 1065.39  on 799  degrees of freedom
Residual deviance:  709.39  on 791  degrees of freedom
AIC: 727.39

Number of Fisher Scoring iterations: 5

Lojistik regresyon modelimizin sonuçlarını yorumlama

Şimdi uydurulan modeli analiz edebilir ve bize ne söylediğini yorumlayabiliriz. Her şeyden önce, SibSp , Fare ve Embarked’ın istatistiksel olarak anlamlı olmadığını görebiliriz. İstatistiksel olarak anlamlı değişkenlere gelince, cinsiyet, yolcunun cinsiyetinin hayatta kalma olasılığı ile güçlü bir ilişkisi olduğunu gösteren en düşük p değerine sahip. Bu bağımsız değişkenin negatif katsayısı, diğer tüm değişkenlerin eşit olduğu durumda, erkek yolcunun hayatta kalma olasılığının daha düşük olduğunu göstermektedir. Logit modelinde bağımlı değişkeninin log olasılıkları olduğunu unutmayın: ln (odds) = ln (p / (1-p)) = a * x1 + b * x2 +… + z * xn. Erkek kukla bir değişken olduğundan, erkek olmak log oranlarını 2.75 oranında azaltırken, yaşta birim artış log oranlarını 0.037 azaltır.

Şimdi sapma tablosunu analiz etmek için anova() fonksiyonunu çağırabiliriz.

anova(model, test="Chisq")

Analysis of Deviance Table
Model: binomial, link: logit
Response: Survived
Terms added sequentially (first to last)

         Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
NULL                       799    1065.39              
Pclass    1   83.607       798     981.79 < 2.2e-16 ***
Sex       1  240.014       797     741.77 < 2.2e-16 ***
Age       1   17.495       796     724.28 2.881e-05 ***
SibSp     1   10.842       795     713.43  0.000992 ***
Parch     1    0.863       794     712.57  0.352873    
Fare      1    0.994       793     711.58  0.318717    
Embarked  2    2.187       791     709.39  0.334990    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Null sapma ile rezidüel sapma arasındaki fark, modelimizin null modele (sadece sabit terim içeren model) karşı nasıl bir performans gösterdiğini gösterir. Bu fark ne kadar geniş olursa o kadar iyidir. Tabloyu incelerken, her bir değişkeni birer birer eklerken sapmadaki düşüşü görebiliriz. Yine Pclass , Sex ve Age eklemek rezidüel sapmayı önemli ölçüde azaltmakta. SibSp düşük bir p değerine sahip olsa da diğer değişkenler modeli daha az geliştiriyor gibi görünüyor. Buradaki büyük bir p değeri, bu değişkenin olmadığı modelin aşağı yukarı aynı miktarda değişimi açıkladığını gösterir. Nihayetinde görmek istediğiniz şey sapma ve AIC’de anlamlı düşüşlerdir.

Doğrusal regresyonun R2’sine tam bir eşdeğer olmamakla birlikte, model uyumunu değerlendirmek için McFadden R2 indeksi kullanılabilir.

library(pscl)
pR2(model)

         llh      llhNull           G2     McFadden         r2ML         r2CU 
-354.6950111 -532.6961008  356.0021794    0.3341513    0.3591775    0.4880244

Modelin tahmin yeteneğinin değerlendirilmesi

Yukarıdaki adımlarda, modelin uyumunu kısaca değerlendirdik, şimdi yeni bir veri kümesinde y‘yi tahmin ederken modelin ne yaptığını görelim. Parameter type =”response” şeklinde ayarlandığında R, olasılıkları P(y=1|X) formunda verir. Karar sınırımız 0,5 olacak. P (y = 1 | X)> 0.5 ise y = 1 ise aksi halde y = 0 olur. Bazı uygulamalar için farklı eşiklerin daha iyi bir seçenek olabileceğini unutmayın.

fitted.results <- predict(model,newdata=subset(test,select=c(2,3,4,5,6,7,8)),type='response')
fitted.results <- ifelse(fitted.results > 0.5,1,0)

misClasificError <- mean(fitted.results != test$Survived)
print(paste('Accuracy',1-misClasificError))

"Accuracy 0.842696629213483" 

Test setindeki 0.84 hassasiyeti oldukça iyi bir sonuçtur. Bununla birlikte, bu sonucun daha önce yaptığım verilerin manuel olarak bölünmesine bağlı olduğunu unutmayın, bu nedenle daha kesin bir puan istiyorsanız, K-katmanlı çapraz doğrulama (k-Fold Cross-Validation) gibi bir tür çapraz doğrulama yapmanız daha doğru olacaktır.

Son adım olarak, ROC eğrisini çizeceğiz ve bir ikili sınıflandırıcı için tipik performans ölçümleri olan AUC’yi (area under curve – eğrinin altındaki alan) hesaplayacağız. ROC, AUC ROC eğrisinin altındaki alan iken, çeşitli eşik ayarlarında gerçek pozitif oranın (TPR) yanlış pozitif orana (FPR) karşı çizilmesiyle oluşturulan bir eğridir. Temel kural olarak, iyi tahmin kabiliyetine sahip bir model, 0.5’e kıyasla 1’e (1 idealdir) yakın bir AUC’ye sahip olmalıdır.

library(ROCR)
p <- predict(model, newdata=subset(test,select=c(2,3,4,5,6,7,8)), type="response")
pr <- prediction(p, test$Survived)
prf <- performance(pr, measure = "tpr", x.measure = "fpr")
plot(prf)

auc <- performance(pr, measure = "auc")
auc <- [email protected][[1]]
auc

0.8647186

Ve işte ROC grafiği:

Umarım bu yazı faydalı olacaktır. Bu örneğin tam kodunu içeren bir özeti burada bulabilirsiniz .

Bu yayını okuduğunuz için teşekkür ederiz, herhangi bir sorunuz varsa aşağıya bir yorum bırakın.

Kaynak: https://www.r-bloggers.com/2015/09/how-to-perform-a-logistic-regression-in-r/