Temel Bilesen Analizi (Principle Component Analysis (PCA))

Mustafa Germec
8 min readMar 1, 2023

Mustafa Germec, PhD

Merhaba sevgili veri bilimi meraklıları,

Bu yazımda Temel Bileşen Analizi ile ilgili kısa ve öz bilgiler paylaştım. Umarım faydalı bulursunuz. Şimdiden keyifli okumalar dilerim.

PCA yöntemi, denetimsiz (unsupervised) makine öğrenimi yöntemlerinden biridir. PCA’nın temel fikri, çok değişkenli verinin ana özelliklerini daha az sayıda değişken/bileşen ile temsil etmektir. Diğer bir ifade ile küçük miktarda bir bilgi kaybını göz önüne alıp değişken boyutunu azaltmaktır. Örneğin, elimizde 100 tane değişkenden oluşan bir veri seti olsun. Küçük bir bilgi kaybı göz önüne alınıp veri setindeki 100 değişken sayısını örneğin 3 değişkene indirme çabasıdır. 100 değişken yerine 3 değişken ile veri setindeki değişkenlik, varyans ve bilgi temsil edilir. Bunun bedeli de göz ardı edilebilecek ufak miktarda bir bilgiden fedakârlık yapmaktır.

Neden boyut indirgeme gibi bir kaygı var?

Bunun nedeni, örneğin doğrusal regresyon problemlerinde çoklu doğrusal bağlantı probleminden kurtulmak olabilir. Bir diğer nedeni, örneğin, bir yüz tanıma probleminde resimlere filtre yapma ihtiyacı olabilir. Bir diğer deyişle, PCA, gürültü azaltma aracı olarak kullanılabilir. Bu örneklerdeki benzer sebepler ile bir şekilde boyut indirgeme ihtiyacı olduğundan bu yöntem kullanılabilir.

PCA, bir boyut indirgeme yaklaşımıdır, yani veri setinin boyutunu küçük miktarda bir bilgi kaybını göze alarak indirgeme işlemidir.

Temel bilesen analizi öncesi ve sonrası

PCA, nerede ve ne şekilde ihtiyaç görür?

Görüntü, regresyon, bazı varsayım problemlerinde, yani bir şekilde çok boyut söz konusu olduğunda kullanılabilir. Bir şekilde boyut indirgeme isteniyorsa, PCA kullanılabilir.

PCA yöntemi, birçok farklı konu ve alanda kullanılabilen temel bir tekniktir. Dolayısıyla sadece doğrudan bir şey yapmak için kullanılmaz. Ancak, örneğin, çok boyutlu bir veriyi örneğin 2 boyuta indirgemek suretiyle görselleştirmek için kullanılabilir. Veri setinde 50 değişkenin olduğunu varsayalım. Bu, veri setinin 50 boyutlu olduğunu gösterir. Bu veri setini PCA yöntemini kullanarak 2 boyuta indirgeyebiliriz. PCA, veri setinin bağımsız değişkenlerini, doğrusal kombinasyonları ile ifade edilen bileşenlere indirger. Dolayısıyla bu bileşenler arasında korelasyon yoktur. Teknik olarak, PCA bu bileşenleri PCA1 ve PCA2 olarak nasıl çıkarır? sorusunun yanıtı ise değişken gruplarının varyanslarını ifade eden öz değerleri ve veri setindeki değişkenleri gruplandırır. Gruplar arasında en fazla varyansa sahip olan gruplar, en önemli gruplardır ki bunlara asal bileşenler denir. Yani burada varyansa ve öz değerlere dayalı bir gruplama yapılmaktadır.

Uygulama

Kütüphaneleri import etme

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler, LabelEncoder
import warnings
warnings.filterwarnings("ignore")

from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import cross_val_score, GridSearchCV
from sklearn.metrics import mean_squared_error, mean_absolute_error
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = 'all'

pd.set_option('display.max_columns', None)
pd.set_option('display.width', 500)

Veri setini import etme

df = pd.read_csv('/kaggle/input/pca-datasets/hitters.csv')
df.columns = [col.lower() for col in df.columns]
df.head()
Veri setinin ilk 5 gözlemi

Bu çalışma, PCA ile ilgili olduğundan ve veri setindeki kategorik ve bağımlı değişken ile ilgilenmediğimizden dolayı bunlar veri setinden uzaklaştırılmıştır. Dolayısıyla, elde edilen değişkenler, çalışılmak istenilen veri setini oluşturmaktadır.

num_cols = [col for col in df.columns if df[col].dtype != "O" and 'salary' not in col]
df_pca = df[num_cols]
df_pca.head()
Kategorik değişkenler ve bağımlı değişken uzaklaştırıldıktan sonra elde edilen veri seti

Veri setindeki eksik değerler şimdilik ilgi alanı olmadığından dolayı, veri setinden silinmiştir. Çünkü buradaki amaç, çok değişkenli bir verinin daha az değişken ile ifade edilmesidir. Örneğin, 16 değişkenli bir veri setinin 2 veya 3 bileşene indirgeme gibi.

df_pca.dropna(inplace=True)
print(f'Veri setindeki gozlemlerin ve kolonlarin sayisi sirasiyla {df_pca.shape[0]} ve {df_pca.shape[1]} dir.')

# Veri setindeki gozlemlerin ve kolonlarin sayisi sirasiyla 322 ve 16 dir.

Veriyi standartlaştırma

df_pca = StandardScaler().fit_transform(df_pca)
pca = PCA()
pca_fit = pca.fit_transform(df_pca)
pca_fit
Verinin standartlaştırılması sonrası elde edilen array

Bu bileşenlerin başarısı, bileşenlerin açıkladığı varyans oranına göre belirlenir. Bileşenlerin açıkladığı varyans oranları aslında açıkladıkları bilgi oranıdır.

pca.explained_variance_ratio_
Her bir bileşenin açıkladığı varyans oranı

Kümülatif varyans oranlarini hesaplama

np.cumsum(pca.explained_variance_ratio_)
Bileşenlerin açıkladığı kümülatif varyans oranları

Bu hesaplama ile elde edilen değerler, PCA’nın oluşturduğu 16 adet yeni bileşenin hepsinin açıkladığı varyans oranıdır.

Optimum bilesen sayısını belirleme (Elbow metodu)

Bu yöntem ile en keskin geçisin nerede olduğu belirlenir.

pca = PCA().fit(df_pca)
sns.lineplot(np.cumsum(pca.explained_variance_ratio_))
plt.xlabel('Bilesen sayisi')
plt.ylabel('Kümülatif varyans orani')
plt.show()
Optimum bilesen sayısını belirlemek için kullanılan Elbow metodu

Yukarıdaki grafik incelendiğinde 2 veya 3 tercih edilebilir. Veri görselleştirme için kullanıldığı durumda 2 boyut seçilmelidir. Regresyon problemi ile ilgilenildiğinde, çoklu doğrusal bağlantı problemini gidermek için değişken sayısı kadar bileşen oluşturmak tercih edilebilir. Böylece veri setinin içerisindeki bilginin tamamı korunmuş olur ancak bu durumda da birbirinden bağımsız olur. Yüksek korelasyon ve çoklu doğrusal bağlantı problemlerine sahip olmaz.

Final PCA modelini oluşturma

pca = PCA(n_components=3)
pca_fit = pca.fit_transform(df_pca)
pca.explained_variance_ratio_
np.cumsum(pca.explained_variance_ratio_)
Final modelinin her bir bilesen için açıkladığı varyans oranları ve kümülatif varyans oranları

Temel bilesen regresyon (PCR) modeli

Diyelim ki Hitters veri setini doğrusal bir modelleme ile modellemek istiyoruz ve değişkenler arasında çoklu doğrusal regresyon problemi var. Bu doğrusal regresyon problemlerinde sağlanması gereken varsayımlardandır. Değişkenler arasında yüksek korelasyon olması, çeşitli problemlere neden olduğundan istenmeyen bir durumdur. Diğer bir amaç ise, yukarıda PCA yöntemiyle çıkarılmış olan bileşenlerin neye karşılık geldiğini belirlemeye çalışmaktır.

Numerik kolonların dışında kalanları getirme

others = [col for col in df.columns if col not in num_cols]
others

# ['league', 'division', 'salary', 'newleague']

df[others].head()
PCA analizine dâhil edilmeyen kategorik değişkenler ve bağımlı değişken
pd.DataFrame(pca_fit, columns=['PC1', 'PC2', 'PC3']).head()
PCA analizine dâhil edilen değişkenlerin 3 boyuta indirgenmesi ile elde edilen dataframe

PCR yöntemiyle önce bir temel bilesen yöntemi uygulanıp değişkenlerin boyutu indirgenmekte ve sonrasında ise bu bileşenlerin üzerine bir regresyon modeli kurulmaktadır. Bunun doğrudan Python’da uygulandığı bir metot yoktur. Python’da olmayıp istatistikte olan bir konu olduğundan dolayı, bu işlemi veri bilimcinin kendisi yapmalıdır. Numerik bileşenlerin seçilip bileşenlerce ifade edilmesi ve üzerine regresyon modelinin kurulması durumunda temel regresyon modeli oluşturulur. Oluşturulan bu bileşenler, değişken olarak kullanılır. Dolayısıyla ‘pca_fit’ ve df[others] değişkenleri bir araya getirilir.

final_df = pd.concat([pd.DataFrame(pca_fit, columns=['PC1', 'PC2', 'PC3']), df[others]], axis=1)
final_df.head()
Modele sokulacak final veri seti

Böylece 16 değişkenin taşıdığı bilginin %82'si PC1, PC2 ve PC3 değişkenleri ile temsil edilmektedir. Bu gerçek bir ihtiyaçtır. Elde edilen final_df veri setini kullanarak tahminleme yapmak için lineer ve karar ağacı modelleri kullanılmıştır. Değişkenleri encode etmek için label encoding yöntemi kullanılmıştır.

Label encoding

def label_encoder(df, binary_cols):
label_encoder = LabelEncoder()
df[binary_cols] = label_encoder.fit_transform(df[binary_cols])

binary_cols = [col for col in final_df.columns if final_df[col].nunique() == 2]
for col in binary_cols:
label_encoder(final_df, col)

final_df.head()
Label encoding sonrası eşsiz değer sayisi 2 olan değişkenlerin 1 ve 0 olarak encode edilmesi

Bağımlı değişkendeki eksik verilerin silinmesi

final_df.dropna(inplace=True)
final_df.shape

# (263, 7)

Bağımlı ve bağımsız değişkenlerin seçilmesi

y = final_df['salary']
X = final_df.drop('salary', axis=1)

Lineer regresyon modeli

lr = LinearRegression().fit(X, y)
y_pred = lr.predict(X)
print(f'Hata kareler ortalamasi = {mean_squared_error(y, y_pred)}')
print(f'Ortalama mutlak hata = {mean_absolute_error(y, y_pred)}')
print(f'Kök ortalama kare hatasi = {np.sqrt(mean_squared_error(y, y_pred))}')

# 5-katli capraz dogrulama ile rmse degerinin hesaplanmasi
print(f'5 katli capraz dogrulama ile rmse degeri = {np.mean(np.sqrt(-cross_val_score(lr, X, y, cv=5, scoring="neg_mean_squared_error")))}')

# Hata kareler ortalamasi = 112133.32935389846
# Ortalama mutlak hata = 228.87439847834383
# Kök ortalama kare hatasi = 334.86315018810063
# 5 katli capraz dogrulama ile rmse degeri = 345.6021106351967
sns.regplot(x=y, y=y_pred, data=final_df)
plt.show()Belirlenen kümelerin küme etiketlerini (labels) getirme
Lineer regresyon modeli ile yapılan tahminleme sonrası deneysel değerlere karşı (x-ekseni) tahmin edilen değerler (y-ekseni)

Ağaç modeli

cart = DecisionTreeRegressor().fit(X, y)
y_pred_cart = cart.predict(X)
print(f'Hata kareler ortalamasi = {mean_squared_error(y, y_pred)}')
print(f'Ortalama mutlak hata = {mean_absolute_error(y, y_pred)}')
print(f'Kök ortalama kare hatasi = {np.sqrt(mean_squared_error(y, y_pred))}')

# 5-katli capraz dogrulama ile rmse degerinin hesaplanmasi
print(f'5 katli capraz dogrulama ile rmse degeri = {np.mean(np.sqrt(-cross_val_score(cart, X, y, cv=5, scoring="neg_mean_squared_error")))}')

# Hata kareler ortalamasi = 112133.32935389846
# Ortalama mutlak hata = 228.87439847834383
# Kök ortalama kare hatasi = 334.86315018810063
# 5 katli capraz dogrulama ile rmse degeri = 394.0791736910673
sns.regplot(x=y, y=y_pred_cart, data=final_df)
plt.show()
Ağaç modeli ile yapılan tahminleme sonrası deneysel değerlere karşı (x-ekseni) tahmin edilen değerler (y-ekseni)

Yukarıdaki grafiğe göre, modelin overfit olduğu anlaşılmaktadır.

Ağaç modeli için hiperparametre optimizasyonu

params = {'max_depth': range(1, 11),
'min_samples_split': range(2, 20)}

best_grid = GridSearchCV(cart, params, cv=5, n_jobs=-1, verbose=True).fit(X, y)
print(best_grid)
cart_final = cart.set_params(**best_grid.best_params_, random_state=1).fit(X, y)
print(f'5 katli capraz dogrulama ile rmse degeri = {np.mean(np.sqrt(-cross_val_score(cart_final, X, y, cv=5, scoring="neg_mean_squared_error")))}')

# Fitting 5 folds for each of 180 candidates, totalling 900 fits
# GridSearchCV(cv=5, estimator=DecisionTreeRegressor(), n_jobs=-1, param_grid={'max_depth': range(1, 11), 'min_samples_split': range(2, 20)}, verbose=True)
# 5 katli capraz dogrulama ile rmse degeri = 330.1964109339104
y_pred_cart_final = cart_final.predict(X)
sns.regplot(x=y, y=y_pred_cart_final, data=final_df)
plt.show()
Ağaç modeli ile yapılan tahminleme ve hiperparametre optimizasyonu sonrası deneysel değerlere karşı (x-ekseni) tahmin edilen değerler (y-ekseni)

Sonuç olarak, ağaç modelinin hiperparametre optimizasyonu sonrasında elde edilen hata değeri, lineer model ile elde edilen hata değerinden daha düşük hesaplanmıştır.

PCA görselleştirme

Burada amaç, PCA ile çok boyutlu bir veriyi iki boyutta görselleştirmektir.

Veri setini getirme ve bağımlı ve bağımsız değişkenleri seçme

dff = pd.read_csv('/kaggle/input/pca-datasets/breast_cancer.csv')
y = dff['diagnosis']
X = dff.drop(['id', 'diagnosis', 'Unnamed: 32'], axis=1)

Bu veri setindeki değişkenler, görsel veriler üzerinden numerik formlara getirilen değişkenlerdir.

Amaca yönelik veri setini indirgemek için tanımlanan ‘create_pca_df()’ fonksiyonu

def create_pca_df(X, y):
X = StandardScaler().fit_transform(X)
pca = PCA(n_components=2)
pca_fit = pca.fit_transform(X)
pca_df = pd.DataFrame(data = pca_fit, columns=['PC1', 'PC2'])
final_df = pd.concat([pca_df, pd.DataFrame(y)], axis=1)
return final_df

final_df = create_pca_df(X, y)
final_df.head()
create_pca_df fonksiyonunun çalıştırılması sonrası elde edilen yeni breast_cancer data frame

Böylece veri setinin bağımsız değişkenleri PC1 ve PC2 olmak üzere iki bileşene indirgenir.

Veri setinin iki boyuta indirgendikten sonra görselleştirilmesi

def plot_pca(dataframe, target):
fig = plt.figure(figsize=(8, 5))
ax = fig.add_subplot(1, 1, 1)
ax.set_xlabel('PC1')
ax.set_ylabel('PC2')
ax.set_title(f'{target.capitalize()}')
targets = list(dataframe[target].unique())
colors = []
while len(colors) != len(targets):
colors.append(list(np.random.random_sample(3)))

for t, color in zip(targets, colors):
indices = dataframe[target] == t
ax.scatter(dataframe.loc[indices, 'PC1'], dataframe.loc[indices, 'PC2'], color=color, s=50)

ax.legend(targets)
ax.grid()
plt.show()

plot_pca(final_df, 'diagnosis')
İki boyuta indirgenen breast_cancer veri setinin gösterimi

Yukarıda tanımlanan fonksiyon (plot_pca()) genellenebilirliği yüksek bir fonksiyon olduğundan, bunu test etmek için başka bir veri seti olan ‘iris’ veri setine bu fonksiyonu uygulayalım. Bu veri seti, çiçeklerin taç ve çanak yaprak bilgileri üzerine kurulu bir veri setidir.

iris = sns.load_dataset('iris')
y = iris['species']
X = iris.drop('species', axis=1)

‘create_pca_df’ ve ‘plot_pca’ fonksiyonları bu anlamda hemen hemen tüm ihtiyaçlar için kullanılabilir. Sadece, bu fonksiyonlara gönderilecek bağımsız değişkenlerin (X) sayısal değişkenlerden oluşması gerekmektedir.

final_df = create_pca_df(X, y)
final_df.head()
create_pca_df fonksiyonunun çalıştırılması sonrası elde edilen yeni iris data frame
plot_pca(final_df, 'species')
İki boyuta indirgenen iris veri setinin gösterimi

‘iris’ veri setine göre ‘breast_cancer’ veri setinin bileşenleri daha fazla birbirine geçmiş gibi gözükmektedir. Diğer senaryolara göre daha fazla iç içe geçme durumu var. ‘breast_cancer’ ve ‘iris’ veri setinin sınıflandırma problemine odaklanıldığında, bunların sınıflarının birbirinden daha kolay ayrıldığı görülmektedir.

Bir sonraki yazımda görüşmek üzere…

Sağlıcakla kalın…

Çalışmada kullanılan Hitters ve breast_cancer veri setlerine ilgili linkler tıklandıktan sonra ulaşılabilir.

WordPress | Kaggle | LinkedIn | GitHub | ResearchGate | Google Akademik

--

--