Makine Öğrenimi Felsefesi-5

Volkan Yurtseven
13 min readSep 12, 2021

--

EDA (Keşifsel Veri Analizi)

İster bir ML modeli kurun ister standart bir veri analizi yapıyor olun, EDA aşaması en kritik aşamadır. Zira gerek verinin bütününü, gerek featureların bireysel olarak kendisini, gerekse bunların arasındaki ilişkiyi anlamanızı sağlar.

Burada önemli olan konu şu; eğer bir ML modeli kuruyorsanız, veri setiniz üzerinde kalıcı değişiklikler yapmamalısınız. Buna missing/null değerlerin ve outlierların ele alınması dahildir.

Öncelikle iki güzel haberim var:

  • EDA yapmanızı sağlayan hazır kütüphaneler var(pandas-profiling, dataprep, autovix ve sweetviz gibi) . Bunları (ve ilerde çıkması muhtemel diğer kütüphaneleri) mutlaka indirin ve deneyin.
  • EDA çalışmaları, genel Python/Pandas bilginizi geliştirmek için güzel bir fırsat olup kendi EDA kodlarınızı(fonksiyonlar, sınıflar) yazabilirsiniz. Ben de mypyext adında bi pakette böyle işler yapmaya çalışıyorum. Burda da bunu bolca kullanacağız. (Sürekli güncellediğim için burda gördüklerinizle son hali arasında farklar olabilecektir.) Evet, yeniden kullanılabilir kodlar yaratmanız önemli, zira aynı işleri farklı datasetler için hep yapacaksınız. Tabiki veri setine özgü değişecek kodlarınız da olacaktır.

Yöntem

EDA teknikleri ile elimizdeki veri setinin özet resmini çıkarmış oluyoruz aslında. Bu konuda bir standart olmamakla, hatta yapılacak analizlerin bir haddi hududu olmamakla birlikte temel olarak belli bi süreçten geçildiğini söyleyebilirim.

Yukarıda belirttiğim gibi, eğer günün sonunda bir ML modeli kuracaksanız veri seti üzerinde kalıcı değişklik yapmayın. Zira bunu Pipeline’lar içinde yapmalısınız. Böylece aynı işlemler gerek test seti için gerek yeni data için de kolaylıkla uygulanabilsin. Bununla beraber veri setinizin bir kopyasını alıp (memory sorununuz yoksa) onun üzerinde denemeler yaparken (Ör:missingler hariç nasıl görünüyormuş diye bakmak için) kalıcı değişiklikler yapabilirsiniz. Bu kalıcı değişiklikler Preprocessing aşaması olarak da adlandırılmakta olup, biz EDA aşamasında bu proprocessinge baz teşkil edecek durumları tespit etmeye çalışırız ve tabi ki daha fazlasını da yaparız. Yani EDA’yı sadece preprocessingin öncülü olarak görmeyelim, adı üzerinde burda datayı keşfediyoruz, onu anlamaya çalışıyoruz. Bu arada ayrıca model kurarken de tüm süreç boyunca yine EDA’ya devam etmek gerekebilir.

Bazı işlemleri ise eğer gerekli kalite kontrol süreçleri uygulanacağını düşünüyorsak ve bir daha bu problemli datanın gelmeyeceğinden eminsek dataframe üzerinde kalıcı olarak yapabilirz, pipeline’a hiç sokmayız. Ör: 10000 tane İstanbul, 3 tane İstanbl değeri varsa, bu 3 tanesini de İstanbula çeviririz, ama bunun için de veri kaynağımızda il bilgilerinin düzgün girilmesini sağlayan önlemleri aldırırız.

EDA’yı 4 ana alt aşamaya bölebiliriz, bu aşamaların her birinde görsel ve programatik yöntemler kullanılabilmektedir.

  • Genel resim çıkarma: Tüm veri seti hakkında genel bilgi edinimi
  • Univariate(tek değişkenli) analiz: Featurelar hakkında tek tek bilgi ediniriz. Missing değerler, outlierlar, anormal değerlerin tespiti gibi.
  • Bivariate(iki değişkenli) analiz: Featurelar arasındaki ilişkilerin tespitini yaparız.
  • Multivariate analiz: Burda ise genelde yapılan 3 veya daha fazla kolon arasındaki korelasyonları bulmak şeklindedir.

NOT: Makale oldukça uzun oldu, çok daha uzun olmaması için tüm kod örneklerini buraya dahil etmedim. Sonuçları görmek için, örnek veri setleri üzerinde yaptığım çalışmaları birazdan link olarak vereceğim, her yeni çalışmada linkleri güncelleyeceğim.

NOT: Konularda rahat ilerleyebilmek için Pandas ve görselleştirme kütüphaneleri ile rahat çalışabiliyor olduğunuz varsayılmıştır. Kendinizi tazelemek için yine benim hazırladığım şu notebooktan faydalanabilirsiniz.

Üzerinde çalışacağımız veri seti şu olup, notebook’a ve mypyext paketine yine github repo’mdan ulaşabilirsiniz.

1. Genel Resmi Çıkarma

Öncelikle gerekli kütüphaneleri import edelim.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
from mypyext import dataanalysis as da
from mypyext import ml
from mypyext import pythonutility as pu

Özet istatistikleri çıkarma

pd.describe() kesin çalıştıralım. Burda min/max başta olmak üzere tüm değerlere göz gezdirelim. Mesela Price alanında negatif değer olmaması gerektiği aşikar, buna bakabiliriz, işte böyle tüm kolonlarda anormal görünen bi şey var mı diye biraz vakti harcayalım.

Bunun dışında ben pandas’ın birkaç faydalı özelliğini tek bir fonksiyonda birleştirdim, öncelikle bunu çalıştırıyorum.(mypyext/dataanlysis içinde)

Veri tipi dönüştürmek

Bu noktada veri tiplerini görüp onlardan eğer özellikle ML modeli kullanacaksak veri tipi dönüştürme işini yapabiliriz. Bunu bazen inplace yapmak gerekebilirken bazen de “şu kolonu numerik/categoric düşün” gibi de ilerleyebiliriz. Zira model kurduğumuzda bunlara numerik olarak ihtiyacımız olacak, bu aşamada categorike çevirip modelleme sırasında tekrar numerik(factorize veya labelencoding) yapmak anlamsız olacaktır. Doğru veri tipine dönüştürme, korelasyon hesaplarken de işimize yarayacak. Zira nümerik değerlerin korelasyonu ile kategoriklerinki farklı hesaplanmakta, keza numerik-kategorik arasındaki korelasyon da öyle. Özellilkle 0–1 değerini almış bir kolon genelde categoric gibi ele alınmalıdır, dolayısıyla korelasyon hesabında bunları categoric kolon gibi düşünmek gerekir, ama veritipini değiştirmeye gerek yoktur.

Bizim veri setimizde ben aşağıdaki değişikleri yapmayı uygun buldum.

nums=['price', 'minimum_nights', 'number_of_reviews', 'reviews_per_month','availability_365']
coltobechanged=[“price”,”minimum_nights”,”number_of_reviews”,”calculated_host_listings_count”,”availability_365"]
datetobe=”last_review”
catstobe=[“neighbourhood_group”,”neighbourhood”,”room_type”]

Bunlardaki değişiklik şöyledir:

df[coltobechanged]=df[coltobechanged].apply(lambda x: x.astype(‘int16’))
df[datetobe]=pd.to_datetime(df[datetobe])
df[catstobe]=df[catstobe].apply(lambda x: x.astype(‘category’))

Bu değişikliklerin memory kullanımındaki etkisini notebook’tan görebilirsiniz.

Bunların dışında;

  • Sayısallığı bozan bilgileri(para birimi gibi) yok etmek gerekebilir.
    df[‘Amount’] = df[‘Amount’].str.replace(‘TL’,’’)
  • Uzun ve karmaşık olan kolon isimlerini sadeleştirebiliriz

Mükerrerlik kontrolü

  • Birbirinin aynı olan satırlar var mı diye kontrol etmek
  • Tek bir kolon(genelde ID benzeri) veya uniqueliği sağlayan belli kolonlar üzerinde mükerrerlik kontrolü
  • Sütunlarda mükerrerlik kontrolü

Bunlarla ilgili kodları da yine notebook içinde bulabilirsiniz.

Unique değer incelemesi

Yukarda SuperInfo içinde zaten nunique yapmıştık. Şimdi biraz daha farklı şekilde bakalım.

İlk olarak cardinalitesi düşük olan featureları yine SuperInfodan görebiliyoruz, ancak bunu programatik olarak da elde etmek istersek yine mypyext/dataanlysis içindeki şu kodu çalıştırabiliriz. Cardinality için default değerim 10, isterseniz bunu manuel olarak değiştirebilirsiniz.(bundan sonraki cardinality gerektiren tüm fonksiyonlarda aynı değeri kullandım)

da.getColumnsInLowCardinality(df)
#çıktısı: ['neighbourhood_group', 'room_type']

Şimdi cardinalitesi düşük olan bazı featurelar için unique değerleri görelim. Bunun için yine mypyext/dataanlysis içindeki aşağıdaki fonksiyonu çalıştırıyorum.

da.printUniques(df)

Bu kategorilerin içindeki elemanlarını her birinin adetleri de önemliyse şöyle bakabiliriz.

da.printValueCount(df)

Baremleme(Binning/Discretization)

Eğer numerik bir kolonda çok fazla değer varsa bunları da kendi içinde baremler halinde gruplamak gerekebilir. Bu, özellikle bazı algoritmalar categoric değer istediği için olabileceği gibi, bazen de kolay EDA yapma amacıyla uygun olabilir. Özellikle bu numerik değerler kendi içinde bi kümeleme eğilimi gösteriyorsa.

Biz bu örneğimizde Price alanı için bunu yapalım

df[“FiyatBarem”]=pd.cut(df[“price”], 5,labels=[“Çok ucuz”, “Ucuz”, “Orta”,”Pahalı”,”Çok pahalı”])
df[“FiyatBarem”].value_counts()
#çıktısı
Çok ucuz 48809
Ucuz 54
Orta 16
Pahalı 9
Çok pahalı 7

Missing/Null values

Null değer var mı diye kontrol edebilirsiniz(her ne kadar Superinfo için de göstermiş olsak da burda da ayrıca bakalım)

Literatürde 3 tür missing valuedan bahsedilir. Biraz daha aşağıda bahsedeceğimiz aksiyon tiplerini de bu bilgiler ışığında ele almak önemli olacaktır.

  • Missing completely at random
  • Missing at random
  • Informative missing

Bunlar hakkında şuradan bilgi edinebilirsiniz ama ben özellikle sonuncusu hakkında birkaç şey söylemek isterim. Bu casede, missing value özel bir anlam ifade eder, bunlar bazen yokluk anlamında yani 0 gibi düşünülebileceği gibi, bazen henüz bir olayın olmadığı veya bir şeye sahip olunmadığı anlamında olabilir. Ör: Bir müşterinin hesap bakiyesinin 0 olması onun o hesaba sahip olduğu ama hiç parası olmadığı anlamına gelirken boş olması, hesabının olmaması anlamına gelebilir, dolayısıyla 0'la doldurmamak gerekebilir. Veya bir müşterinin (kredi) takip bakiyesinin 0 olması, onun bir zamanlar takibe girdiği(kredisinin battığı) ama bunu sonradan kapattığını(ödediğini) gösterirken null olması hiç takipe girmediği anlamına gelebilir.

Null kontrolleri aşağıdaki şekillerde yapılabilir:

df.isnull().values.any() # NA/null değer var mı kontrol edilir. df.isnull().any().sum() # kaç kolonda null var
df.isnull().sum()
#Varsa kaç adet olduğunu görmek için
df.isnull().all().sum() #tüm kolonu null olan var mı

Bazen data null değildir ama null olarak yorumlamak gerekebilir. Ör: numerik değerler için -1/-999 gibi, tarihlerde 31.12.9999 veya 11.11.1111 gibi, categoric değerler için de “Bilinmiyor”, “NA” v.s gibi. Bunlar için de unique değerlere göz gezdirmekte fayda olacaktır. Özellikle unique değeri az olanlara. Bunu da zaten yukarıda printUniques fonksiyonu ile görebiliyoruz. Bazı durumlarda 0 değeri de null olarak yorumlanabilir, buna da dikkat edin. Bunun için de mypyext/dataanlysis içine yazdığımız bi fonksiyonu kullanacağız.

da.findNullLikeValues(df)
# çıktı: 2 null-like values in host_name

Ayrıca nulların datada nasıl yer tutuğuna tek seferde bakmak da önemli olabilir. Satır bazında random mı, yoksa hep belli kolonlar mı aynı anda null oluyor onu görebilme imkanı verir.

Bunlarda imputation(nulları doldurma) yapmadan önce bu haliyle incelenmesinde fayda var, belki missingler özelinde anlamlı bi bilgi çıkacaktır. Modelleme aşamasına gelene kadar imputation yapmamakta fayda var.

Bu missing değerleri çeşitli şekillerde ele alabiliyoruz.

  • Boş kayıt içeren kolonu komple silebiliriz: Kolonun büyük kısmı boş ise.(df.dropna)
  • Çok sayıda missing value’su olan bir satır varsa o satırı sileriz. Imputation yapmadan önce bu aşamayı uygulamak önemli.
  • Imputation, yani kolonu bir değerle doldurma: Az sayıda satır boş ise, özellikle elimizde yeterli veri yoksa uygundur.(df.fillna veya Imputer sınıfı ile). ML modeli çalıştırmayacaksak fillna yeterli, aksi halde Imputer sınıflarından yararlanmakta fayda var.

Şimdi bizim veri setimize bakacak olursak, name ve host_name alanlarındaki null değerler çok kritik değil, zaten bunları bir model yapacaksak bile modelde kullanacağımız alanlar değil. O yüzden preprocessingde bunlara müdahale etmeye gerek yok. Ancak reviewla ilgili olanlar nerdeyse toplam kayıt sayısının 4'te biri. Bunlara ne yapacağımıza bakalım.

Mesela reviews_per_month kolonunu 0'la doldurmak isteyebiliriz. fillna kullanacağız.

df.reviews_per_month.fillna(0,inplace=True)

Burada bazen missingleri ortalama ile, en sık değerle v.s doldurma seçenekleri uygulanabilmekte. Ancak bazen bu aggregate değerleri tüm kolon üzerinden değil de belirli bir kolon(lar)a göre almak gerekebilir. Yani Exceldeki Averageif(s) mantığı ile. Tabi bunun için Catplot yapıp errorbarları (varyansı gösterir) gözlemlemek iyi olacaktır. Varyans yüksekse burada null hücreleri ortalama ile doldurmak anlamsız olabilir.

Mesela oda tipi bazında ortalama alıp bakalım, varyanslar makul gibi görünüyor, dolayısıyla böyle bir ortalamayı kullanabiliriz.

g=sns.catplot(x="room_type",y="reviews_per_month",data=df,kind="bar")
g.set_ylabels("Oda tipi bazında fiyatlar")
plt.xticks(rotation= 90)
plt.show();
df["reviews_per_month"].fillna(df.groupby("room_type")["reviews_per_month"].transform("mean"),inplace=True)

Ama mesela aşağıdaki gibi bir tabloda Flying tipli pokemonların atak gücünde varyans yüksek, bu nedenle nerdeyse tüm Tip1ler için için ortalama koymak mantıklı ancak Flying tiptekiler için başka birşey yapılmalıdır.

Doğru soruları sorarak detaylara dalma

Bu noktada çeşitli filtrelemeler/sıralamalar yapılabilir. Bu kısım, genel yöntemlerden ziyade ilgili domaine ve veri setine uygun soruların sorulup cevaplanmaya çalışıldığı kısım olup, sizin ne kadar iyi bir veri analizcisi/bilimcisi olduğunuzu ortaya koyacak kısımdır. Bu noktada doğru soruları soramazsanız, katma değer üreten cevaplar da elde edemezsiniz. Burası gerçek anlamda data science alanıdır ve kesinlikle yoğun bir domain(iş/business) bilgisi ile biraz da yaratıcılık gerektirir.

Univariate(Tek featurelu) Analizler

Veri analizi notebookumda hangi tür analizi için nasıl bir grafik kullanılabileceğini görmüştük.

Çeşitli örnekler şöyle olabilir:

  • df.unique() yaptığımızda sadece 2 feature’ın az sayıda distinct değer aldığını görmüştük, dolayısıyla bunların gruplu değerleri üzerinden grafikler de çıkarabiliriz.
df[‘neighbourhood_group’].value_counts().plot.bar(title=”Semte göre dağılım”);

Yorum: En çok ev Brooklyn ve Manhattandaymış.

  • Oda tipi bazındaki adetlere bakalım, bu sefer seaborn ile.
y=df[“room_type”]
ax = sns.countplot(y,label=”Count”)

Yorum: Shared roomlu ev sayısı çok azmış.

  • 1 gece kalmalı kaç oda varmış ona bakalım
len(df[df[“minimum_nights”]==1]) #12720
  • Sayısal tüm kolonların top5 değerini görelim

Uzun olduğu için hepsini buraya almadım ancak tüm nümerik kolonların top 5 değerini verdi.

nums=['price', 'minimum_nights', 'number_of_reviews', 'reviews_per_month','availability_365']
da.ShowTopN(df[nums]) #default n değeri=5
  • En çok hangi host tercih ediliyor? Sebebi ne olabilir?
#en popüler host
df[“host_id”].mode()

Peki, bu en popüler host’u diğerlerinden ayıran en olabilir diye bi bakalım.

df[df[“host_id”]==219517861].groupby(“host_id”)[nums].mean()

Diğerlerindeki durumu görelim;

Benim yorumum, fiyatı daha yüksek olduğu için kaliteli algısı oluşturuyor olabilir, ayrıca ortalamaya(88) göre yılın daha çok zamanı(301) açık olması da tercih sebebini artırıyor olabilir. Bu işte olanlar bu sonuçları daha iyi yorumlayabilecektir.

df[df[“host_id”]!=219517861].groupby(“host_id”)[nums].mean().mean().to_frame()
  • En popüler 5 hostun grafiğini çizelim;
chrt=top5.plot(kind=’bar’)
chrt.set_title(“Ev sahibi popülerlik listesi”)
chrt.set_ylabel(‘Ev sahibi listing adedi’)
chrt.set_xlabel(‘Host ID’)
chrt.set_xticklabels(chrt.get_xticklabels(), rotation=45)

Yorum: Popülerlikte fark atan bir host yok, makul şekilde bir sıralama görüyoruz. Bunu outlier grafiği çıkararak da görebilirdik, aşağıda göreceğiz.

  • Komşuluk ve oda tipi bazında pivot alıp fiyatlar için descriptive bi tablo çıkaralım.
d=df.groupby(“neighbourhood_group”)[“price”].describe()
d.applymap(int)

Yorum: Standart sapmalar ortalama rakamlara göre çok yüksek, demek çok fazla outlier var. Outlier tespiti kısmında bunları göreceğiz. Ama öncesinde biz outlier tespiti için iki oranı da tabloyu koyup grafiği çizelim

d[“mean/median”]=d[“mean”]/d[“50%”]
d[“std/mean”]=d[“std”]/d[“mean”]
d.iloc[:,-2:].plot.bar(subplots=True,figsize=(5,6))
plt.tight_layout()
plt.show();

Özellikle alttaki grafikten outlierların olduğu anlaşılıyor, zira std/mean oranı yani varyasyon katsayısı olarak bilinen bu oranını genelde %20–30lardan küçük olması gerekir ki, çok büyük bir farklılık yok diyebilelim.

Dağılım analizleri

Öncelikle boxplot ile outlier kontrolü yapalım:

#ölçekler farklı olduğu için ayrı ayrı chartlarda görelim
plt.figure()
df[nums].plot(kind=”box”, subplots = True,figsize=(10,6),rot=45)
plt.tight_layout()
plt.show();

Sondaki hariç hepsinde bol miktarda outlier olduğunu görebiliyoruz.

#Sadece price için gruplama yaparak bakalım
plt.figure(figsize=(12,6))
chart=sns.boxplot(x=”neighbourhood_group”, y=”price”, data=df)
chart.set_xticklabels(chart.get_xticklabels(),rotation=45)
plt.show();

Mahalle grubu bazında dahi outlierların bol olduğunu görebiliyoruz, yani belli bi mahalle grubunda toplanmamış bu outlierlar.

Histogram çizdirerek de outlier ve genel bir dağılım kontrolü yapabiliriz.

df[“price”].plot(kind=”hist”,bins=10,figsize=(8,5))
plt.show();

Bu histogram çok açıklayıcı değil, sanki tüm fiyatlar 0–1000 arasında toplanmış gibi, bu aralığa tekrar uygulayalım.

df[df[“price”]<1000].price.plot(kind=”hist”,bins=10,figsize=(8,5))
plt.show()

Şimdi daha anlamlı bir histogram var. önemli bi kısmı 0–100 aralığında, yine önemli bi kısmı da 100–200 arasında, 200–300 de fena değil, sonra fiyat arttıkça frekans düşüyor.

Buna bir de bölge bazlı bakalım

g=sns.FacetGrid(df[df.price<250],col=”neighbourhood_group”)
g.map(plt.hist, “price”,bins=10)
g.add_legend()
plt.show()

Şimdi burda hepsinde y ekseni aynı olduğu için sondaki iki grafikteki histogram dağılımı çok net değilim, o yüzden hist yerine distplot yapıp tekrar bakalım.

g=sns.FacetGrid(df[df.price<250],col=”neighbourhood_group”)
g.map(sns.distplot, “price”,bins=10)
plt.show();

Aynısını oda tipi bazında da çıkarabiliriz. Bu da notebookta bulunuyor.

  • Bir de tüm anlamı olan nümerik kolonların histogramlarına topluca bakalım
df[nums].hist(figsize=(8,5))
plt.tight_layout();

Avalibility dışında hepsi ilk “barem(bin)” içinde yoğunlaşmış gibi, yani right-skewed bir dağılım. Bunlara da price’a yaptığımız gibi daha yakından bakmak gerekebilir, bu kısmı size bırakıyorum.

Skewed olan featurelar önemli. Eğer normal dağılım olma varsayımını yapan bir ML algoritması kullanılıyorsa(mesela regression) bunları düzeltmek lazım. Çünkü bu durum modelin intercept ve coefficient değerlerini etkileyebilir. Bunun için bir yöntem log transformation uygulamak olabilir. Log transformasyonun detayları için araştırma yapmanız gerekiyor, bu makalede buna girmek anlamsız olacaktır. Bu arada log transformasyon dışında başka yöntemler de var tabi ki, bunları da araştırabilirsiniz.

Programatik outlier tespiti

Outlier konusu veri analizi açısından önemli ancak ML modelleri inşa ederken daha da önemli, zira bazı modeller outilerlera karşı aşırı duyarlıdır ve yanlış sonuç üretebilirler. O yüzden doğru şekilde ele alınmaları gerekir. Bazen ise esas görevimiz tamamen outlier durumları yakalamak olabilir. Bu konu da başlı başına bir konu olup biz burada temellerine değineceğiz, ve özellikle sadece tek bir featuredaki outlier tespitine bakacağız. yoksa multidimensional outlier tespit yöntemleri de bulunmaktadır, ki bunlar da bu gönderi kapsamının dışında yer almaktadır. Bu konuda da bir gün bi gönderi yayınlamaya düşünüyorum.

Görsel tespit için yukarda boxplot, violinplot ve histogram gibi grafik türlerimizi kullandık.

Grafiksel olmayan yani programatik yöntemler ise şöyledir.

  • Standart Sapma/Mean oranı: Bu oran 0'a ne kadar yakınsa değerlerin dağılımı o kadar homojendir, tersi durumda değerlerin birbiriyle alakası yoktur. Bu arada tespit için ortalama +/- 3*std sınırlarına bakılabilir.
  • Median/Mean oranı:1'den ne kadar farklıysa outlier olma ihtimali o kadar yüksek. 1'in altında olup olmaması, outlier değerlerin üstte mi altta mı olduğunu da gösterecektir.
  • IQR Yöntemi: Q1–1,5 IQR altında ve Q3+1,5 IQR üstünde yer alan değerlerin toplam kayıt sayısına bölünmesi.(Aslında boxplot ve violinplot da bu verileri kullanır)
Q1 = df.price.quantile(0.25)
Q3 = df.price.quantile(0.75)
IQR = Q3 — Q1
print(IQR)
print(df[(df.price > (Q3 + 1.5 * IQR)) | (df.price > (Q1–1.5 * IQR))][“price”])
  • z-score yöntemi: Skoru -3 ve 3ün dışında olanlar
from scipy import stats
import numpy as np
z = np.abs(stats.zscore(df.price))
print(df.iloc[np.where(z>3)][“price”].min())

Ben bunlar için de mypyext/dataanlysis içinde hazır fonksiyonlar bulunduruyorum.

da.outliers_zs(df,[“price”])
#çıktısı:387

Bunların çalışma farklı şekli, null değerlere karşı duyarlılıkları farklı olduğu için sonuçları da farklı olabilecektir. Bu fonksiyonlarda parametre olarak null değerlerle ne yapılacağını belirleyebilirsiniz.

Bivariate Analizler

Kolonlar Arası Benzerlikler

Yukarıda mükerrer kolonları bulmak için farklı yöntemler denemiştik. Ancak bazen kolon adı farklı olup içerikleri birbirinin aynısı veya çok yakın değerler olabilmektedir. Bunları tespit etmek önemli bir bulgu olabilir.

Burda genelde manhattan distance/euclidean distance gibi distance metrikleri kullanılır. (NOT: Bu gönderiyi ilk yayınladığımda sadece cosine similarity’yi kullanmıştım ancak bunun daha çok doküman karşılaştırmalarında kullandığını öğrendim)

Öncelikle manhattan’a bakalım(Bu arada biz sadece iki sklaler değeri input olarak verdiğimiz için yani iki bouylut vektörleri vermediğimiz için öklid ve manhattan aynı sonucu verecektir)

da.calculateManhattanSimilarity(df,nums) #default eşik %1

Bunun sonucunda hiç çıktı alamadık, demekki kolonlar arasında bir benzerlik yok. Şimdi bir de cosine’e bakalım.

da.calculateCosineSimilarity(df,nums,threshold=0.5)

Burda da anlamlı bi benzerlik yok. Rakamların yüksek göründüğüne bakmayın, cosine similarity’yi daha çok metinsel karşılaştırmalarda kullanmak gerekiyor.

Feature benzerliği ile ilgili aşağıdaki linkleri de incelemenizi tavsiye ederim

Korelasyonlar

Numerik kolonlar arası korelasyon

Numerik alanların korelasyonunu bulmak için en basit yöntem pandas’ın corr metodunu kullanmaktır. Akabinde bunları bir heatmapte göstermek de görsellik açısından uygun olacaktır. Keza çoklu bir scatter grafik türü olan scatter-matrix de başka bir alternatif olabilir.

fig,axes = plt.subplots(nrows=1,ncols=2,figsize=(16,5))
lw=.5,
fmt=".2f"
sns.heatmap(df[nums].corr(),annot=True,ax=axes[0],linewidths=lw,fmt=fmt)
sns.heatmap(df.groupby("room_type")[nums].mean().corr(),annot=True,ax=axes[1],linewidths=lw,fmt=fmt)
axes[0].set_title("Tüm data korelasyonu")
axes[1].set_title("Oda tipi bazında ortalamaların korelasyonu")
plt.subplots_adjust(wspace=0.5)
plt.show();

Reviews_per_month alanı ile number_of_review arasında en yüksek korelasyon görünüyor ama bu ciddi bi oran değil. Sağdaki grafikte ise oda tipi bazında ortalamalara bakıldığındaki korelasyonları görüyorsunuz. Burda ise hem + yönde hem — yönde oldukça yüksek korelasyonlar var.

Şimdi de scatter-matrix bakalım.

from pandas.plotting import scatter_matrix
scatter_matrix(df[nums], alpha=0.2, figsize=(10, 10), diagonal='kde')
plt.show();

Kategorik kolonlar arası korelasyon

Kategorik kolonlar arasında korelasyon için farklı istatistiki yöntemler sözkonusu. Bunların temelinde genelde chi kare testi yatıyor. Ben pythonda bu işleri yapan iki farklı kütüphane buldum. Biri dython, biri phik. dythonda bazı sorunlar yaşadım, kaynak kodunu bulup bazı değişiklikler yapmam gerekti; phik'in kullanımı biraz daha kolay gibi. Bu arada detaylarını henüz inceleyememiş olmakla birlikte (missing valuelar yüzünden olsa gerek) sonuçlar biraz farklı çıkabiliyor.

İşin teorisini anlamınız için de şu kaynaklara bakabilirsiniz:

import phik
dfphik=df[catstobe].phik_matrix()
dfphik

Kategorik ve numerik kolonlar arası korelasyon

Yine phik’in tek satırlık komutu ile tüm kolonlar arası korelasyonu çıkarabiliyoruz. Sadece numerik kolonların ne olduğunu interval_cols parametresini vererek belirtmemiz yeterli.

dffullcorr=df[catstobe+nums].phik_matrix(interval_cols=nums)

İşin teorisi için şu linke bakılabilir.

Sonuç

Başta da belirttiğim gibi bu gönderi biraz uzun oldu, daha da uzun olabilirdi. Zira her veri setinin kendine göre bi özgünlüğü ve dolayısıyla keşfedilmesi gereken farklı yönleri olabilmekte. Özellikle “detaylara dalma” kısmı hemen her veri setinde farklı olmaktadır. Diğer kısımlar üç aşağı beş yukarı benzer olabilmekte. Yine başta belirttiğim gibi burdaki kodların büyük kısmını hazır EDA paketleri yapmakta. Hatta artık bir moda haline gelmeye başlayan AutoML toolları ile bu işler iyice basitleşmektedir. Burda önemli olan kısım EDA sonuçları ile preporcessingi ve feature engineering kısımlarını düzgün bir şekilde birleştirme beceresini gösterebilmekte.

Sonuna kadar okuduğunuz için teşekkür ederim. Serinin bir sonraki gönderisinde görüşmek üzere.

--

--

Volkan Yurtseven

Once self-taught-Data Science Enthusiast,now graduate one