04/08/2023 • Mehmet Emre Toktay Banka Müşteri Segmentasyonu: K-Means, DBscan ve OPTICS ile Analiz İçindekiler 1. Giriş 2. Veri Setinin İlk İncelemesi 3. Ön İşleme 4. Keşifsel Veri Analizi (EDA) 5. Kümeleme Modelleri 5.1 K-Means 5.1.1 K-Means Normal 5.1.2 K-Means Aykırı Veri Düzeltilmiş 5.1.3 K-Means UMAP 5.1.4 K-Means PCA 5.2 DBSCAN 5.2.1 DBSCAN Normal 5.2.2 DBSCAN UMAP 5.2.3 DBSCAN PCA 5.3 OPTICS 5.3.1 OPTICS Normal 5.3.2 OPTICS UMAP 5.3.3 OPTICS PCA 6. Sonuçlar KMeans Normal UMAP PCA Outlier-free (Aykırı Değersiz) DBSCAN OPTICS Normal: UMAP & PCA: Özet Kümeleri tahminleme/anlamlandırma Küme 0 Küme 1 Küme 2 Banka Müşteri Segmentasyonu: K-Means, DBscan ve OPTICS ile Analiz 1. Giriş Bu çalışmada son altı ayda yaklaşık 9000 kredi kartı kullanıcısının kullanım davranışını içeren bir veri seti kullanılacaktır. Müşteri davranışına birkaç gruba ayırmak, etkili ve verimli bir kredi kartı pazarlama stratejisi elde etmek için gereklidir. Bu not defterinin amacı şunlardır: - Veri görselleştirme teknikleri kullanarak veri setini keşfetmek. - Modelleri kullanmadan önce veri önişleme yapmak. - Farklı kümeleme modelleri kullanarak müşterileri kümeler halinde gruplandırmak. - Oluşturulan grupların (profilleme) yorumunu ve analizini yapmak. - Yapılan profilleme sonuçlarına ve analizlere dayanarak pazarlama önerileri sunmak. Code import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.cluster import KMeans, OPTICS from sklearn.preprocessing import StandardScaler from pyclustertend import hopkins from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score, silhouette_samples from scipy.spatial.distance import pdist, squareform from mpl_toolkits.mplot3d import Axes3D from yellowbrick.cluster import SilhouetteVisualizer import umap from sklearn.neighbors import NearestNeighbors import matplotlib.cm as cm from sklearn.cluster import DBSCAN Code url = 'https://raw.githubusercontent.com/EmreToktay/pydash/main/Creditcard.csv' df = pd.read_csv(url) 2. Veri Setinin İlk İncelemesi İlk olarak elimizde bulunan veri setini biraz tanıyalım; Code print(df.shape) df.head() (8950, 19) CUST_ID BALANCE BALANCE_FREQUENCY PURCHASES ONEOFF_PURCHASES INSTALLMENTS_PURCHASES CASH_ADVANCE PURCHASES_FREQUENCY ONEOFF_PURCHASES_FREQUENCY PURCHASES_INSTALLMENTS_FREQUENCY CASH_ADVANCE_FREQUENCY CASH_ADVANCE_TRX PURCHASES_TRX CREDIT_LIMIT PAYMENTS MINIMUM_PAYMENTS PRC_FULL_PAYMENT TENURE City 0 C10001 40.900749 0.818182 95.40 0.00 95.4 0.000000 0.166667 0.000000 0.083333 0.000000 0 2 1000.0 201.802084 139.509787 0.000000 12 Bursa 1 C10002 3202.467416 0.909091 0.00 0.00 0.0 6442.945483 0.000000 0.000000 0.000000 0.250000 4 0 7000.0 4103.032597 1072.340217 0.222222 12 Şanlıurfa 2 C10003 2495.148862 1.000000 773.17 773.17 0.0 0.000000 1.000000 1.000000 0.000000 0.000000 0 12 7500.0 622.066742 627.284787 0.000000 12 Çorum 3 C10004 1666.670542 0.636364 1499.00 1499.00 0.0 205.788017 0.083333 0.083333 0.000000 0.083333 1 1 7500.0 0.000000 NaN 0.000000 12 Balıkesir 4 C10005 817.714335 1.000000 16.00 16.00 0.0 0.000000 0.083333 0.083333 0.000000 0.000000 0 1 1200.0 678.334763 244.791237 0.000000 12 Batman Başlıklarla ilgili biraz detay; BALANCE: Kredi kartınızın kullanılabilir kısmı BALANCE_FREQUENCY: Bakiyenin ne sıklıkla güncellendiği, 0 ile 1 arasında puan (1 = sıkça güncellenir, 0 = sıkça güncellenmez) PURCHASES: Hesaptan yapılan alışveriş miktarı ONEOFF_PURCHASES: Tek seferde yapılan en yüksek alışveriş miktarı INSTALLMENTS_PURCHASES: Taksitle yapılan alışveriş miktarı CASH_ADVANCE: Nakit Avans PURCHASES_FREQUENCY: Alışverişlerin ne sıklıkla yapıldığı, 0 ile 1 arasında puan (1 = sıkça alışveriş yapılır, 0 = sıkça alışveriş yapılmaz) ONEOFF_PURCHASES_FREQUENCY: Tek seferdeki alışverişlerin ne sıklıkla yapıldığı (1 = sıkça alışveriş yapılır, 0 = sıkça alışveriş yapılmaz) PURCHASES_INSTALLMENTS_FREQUENCY: Taksitli alışverişlerin ne sıklıkla yapıldığı (1 = sıkça yapılır, 0 = sıkça yapılmaz) CASH_ADVANCE_FREQUENCY: Önceden alınan naktin ne sıklıkla ödendiği CASH_ADVANCE_TRX: “Nakit Avans” ile yapılan işlem sayısı PURCHASES_TRX: Yapılan alışveriş işlemlerinin sayısı CREDIT_LIMIT: Kullanıcının kredi kartı limiti PAYMENTS: Kullanıcı tarafından yapılan ödeme miktarı MINIMUM_PAYMENTS: Kullanıcı tarafından yapılan minimum ödeme miktarı PRC_FULL_PAYMENT: Kullanıcı tarafından yapılan tam ödemenin yüzdesi TENURE: Kullanıcının kredi kartı hizmet süresi Veri tiplerini inceleyelim; Code df.info() <class 'pandas.core.frame.DataFrame'> RangeIndex: 8950 entries, 0 to 8949 Data columns (total 19 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 CUST_ID 8950 non-null object 1 BALANCE 8950 non-null float64 2 BALANCE_FREQUENCY 8950 non-null float64 3 PURCHASES 8950 non-null float64 4 ONEOFF_PURCHASES 8950 non-null float64 5 INSTALLMENTS_PURCHASES 8950 non-null float64 6 CASH_ADVANCE 8950 non-null float64 7 PURCHASES_FREQUENCY 8950 non-null float64 8 ONEOFF_PURCHASES_FREQUENCY 8950 non-null float64 9 PURCHASES_INSTALLMENTS_FREQUENCY 8950 non-null float64 10 CASH_ADVANCE_FREQUENCY 8950 non-null float64 11 CASH_ADVANCE_TRX 8950 non-null int64 12 PURCHASES_TRX 8950 non-null int64 13 CREDIT_LIMIT 8949 non-null float64 14 PAYMENTS 8950 non-null float64 15 MINIMUM_PAYMENTS 8637 non-null float64 16 PRC_FULL_PAYMENT 8950 non-null float64 17 TENURE 8950 non-null int64 18 City 8950 non-null object dtypes: float64(14), int64(3), object(2) memory usage: 1.3+ MB Her başlık için temel istatistik değerleri: Code df.describe() BALANCE BALANCE_FREQUENCY PURCHASES ONEOFF_PURCHASES INSTALLMENTS_PURCHASES CASH_ADVANCE PURCHASES_FREQUENCY ONEOFF_PURCHASES_FREQUENCY PURCHASES_INSTALLMENTS_FREQUENCY CASH_ADVANCE_FREQUENCY CASH_ADVANCE_TRX PURCHASES_TRX CREDIT_LIMIT PAYMENTS MINIMUM_PAYMENTS PRC_FULL_PAYMENT TENURE count 8950.000000 8950.000000 8950.000000 8950.000000 8950.000000 8950.000000 8950.000000 8950.000000 8950.000000 8950.000000 8950.000000 8950.000000 8949.000000 8950.000000 8637.000000 8950.000000 8950.000000 mean 1564.474828 0.877271 1003.204834 592.437371 411.067645 978.871112 0.490351 0.202458 0.364437 0.135144 3.248827 14.709832 4494.449450 1733.143852 864.206542 0.153715 11.517318 std 2081.531879 0.236904 2136.634782 1659.887917 904.338115 2097.163877 0.401371 0.298336 0.397448 0.200121 6.824647 24.857649 3638.815725 2895.063757 2372.446607 0.292499 1.338331 min 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 50.000000 0.000000 0.019163 0.000000 6.000000 25% 128.281915 0.888889 39.635000 0.000000 0.000000 0.000000 0.083333 0.000000 0.000000 0.000000 0.000000 1.000000 1600.000000 383.276166 169.123707 0.000000 12.000000 50% 873.385231 1.000000 361.280000 38.000000 89.000000 0.000000 0.500000 0.083333 0.166667 0.000000 0.000000 7.000000 3000.000000 856.901546 312.343947 0.000000 12.000000 75% 2054.140036 1.000000 1110.130000 577.405000 468.637500 1113.821139 0.916667 0.300000 0.750000 0.222222 4.000000 17.000000 6500.000000 1901.134317 825.485459 0.142857 12.000000 max 19043.138560 1.000000 49039.570000 40761.250000 22500.000000 47137.211760 1.000000 1.000000 1.000000 1.500000 123.000000 358.000000 30000.000000 50721.483360 76406.207520 1.000000 12.000000 Yukarıdaki tabloda her özelliğin yüzdelik değerlerine dayanarak, CASH_ADVANCE_TRX, PURCHASES_TRX ve TENURE özelliklerinin sürekli olmayabileceği sonucu çıkabilir. Ancak bu hipotezi kanıtlamak için kontrol edilmelidirler. Her özelliğin sayısına bakıldığında, CREDIT_LIMIT ve MINIMUM_PAYMENTS sütunlarında bazı eksik değerler bulunmaktadır. Yüzdeliklere bakıldığında, bazı özelliklerin dağılımları ağır bir şekilde skewness görülmekte ve daha ayrıntılı analiz gereklidir. Sonuç olarak, grafikleri görselleştirmek ve analiz etmek, veriyi daha derinlemesine anlamada yardımcı olabilir. 3. Ön İşleme Data setinde ki null değerlerin incelenmesi ve oranı: Code df.isna().mean()*100 CUST_ID 0.000000 BALANCE 0.000000 BALANCE_FREQUENCY 0.000000 PURCHASES 0.000000 ONEOFF_PURCHASES 0.000000 INSTALLMENTS_PURCHASES 0.000000 CASH_ADVANCE 0.000000 PURCHASES_FREQUENCY 0.000000 ONEOFF_PURCHASES_FREQUENCY 0.000000 PURCHASES_INSTALLMENTS_FREQUENCY 0.000000 CASH_ADVANCE_FREQUENCY 0.000000 CASH_ADVANCE_TRX 0.000000 PURCHASES_TRX 0.000000 CREDIT_LIMIT 0.011173 PAYMENTS 0.000000 MINIMUM_PAYMENTS 3.497207 PRC_FULL_PAYMENT 0.000000 TENURE 0.000000 City 0.000000 dtype: float64 Minimum_payments ve Credit_Limits kısımlarında boş veriler bulunmakta analizin devamı için bunlarla ilgileniyoruz; Code df.loc[(df['MINIMUM_PAYMENTS'].isnull()==True),'MINIMUM_PAYMENTS']=df['MINIMUM_PAYMENTS'].mean() df.loc[(df['CREDIT_LIMIT'].isnull()==True),'CREDIT_LIMIT']=df['CREDIT_LIMIT'].mean() Code df.isna().mean()*100 CUST_ID 0.0 BALANCE 0.0 BALANCE_FREQUENCY 0.0 PURCHASES 0.0 ONEOFF_PURCHASES 0.0 INSTALLMENTS_PURCHASES 0.0 CASH_ADVANCE 0.0 PURCHASES_FREQUENCY 0.0 ONEOFF_PURCHASES_FREQUENCY 0.0 PURCHASES_INSTALLMENTS_FREQUENCY 0.0 CASH_ADVANCE_FREQUENCY 0.0 CASH_ADVANCE_TRX 0.0 PURCHASES_TRX 0.0 CREDIT_LIMIT 0.0 PAYMENTS 0.0 MINIMUM_PAYMENTS 0.0 PRC_FULL_PAYMENT 0.0 TENURE 0.0 City 0.0 dtype: float64 Müşteri Segmentasyonu için gerekli olmayan iki başlığı düşürüyoruz, bu başlıklar analiz sonrası tekrar eklenecektir. Code df = df.drop(columns=['City', 'CUST_ID']) 4. Keşifsel Veri Analizi (EDA) 🔍 Datayı görselleştirmek için Sweetviz kütüphanesini kullandım, Sweetvizle ilgili; Python için bir veri görselleştirme kütüphanesidir. Eksploratif veri analizi (Exploratory Data Analysis - EDA) amacıyla tasarlanmıştır. Bir veya iki veri çerçevesini (DataFrame) hızla görselleştirerek detaylı ve görsel olarak çekici raporlar üretir. Code import sweetviz as sv # Veriyi analiz edin report = sv.analyze(df) # Raporu doğrudan Jupyter Notebook'ta göstermek için aşağıdaki kodu kullanabilirsiniz (isteğe bağlı) report.show_notebook() PURCHASES_FREQUENCY dışında, başlıkların hiçbirinde dengeli bir dağılım görülmemektedir. Ayrıca, PURCHASES_FREQUENCY bile normal bir dağılıma sahip değildir! Önceki bölümde belirtildiği gibi, bazı başlıklarda ağır bir şekilde skewness(çarpıklık) mevcutır. Sonuç olarak outlierları (aykırı değerleri), bulmak için daha ayrıntılı bir inceleme yapılması gerekmektedir. Ayrıca, alışılagelmiş kümeleme algoritmaları yeterince verimli olmayabilir. Veri ölçeklendirmesi, makine öğrenimi algoritmalarının daha etkili çalışmasını sağlamak için genellikle kullanılır. Özellikle, birçok algoritma, özellikler arasındaki farklı ölçekler nedeniyle yanıltıcı sonuçlar üretebilir. Bu nedenle, tüm özellikleri benzer bir ölçeğe getirmek önemlidir. Kullandığımız ölçeklendirme yöntemi StandardScalerdır. StandardScaler, her özelliği, ortalaması 0 ve standart sapması 1 olacak şekilde ölçeklendirir. Bu, z-skor normalleştirmesi olarak da bilinir. Code scaler = StandardScaler() df_scaled = scaler.fit_transform(df) Bu kod ile verimiz başarılı bir şekilde ölçeklendirilmiş oldu ve model eğitimi veya diğer analizler için hazır hale getirildi. Hopkins İstatistiği Kümeleme analizine başlamadan önce veri setinin kümelemeye uygun olup olmadığını kontrol etmek önemlidir. Bu amaçla, veri setinin rastgele dağılıp dağılmadığını kontrol etmek için Hopkins İstatistiği kullanılır. Hopkins İstatistiği, bir veri setinin kümelemeye ne kadar uygun olduğunu ölçen bir testtir. Değerin 0.5’e yakın olması, verinin rastgele bir dağılıma sahip olduğunu ve bu nedenle kümelemeye uygun olmadığını gösterir. Öte yandan, değer 0.7’den büyükse, veri kümesi muhtemelen kümelemeye uygundur. Code hopkins_score = hopkins(df_scaled, sampling_size=len(df_scaled)) print(hopkins_score) 0.034992587280613066 Bu sonuca göre, 0.0351 değeri Hopkins İstatistiği için oldukça düşüktür, bu da veri kümesinin belirgin bir yapıya veya kümeye sahip olmadığını, dolayısıyla kümelemeye pek uygun olmadığını gösterir. Data setinin genel yapısına önceden baktığımızda aşırı outlier ve skewness olduğunu görmüştük bu yüzden hopkins skorunun tüm data üstünde kullanılması yanıltıcı olabilir. Bu yüzden rastgele %10 luk veri üzerinde tekrardan hopkins testi uyguladım; Code import numpy as np from random import sample from sklearn.neighbors import NearestNeighbors from numpy.random import uniform from math import isnan def hopkins(X): d = X.shape[1] n = len(X) m = int(0.1 * n) nbrs = NearestNeighbors(n_neighbors=1).fit(X) rand_X = sample(range(0, n, 1), m) ujd = [] wjd = [] for j in range(0, m): u_dist, _ = nbrs.kneighbors(uniform(np.amin(X,axis=0),np.amax(X,axis=0),d).reshape(1, -1), 2, return_distance=True) ujd.append(u_dist[0][1]) w_dist, _ = nbrs.kneighbors(X[rand_X[j]].reshape(1, -1), 2, return_distance=True) wjd.append(w_dist[0][1]) H = sum(ujd) / (sum(ujd) + sum(wjd)) if isnan(H): print(ujd, wjd) H = 0 return H # Hopkins Testini Gerçekleştir hopkins_value = hopkins(df_scaled) hopkins_result = 'Sonuç: {:.4f}'.format(hopkins_value) print('.: Hopkins Testi :.') print(hopkins_result) if 0.7 < hopkins_value < 0.99: print('>> Yukarıdaki sonuca göre, yüksek bir kümeleme eğilimi var (anlamlı kümeler içeriyor)') print('.:. Sonuçlar: H0 Kabul .:.') else: print('>> Yukarıdaki sonuca göre, anlamlı kümeler yok') print('.:. Sonuçlar: H0 Red .:.') .: Hopkins Testi :. Sonuç: 0.9672 >> Yukarıdaki sonuca göre, yüksek bir kümeleme eğilimi var (anlamlı kümeler içeriyor) .:. Sonuçlar: H0 Kabul .:. Veri kümesinin tamamı üzerinden yapılan ilk Hopkins istatistiği testinde, verinin rastgele bir dağılıma kıyasla ne kadar kümeleme eğilimli olduğuna dair düşük bir değer elde ettik. Bu sonuç, ilk bakışta verinin belirgin kümeler içermediğini veya kümelerin ayrımının zor olduğunu gösteriyor olabilir. %10’luk rastgele bir alt küme üzerinde yapılan Hopkins testinin sonucu, verinin yüksek bir kümeleme eğilimine sahip olduğunu gösterdi. Sonuç olarak, geniş veri kümelerinin analizinde, hem tüm veri seti üzerinde hem de rastgele alt kümeler üzerinde analiz yapmanın avantajları vardır. Her iki yaklaşımın da sonuçları, veri setinin genel yapısının ve kümeleme eğiliminin daha bütünsel bir anlayışını sağlar. Data setinde bulunan aykırı değerlerinin ortalamasını inceleme zamanı geldi Aykırı değerleri tespit etmek için IQR (çeyrekler arası aralık) metodunu kullandık. ; Code outlier_percentage = {} for feature in df: tempData = df.sort_values(by=feature)[feature] Q1, Q3 = tempData.quantile([0.25, 0.75]) IQR = Q3 - Q1 Lower_range = Q1 - (1.5 * IQR) Upper_range = Q3 + (1.5 * IQR) outlier_count = ((tempData < Lower_range) | (tempData > Upper_range)).sum() outlier_perc = round((outlier_count / tempData.shape[0]) * 100, 2) outlier_percentage[feature] = outlier_perc outlier_percentage {'BALANCE': 7.77, 'BALANCE_FREQUENCY': 16.68, 'PURCHASES': 9.03, 'ONEOFF_PURCHASES': 11.32, 'INSTALLMENTS_PURCHASES': 9.69, 'CASH_ADVANCE': 11.51, 'PURCHASES_FREQUENCY': 0.0, 'ONEOFF_PURCHASES_FREQUENCY': 8.74, 'PURCHASES_INSTALLMENTS_FREQUENCY': 0.0, 'CASH_ADVANCE_FREQUENCY': 5.87, 'CASH_ADVANCE_TRX': 8.98, 'PURCHASES_TRX': 8.56, 'CREDIT_LIMIT': 2.77, 'PAYMENTS': 9.03, 'MINIMUM_PAYMENTS': 8.65, 'PRC_FULL_PAYMENT': 16.47, 'TENURE': 15.26} Bu sonuçlara göre, bazı özelliklerde; örneğin BALANCE_FREQUENCY, PRC_FULL_PAYMENT ve TENURE aykırı değerlerin yüzdesi oldukça yüksektir. Bu özelliklerin veri seti üzerindeki etkilerini ve bu aykırı değerlerin nasıl işleneceğini değerlendirmemiz gerekmektedir. Diğer yandan, bazı özelliklerde; PURCHASES_FREQUENCY ve PURCHASES_INSTALLMENTS_FREQUENCY aykırı değer bulunmamaktadır. Aykırı değerler, analizlerimiz ve modellemelerimiz üzerinde olumsuz etkilere sahip olabileceğinden, bu değerlerle ilgili stratejiler geliştirmemiz önemlidir. Bu stratejiler, aykırı değerlerin silinmesi, dönüştürülmesi veya başka bir yöntemle işlenmesi şeklinde olabilir. Aykırı değerlerle ilgili her zaman işlem yapılması zorunluluk değildir bazı durumlarda yanıltıcı bile olabilir. Yine de ilerleyen analizlerde aykırı değerler üstünde işlem yapılmış bir veri seti oluşturdum, bu sayede farklı sonuçları inceleme fırsatım oldu. Code def preprocess_data(data): feature_boundaries = { 'BALANCE': [0, 500, 1000, 3000, 5000, 10000], 'PURCHASES': [0, 500, 1000, 3000, 5000, 10000], 'ONEOFF_PURCHASES': [0, 500, 1000, 3000, 5000, 10000], 'INSTALLMENTS_PURCHASES': [0, 500, 1000, 3000, 5000, 10000], 'CASH_ADVANCE': [0, 500, 1000, 3000, 5000, 10000], 'CREDIT_LIMIT': [0, 500, 1000, 3000, 5000, 10000], 'PAYMENTS': [0, 500, 1000, 3000, 5000, 10000], 'MINIMUM_PAYMENTS': [0, 500, 1000, 3000, 5000, 10000] } frequency_boundaries = { 'BALANCE_FREQUENCY': [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9], 'PURCHASES_FREQUENCY': [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9], 'ONEOFF_PURCHASES_FREQUENCY': [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9], 'PURCHASES_INSTALLMENTS_FREQUENCY': [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9], 'CASH_ADVANCE_FREQUENCY': [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9], 'PRC_FULL_PAYMENT': [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9] } trx_boundaries = { 'PURCHASES_TRX': [0, 5, 10, 15, 20, 30, 50, 100], 'CASH_ADVANCE_TRX': [0, 5, 10, 15, 20, 30, 50, 100] } def assign_range(column, boundaries): new_column = column + '_RANGE' data[new_column] = 0 for idx, boundary in enumerate(boundaries): if idx == len(boundaries) - 1: data.loc[data[column] > boundary, new_column] = idx + 1 else: data.loc[(data[column] > boundary) & (data[column] <= boundaries[idx + 1]), new_column] = idx + 1 for column, boundaries in feature_boundaries.items(): assign_range(column, boundaries) for column, boundaries in frequency_boundaries.items(): assign_range(column, boundaries) for column, boundaries in trx_boundaries.items(): assign_range(column, boundaries) columns_to_drop = [ 'BALANCE', 'BALANCE_FREQUENCY', 'PURCHASES', 'ONEOFF_PURCHASES', 'INSTALLMENTS_PURCHASES', 'CASH_ADVANCE', 'PURCHASES_FREQUENCY', 'ONEOFF_PURCHASES_FREQUENCY', 'PURCHASES_INSTALLMENTS_FREQUENCY', 'CASH_ADVANCE_FREQUENCY', 'CASH_ADVANCE_TRX', 'PURCHASES_TRX', 'CREDIT_LIMIT', 'PAYMENTS', 'MINIMUM_PAYMENTS', 'PRC_FULL_PAYMENT' ] df_wo = df.drop(columns=columns_to_drop) return df_wo Code df_wo = preprocess_data(df) Bu veri ön işleme fonksiyonu, bazı belirli sütunları kategorik aralıklara ayırmak için oluşturulmuştur. Bu sütunlar için önceden tanımlanmış sınırlar kullanılarak, bu sınırlara dayalı olarak yeni özellikler türetilmiştir. İlgili özelliklerin sayısal değerleri korunurken, bu değerlere karşılık gelen kategorik aralıkları belirleyen yeni sütunlar oluşturulmuştur. Özellik Sınırları: Belirli sütunlar için değer aralıklarını temsil eden sınırlar belirlenmiştir. Örneğin, ‘BALANCE’ sütunu için sınırlar: 0, 500, 1000, 3000, 5000, 10000 olarak tanımlanmıştır. Bu sınırlar, belirli bir özellikteki değerlerin hangi aralıkta olduğunu belirlemek için kullanılır. Sınırların Uygulanması: Her bir sütun için assign_range adında bir yardımcı fonksiyon kullanılmıştır. Bu fonksiyon, belirli bir sütunun değerlerini alarak bu değerleri tanımlanan sınırlara göre kategorik bir sütuna dönüştürür. Örneğin, ‘BALANCE’ sütunu için 750 değerine sahip bir gözlem, ‘BALANCE_RANGE’ sütununda 2 değerine sahip olacaktır. Çünkü bu değer 500 ile 1000 arasında yer almaktadır. Gereksiz Sütunların Kaldırılması: Kategorik aralıklara dönüştürülen sütunların orijinal sayısal sütunları gereksiz hale gelmiştir. Bu nedenle, bu sütunlar veri setinden kaldırılmıştır. Sonuç olarak, bu fonksiyon, belirli sütunları kategorik aralıklara dönüştürmek için kullanılır ve bu dönüşümün ardından orijinal sayısal sütunları veri setinden kaldırır. 5. Kümeleme Modelleri İncelemede 3 farklı kümeleme yöntemini farklı metodolojilerle deneyip en ideal olanı bulmaya çalışcaz. Kümeleme modelleri için K-Means, DBSCAN ve OPTICS yöntemlerini kullanacağım. K-means için işlenmemiş dataset, aykırı veriler için işlem yapılmış dataseti, PCA ve UMAP uygulanmış datasetlerini kullanacağım. DBSCAN ve OPTICS doğası gereği aykırı değerlerden çok fazla etkilenmediği için normal, PCA ve UMAP data setleri kullanılarak sonuçlar alınacaktır. Code results = { "KMeans": { "normal": {}, "umap": {}, "pca": {}, "outlier_free": {} }, "DBSCAN": { "normal": {}, "umap": {}, "pca": {} }, "OPTICS": { "normal": {}, "umap": {}, "pca": {} } } Bu kod, farklı kümeleme algoritmalarının sonuçlarını ve performans metriklerini saklamak üzere bir yapı inşa ediyor. Özellikle, KMeans, DBSCAN ve OPTICS kümeleme algoritmalarının sonuçlarını değerlendiriyoruz. Ayrıca, bu algoritmaları normal, UMAP indirgenmiş, PCA indirgenmiş ve aykırı değer içermeyen veri setleri üzerinde de test edeceğiz. Analiz için yaptığım yol haritasının şemasını bu kodda görebilirsiniz. Kısaca bahsetmek gerekirse. KMeans: Veriyi belirli bir “k” sayısı olacak şekilde kümeye ayırmak için bir algoritmadır. DBSCAN: Yoğunluk tabanlı bir kümeleme algoritmasıdır ve küme sayısını önceden belirtmeye gerek duymaz. OPTICS: Yoğunluk tabanlı bir kümeleme algoritması olan DBSCAN’in genelleştirilmiş bir versiyonudur. UMAP: Veriyi daha az boyutlu bir uzaya indirgemek için kullanılan bir boyut indirgeme yöntemidir. PCA: Principal Component Analysis’in kısaltmasıdır ve veriyi az sayıda özellikle temsil etmek için kullanılır. Silhouette Coefficient: Bir kümenin içsel uyumu ve kümeler arasındaki ayrımı ölçen bir metrik. Calinski-Harabasz Index: Küme dağılımının kalitesini ölçen bir skor. Davies-Bouldin Index: Küme içi benzerlikleri ile kümeler arası benzerliklerin oranını ölçer. Düşük değerler daha iyi kümelemeyi gösterir. 5.1 K-Means K-Means, veriyi belirlenen ‘k’ sayıda kümeye bölmek için kullanılan bir kümeleme algoritmasıdır. Algoritma, her bir küme merkezini rastgele başlatarak çalışır ve ardından bu merkezleri, kümelerdeki veri noktalarının ortalaması olacak şekilde iteratif olarak günceller. Bu süreç, belirlenen bir kriteri (örneğin, merkezlerin hareket etmediği bir durumu) karşılayana kadar devam eder. K-Means sürecini destekleyici olarak dirsek yöntemi ve Silhouette skoru kullanıldı; Dirsek Yöntemi (Elbow Method) K-means algoritması için en zor kararların başında, verinin kaç kümeye ayrılması gerektiğini belirlemek gelir. Dirsek yöntemi, bu kararı vermek için kullanılan yaygın bir tekniktir. Bu yöntem, farklı k değerleri için toplam iç kareler toplamının (WCSS) hesaplanmasını içerir. K değerinin artmasıyla WCSS azalır. Ancak belirli bir k değerinden sonra, bu azalma miktarı önemsiz hale gelir. Bu “dirsek” olarak adlandırılan nokta, optimal k değerini belirlememize yardımcı olur. Silhouette Skoru Silhouette skoru, kümelerin ne kadar iyi tanımlandığını ölçer. Bu skor, -1 ile 1 arasında değerler alır. 1’e yakın bir değer, noktaların kendi kümelerinde benzer ve diğer kümelerden farklı olduğunu gösterirken, -1’e yakın bir değer bu noktaların yanlış kümelenmiş olduğunu gösterir. 0 değeri, kümelerin birbirinden ne kadar ayrıldığı konusunda belirsizlik olduğunu gösterir. 5.1.1 K-Means Normal Code k_values = range(1, 11) wcss = [] silhouette_scores = [] for k in k_values: kmeans = KMeans(n_clusters=k, init='k-means++', max_iter=300, n_init=10, random_state=0) kmeans.fit(df_scaled) wcss.append(kmeans.inertia_) if k > 1: silhouette_scores.append(silhouette_score(df_scaled, kmeans.labels_)) else: silhouette_scores.append(0) fig, ax1 = plt.subplots(figsize=(12, 7)) ax1.set_xlabel('Küme Sayısı (k)') ax1.set_ylabel('WCSS', color='tab:blue') ax1.plot(k_values, wcss, 'o-', color='tab:blue') ax1.tick_params(axis='y', labelcolor='tab:blue') ax2 = ax1.twinx() ax2.set_ylabel('Silhouette Skoru', color='tab:orange') ax2.plot(k_values, silhouette_scores, 'o-', color='tab:orange') ax2.tick_params(axis='y', labelcolor='tab:orange') fig.tight_layout() plt.title('Dirsek Yöntemi ve Silhouette Skoru') plt.show() Grafiğin Değerlendirilmesi Grafiği değerlendirirken şunlara dikkat edilmelidir: Dirsek Noktası: WCSS grafiğini (mavi çizgi) incelerken, WCSS’nin önemli ölçüde azalmadığı k değerini arayın. Bu nokta, optimal k değerini belirlememiz için bir ipucu olarak kullanılabilir. Silhouette Skoru: Silhouette skoru grafiğini (turuncu çizgi) incelerken, en yüksek skorlu k değerini arayın. Yüksek bir silhouette skoru, iyi tanımlanmış kümeler olduğunu gösterir. Bu iki ölçümü birlikte kullanarak, veri kümesi için en uygun k değerini belirleyebilirsiniz. Code kmeans = KMeans(n_clusters=4, init='k-means++', max_iter=300, n_init=10, random_state=0) kmeans.fit(df_scaled) labels = kmeans.labels_ fig = plt.figure(figsize=(10, 8)) ax = fig.add_subplot(111, projection='3d') colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'] for i, color in enumerate(colors): ax.scatter(df_scaled[labels == i, 0], df_scaled[labels == i, 1], df_scaled[labels == i, 2], c=color, label=f'Cluster {i+1}', s=50) ax.set_title("3D Scatter Plot of Clusters") ax.set_xlabel("Feature 1") ax.set_ylabel("Feature 2") ax.set_zlabel("Feature 3") ax.legend() plt.show() silhouette_vals = silhouette_samples(df_scaled, labels) fig, ax = plt.subplots(1, 1, figsize=(8, 6)) y_lower = 10 for i in range(4): ith_cluster_silhouette_values = silhouette_vals[labels == i] ith_cluster_silhouette_values.sort() size_cluster_i = ith_cluster_silhouette_values.shape[0] y_upper = y_lower + size_cluster_i color = cm.nipy_spectral(float(i) / 4) ax.fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_silhouette_values, facecolor=color, edgecolor=color, alpha=0.7) ax.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i+1)) y_lower = y_upper + 10 ax.set_title("Silhouette Plot for the Clusters") ax.set_xlabel("Silhouette Coefficient Values") ax.set_ylabel("Cluster Label") ax.set_yticks([]) ax.axvline(x=silhouette_score(df_scaled, labels), color="red", linestyle="--") plt.show() cluster_counts = np.bincount(labels) total_count = len(labels) percentages = (cluster_counts / total_count) * 100 plt.figure(figsize=(8, 8)) plt.pie(percentages, labels=[f'Cluster {i+1}' for i in range(4)], colors=colors, autopct='%1.1f%%', shadow=True, startangle=140) plt.title("Percentage Distribution of Clusters") plt.show() 1. 3D Küme Dağılım Grafiği Bu grafik, ölçeklendirilmiş veri setindeki kümelerin 3 boyutlu bir uzayda nasıl dağıldığını gösterir. Her renk, farklı bir kümeyi temsil eder. Gözlem: Eğer kümeler birbirinden belirgin bir şekilde ayrılıyorsa, bu, K-Means algoritmasının iyi bir şekilde kümeleme yaptığını gösterir. 2. Silhouette Grafiği Silhouette grafiği, her veri noktasının kendi kümesi içindeki diğer veri noktalarına ne kadar yakın olduğunu ve en yakın diğer kümeye ne kadar uzak olduğunu değerlendirir. Bantlar: Her bant, belirli bir kümeyi temsil eder. Bantın genişliği, o kümedeki veri noktalarının sayısını gösterirken, yüksekliği silhouette skorunu temsil eder. Kırmızı Çizgi: Ortalama silhouette skoru. Bu çizgiye yakın veya üzerinde değerlere sahip kümelerin iyi tanımlanmış olduğunu söyleyebiliriz. Gözlem: Eğer bantlar kırmızı çizgiye yakın veya onun üzerindeyse ve bant genişlikleri benzerse, bu, kümelerin dengeli ve iyi tanımlanmış olduğunu gösterir. 3. Küme Dağılım Yüzdelikleri Grafiği Bu pasta grafiği, her bir kümeye düşen veri noktalarının yüzdelik dağılımını gösterir. Gözlem: Eğer dilimler benzer boyutlardaysa, bu, kümelerin dengeli bir şekilde dağıldığını gösterir. Ancak bir veya birden fazla dilimin diğerlerine göre çok büyük veya çok küçük olduğunu görürseniz, bu, belirli kümelerin diğerlerinden daha fazla veya daha az veri noktasına sahip olduğunu gösterir. Code kmeans = KMeans(n_clusters=3) labels = kmeans.fit_predict(df_scaled) results["KMeans"]["normal"]["Silhouette Coefficient"] = silhouette_score(df_scaled, labels) results["KMeans"]["normal"]["Calinski-Harabasz Index"] = calinski_harabasz_score(df_scaled, labels) results["KMeans"]["normal"]["Davies-Bouldin Index"] = davies_bouldin_score(df_scaled, labels) for metric, value in results["KMeans"]["normal"].items(): print(f"{metric}: {value:.2f}") Silhouette Coefficient: 0.25, Calinski-Harabasz Index: 1604.40, Davies-Bouldin Index: 1.60 Sonuçların Değerlendirilmesi Kod çalıştırıldığında elde edilen sonuçların anlamını ve nasıl değerlendirileceğini aşağıda bulabilirsiniz: Silhouette Coefficient: Bu değer -1 ile 1 arasında değişir. 1’e yakın bir değer, kümelerin iyi tanımlandığını gösterirken, -1’e yakın bir değer, kümelerin yanlış tanımlandığını gösterir. 0, kümelerin birbirine yakın olduğunu veya çakıştığını gösterir. Calinski-Harabasz Index: Daha yüksek bir değer, kümelerin daha iyi tanımlandığını gösterir. Bu ölçüt, kümelerin yoğunluğu ve dağılımı arasındaki oranı ölçer. Davies-Bouldin Index: Düşük değerler kümelerin daha iyi tanımlandığını gösterir. Bu indeks, her küme için benzerlik oranını ölçer ve bu oranın ortalama değerini alır. Bu metrikleri kullanarak, farklı algoritmaların veya aynı algoritmanın farklı parametreleriyle elde edilen kümelenme sonuçlarının kalitesini karşılaştırabilir ve hangi yaklaşımın veriniz için en uygun olduğuna karar verebilirsiniz. Bu sonuçların genel değerlendirmesini analizin en sonunda paylaşacağım. 5.1.2 K-Means Aykırı Veri Düzeltilmiş Code df_wo = preprocess_data(df) Code k_values = range(1, 11) wcss = [] silhouette_scores = [] for k in k_values: kmeans = KMeans(n_clusters=k, init='k-means++', max_iter=300, n_init=10, random_state=0) kmeans.fit(df_wo) wcss.append(kmeans.inertia_) if k > 1: silhouette_scores.append(silhouette_score(df_wo, kmeans.labels_)) else: silhouette_scores.append(0) fig, ax1 = plt.subplots(figsize=(12, 7)) ax1.set_xlabel('Küme Sayısı (k)') ax1.set_ylabel('WCSS', color='tab:blue') ax1.plot(k_values, wcss, 'o-', color='tab:blue') ax1.tick_params(axis='y', labelcolor='tab:blue') ax2 = ax1.twinx() ax2.set_ylabel('Silhouette Skoru', color='tab:orange') ax2.plot(k_values, silhouette_scores, 'o-', color='tab:orange') ax2.tick_params(axis='y', labelcolor='tab:orange') fig.tight_layout() plt.title('Dirsek Yöntemi ve Silhouette Skoru') plt.show() Code kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300, n_init=10, random_state=0) kmeans.fit(df_wo) labels = kmeans.labels_ fig = plt.figure(figsize=(10, 8)) ax = fig.add_subplot(111, projection='3d') colors = ['#1f77b4', '#ff7f0e', '#2ca02c'] for i, color in enumerate(colors): ax.scatter(df_wo[labels == i].iloc[:, 0], df_wo[labels == i].iloc[:, 1], df_wo[labels == i].iloc[:, 2], c=color, label=f'Cluster {i+1}', s=50) ax.set_title("3D Scatter Plot of Clusters") ax.set_xlabel("Feature 1") ax.set_ylabel("Feature 2") ax.set_zlabel("Feature 3") ax.legend() plt.show() silhouette_vals = silhouette_samples(df_wo, labels) fig, ax = plt.subplots(1, 1, figsize=(8, 6)) y_lower = 10 for i in range(3): ith_cluster_silhouette_values = silhouette_vals[labels == i] ith_cluster_silhouette_values.sort() size_cluster_i = ith_cluster_silhouette_values.shape[0] y_upper = y_lower + size_cluster_i color = cm.nipy_spectral(float(i) / 3) ax.fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_silhouette_values, facecolor=color, edgecolor=color, alpha=0.7) ax.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i+1)) y_lower = y_upper + 10 ax.set_title("Silhouette Plot for the Clusters") ax.set_xlabel("Silhouette Coefficient Values") ax.set_ylabel("Cluster Label") ax.set_yticks([]) ax.axvline(x=silhouette_score(df_wo, labels), color="red", linestyle="--") plt.show() cluster_counts = np.bincount(labels) total_count = len(labels) percentages = (cluster_counts / total_count) * 100 plt.figure(figsize=(8, 8)) plt.pie(percentages, labels=[f'Cluster {i+1}' for i in range(3)], colors=colors, autopct='%1.1f%%', shadow=True, startangle=140) plt.title("Percentage Distribution of Clusters") plt.show() Code kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300, n_init=10, random_state=0) labels = kmeans.fit_predict(df_wo) results["KMeans"]["outlier_free"]["Silhouette Coefficient"] = silhouette_score(df_wo, labels) results["KMeans"]["outlier_free"]["Calinski-Harabasz Index"] = calinski_harabasz_score(df_wo, labels) results["KMeans"]["outlier_free"]["Davies-Bouldin Index"] = davies_bouldin_score(df_wo, labels) for metric, value in results["KMeans"]["outlier_free"].items(): print(f"{metric}: {value:.2f}") Silhouette Coefficient: 0.32 Calinski-Harabasz Index: 4345.55 Davies-Bouldin Index: 1.42 5.1.3 K-Means UMAP UMAP (Uniform Manifold Approximation and Projection) UMAP, yüksek boyutlu veri setlerini düşük boyutlu bir uzaya görselleştirmek için kullanılan modern bir boyut indirgeme tekniğidir. Özellikle büyük veri setleri için hızlı ve ölçeklenebilir olmasıyla bilinir. Yerel ve Global Yapının Korunması: UMAP, verinin hem yerel hem de global yapılarını korumayı amaçlar. Bu, özellikle karmaşık veri yapıları için faydalıdır. Genel Uygulamalar: UMAP sadece görselleştirme için değil, aynı zamanda genel boyut indirgeme uygulamaları için de kullanılabilir. UMAP’in en büyük avantajlarından biri, t-SNE gibi diğer boyut indirgeme yöntemlerine göre daha hızlı çalışması ve daha genel kullanım özelliklerine sahip olmasıdır. Code reducer = umap.UMAP() embedding = reducer.fit_transform(df_scaled) df_umap = pd.DataFrame(embedding, columns=['UMAP 1', 'UMAP 2']) plt.figure(figsize=(12, 8)) plt.scatter(df_umap['UMAP 1'], df_umap['UMAP 2'], cmap='Spectral', s=5) plt.gca().set_aspect('equal', 'datalim') plt.colorbar(boundaries=np.arange(11)-0.5).set_ticks(np.arange(10)) plt.title('UMAP Projection', fontsize=24); plt.show() Code k_values = range(1, 11) wcss = [] silhouette_scores = [] for k in k_values: kmeans = KMeans(n_clusters=k, init='k-means++', max_iter=300, n_init=10, random_state=0) kmeans.fit(df_umap) wcss.append(kmeans.inertia_) if k > 1: silhouette_scores.append(silhouette_score(df_umap, kmeans.labels_)) else: silhouette_scores.append(0) fig, ax1 = plt.subplots(figsize=(12, 7)) ax1.set_xlabel('Küme Sayısı (k)') ax1.set_ylabel('WCSS', color='tab:blue') ax1.plot(k_values, wcss, 'o-', color='tab:blue') ax1.tick_params(axis='y', labelcolor='tab:blue') ax2 = ax1.twinx() ax2.set_ylabel('Silhouette Skoru', color='tab:orange') ax2.plot(k_values, silhouette_scores, 'o-', color='tab:orange') ax2.tick_params(axis='y', labelcolor='tab:orange') fig.tight_layout() plt.title('Dirsek Yöntemi ve Silhouette Skoru') plt.show() Code kmeans = KMeans(n_clusters=2, init='k-means++', max_iter=300, n_init=10, random_state=0) kmeans.fit(df_umap) labels = kmeans.labels_ umap_array = df_umap.values fig = plt.figure(figsize=(10, 8)) colors = ['#1f77b4', '#ff7f0e'] for i, color in enumerate(colors): plt.scatter(umap_array[labels == i, 0], umap_array[labels == i, 1], c=color, label=f'Cluster {i+1}', s=50) plt.title("2D Scatter Plot of Clusters") plt.xlabel("Feature 1") plt.ylabel("Feature 2") plt.legend() plt.show() silhouette_vals = silhouette_samples(df_umap, labels) fig, ax = plt.subplots(1, 1, figsize=(8, 6)) y_lower = 10 for i in range(2): ith_cluster_silhouette_values = silhouette_vals[labels == i] ith_cluster_silhouette_values.sort() size_cluster_i = ith_cluster_silhouette_values.shape[0] y_upper = y_lower + size_cluster_i color = cm.nipy_spectral(float(i) / 2) ax.fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_silhouette_values, facecolor=color, edgecolor=color, alpha=0.7) ax.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i+1)) y_lower = y_upper + 10 ax.set_title("Silhouette Plot for the Clusters") ax.set_xlabel("Silhouette Coefficient Values") ax.set_ylabel("Cluster Label") ax.set_yticks([]) ax.axvline(x=silhouette_score(df_scaled, labels), color="red", linestyle="--") plt.show() Code kmeans_umap = KMeans(n_clusters=2, init='k-means++', max_iter=300, n_init=10, random_state=0) labels_umap = kmeans_umap.fit_predict(df_umap) results["KMeans"]["umap"]["Silhouette Coefficient"] = silhouette_score(df_umap, labels_umap) results["KMeans"]["umap"]["Calinski-Harabasz Index"] = calinski_harabasz_score(df_umap, labels_umap) results["KMeans"]["umap"]["Davies-Bouldin Index"] = davies_bouldin_score(df_umap, labels_umap) for metric, value in results["KMeans"]["umap"].items(): print(f"{metric}: {value:.2f}") Silhouette Coefficient: 0.42 Calinski-Harabasz Index: 8208.00 Davies-Bouldin Index: 0.95 5.1.4 K-Means PCA PCA (Principal Component Analysis) PCA, çok değişkenli veri setlerinde değişkenler arasındaki varyansı maksimize ederek boyut indirgeme yapmak için kullanılan istatistiksel bir yöntemdir. Temel bileşenler, verinin ana yapısını yakalamak için ortogonal bir şekilde seçilir. Varyansın Maksimizasyonu: PCA, veri setindeki maksimum varyansı yakalamak için ana bileşenleri seçer. Düşük Boyutlu Gösterim: Veri setini daha az sayıda özellikle temsil ederek, görselleştirme ve modelleme için kullanışlı bir hale getirir. Açıklanan Varyans: Her bileşenin veri setinde ne kadar varyansı açıkladığına dair bilgi sağlar, böylece en önemli bileşenleri seçmek daha kolay hale gelir. PCA, veri bilimi ve makine öğrenimi uygulamalarında sıkça kullanılan popüler bir boyut indirgeme yöntemidir. Code from sklearn.decomposition import PCA pca = PCA(n_components=2) df_pca = pca.fit_transform(df_scaled) print(df_pca.shape) explained_variance = pca.explained_variance_ratio_ print(f"Explained Variance (first two components): {100 * explained_variance.sum():.2f}%") (8950, 2) Explained Variance (first two components): 47.59% Code k_values = range(1, 11) wcss = [] silhouette_scores = [] for k in k_values: kmeans = KMeans(n_clusters=k, init='k-means++', max_iter=300, n_init=10, random_state=0) kmeans.fit(df_pca) wcss.append(kmeans.inertia_) if k > 1: silhouette_scores.append(silhouette_score(df_pca, kmeans.labels_)) else: silhouette_scores.append(0) fig, ax1 = plt.subplots(figsize=(12, 7)) ax1.set_xlabel('Küme Sayısı (k)') ax1.set_ylabel('WCSS', color='tab:blue') ax1.plot(k_values, wcss, 'o-', color='tab:blue') ax1.tick_params(axis='y', labelcolor='tab:blue') ax2 = ax1.twinx() ax2.set_ylabel('Silhouette Skoru', color='tab:orange') ax2.plot(k_values, silhouette_scores, 'o-', color='tab:orange') ax2.tick_params(axis='y', labelcolor='tab:orange') fig.tight_layout() plt.title('Dirsek Yöntemi ve Silhouette Skoru') plt.show() Code kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300, n_init=10, random_state=0) kmeans.fit(df_pca) kmeans_labels_pca = kmeans.labels_ fig = plt.figure(figsize=(10, 8)) colors = ['#1f77b4', '#ff7f0e', '#2ca02c'] for i, color in enumerate(colors): plt.scatter(df_pca[kmeans_labels_pca == i, 0], df_pca[kmeans_labels_pca == i, 1], c=color, label=f'Cluster {i+1}', s=50) plt.title("2D Scatter Plot of Clusters") plt.xlabel("Feature 1") plt.ylabel("Feature 2") plt.legend() plt.show() silhouette_vals = silhouette_samples(df_pca, kmeans_labels_pca) fig, ax = plt.subplots(1, 1, figsize=(8, 6)) y_lower = 10 for i in range(3): ith_cluster_silhouette_values = silhouette_vals[kmeans_labels_pca == i] ith_cluster_silhouette_values.sort() size_cluster_i = ith_cluster_silhouette_values.shape[0] y_upper = y_lower + size_cluster_i color = cm.nipy_spectral(float(i) / 3) ax.fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_silhouette_values, facecolor=color, edgecolor=color, alpha=0.7) ax.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i+1)) y_lower = y_upper + 10 ax.set_title("Silhouette Plot for the Clusters") ax.set_xlabel("Silhouette Coefficient Values") ax.set_ylabel("Cluster Label") ax.set_yticks([]) ax.axvline(x=silhouette_score(df_scaled, kmeans_labels_pca), color="red", linestyle="--") plt.show() Code kmeans_pca = KMeans(n_clusters=3, init='k-means++', max_iter=300, n_init=10, random_state=0) kmeans_labels_pca = kmeans_pca.fit_predict(df_pca) results["KMeans"]["pca"]["Silhouette Coefficient"] = silhouette_score(df_pca, kmeans_labels_pca) results["KMeans"]["pca"]["Calinski-Harabasz Index"] = calinski_harabasz_score(df_pca, kmeans_labels_pca) results["KMeans"]["pca"]["Davies-Bouldin Index"] = davies_bouldin_score(df_pca, kmeans_labels_pca) for metric, value in results["KMeans"]["pca"].items(): print(f"{metric}: {value:.2f}") Silhouette Coefficient: 0.45 Calinski-Harabasz Index: 5337.49 Davies-Bouldin Index: 0.81 5.2 DBSCAN DBSCAN (Density-Based Spatial Clustering of Applications with Noise) DBSCAN, yoğunluk tabanlı bir kümeleme algoritmasıdır. Veri noktalarının yoğun bölgelerini tanımlar ve bu bölgelerdeki noktaları aynı kümeye atar. Yoğun olmayan bölgelerdeki noktalar ise gürültü olarak sınıflandırılır. Çalışma Prensibi: - Her veri noktası etrafında belirli bir yarıçapa (eps) sahip bir çevre tanımlanır. Eğer bu çevre içinde min_samples sayısından fazla veri noktası bulunuyorsa, bu nokta yoğun bir bölgenin parçası olarak kabul edilir. - Yoğun bölgeler birleştirilerek geniş kümeler oluşturulur. - Yoğun bölgelerin dışında kalan ve belirli bir çevresi içinde yeterince komşusu olmayan noktalar gürültü olarak etiketlenir. Avantajları: - Kümelerin şekilleri hakkında varsayımda bulunmaz. Dolayısıyla, kümeler dairesel olmak zorunda değildir. - Otomatik olarak gürültüyü ayırt edebilir. - Kümelerin sayısını önceden belirtmek zorunda değilsiniz. Zorlukları: - Yoğunluk farklarına sahip kümeleri doğru bir şekilde ayrımakta zorlanabilir. - eps ve min_samples parametrelerinin doğru bir şekilde ayarlanması gerekmektedir. DBSCAN, özellikle gürültülü veri setleri ve karmaşık yapıya sahip kümeler için uygun bir seçenektir. 5.2.1 DBSCAN Normal Code X = df_scaled def epsilon(X): neighbors = NearestNeighbors(n_neighbors=2) nbrs = neighbors.fit(X) distances, indices = nbrs.kneighbors(X) distances = np.sort(distances, axis=0) distances_1 = distances[:, 1] plt.plot(distances_1, color='#5829A7') plt.xlabel('Total') plt.ylabel('Distance') for spine in plt.gca().spines.values(): spine.set_color('None') plt.grid(axis='y', alpha=0.5, color='#9B9A9C', linestyle='dotted') plt.grid(axis='x', alpha=0) plt.title('DBSCAN Epsilon Value for Scaled Data') plt.tight_layout() plt.show(); epsilon(X); Code dbscan = DBSCAN(eps=2.2, min_samples=5) labels = dbscan.fit_predict(df_scaled) plt.figure(figsize=(10, 8)) unique_labels = np.unique(labels) colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))] for k, col in zip(unique_labels, colors): if k == -1: col = [0.6, 0.6, 0.6, 1] class_member_mask = (labels == k) xy = df_scaled[class_member_mask] plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col), markeredgecolor='k', markersize=6) plt.title('DBSCAN Clustering') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.grid(True) plt.show() Code dbscan_normal = DBSCAN(eps=2.2, min_samples=5) labels_normal = dbscan_normal.fit_predict(df_scaled) results["DBSCAN"]["normal"]["Silhouette Coefficient"] = silhouette_score(df_scaled, labels_normal) if len(np.unique(labels_normal)) > 1 else 0 results["DBSCAN"]["normal"]["Calinski-Harabasz Index"] = calinski_harabasz_score(df_scaled, labels_normal) results["DBSCAN"]["normal"]["Davies-Bouldin Index"] = davies_bouldin_score(df_scaled, labels_normal) for metric, value in results["DBSCAN"]["normal"].items(): print(f"{metric}: {value:.2f}") Silhouette Coefficient: 0.52 Calinski-Harabasz Index: 939.76 Davies-Bouldin Index: 1.97 5.2.2 DBSCAN UMAP Code X = df_umap def epsilon(X): neighbors = NearestNeighbors(n_neighbors=2) nbrs = neighbors.fit(X) distances, indices = nbrs.kneighbors(X) distances = np.sort(distances, axis=0) distances_1 = distances[:, 1] plt.plot(distances_1, color='#5829A7') plt.xlabel('Total') plt.ylabel('Distance') for spine in plt.gca().spines.values(): spine.set_color('None') plt.grid(axis='y', alpha=0.5, color='#9B9A9C', linestyle='dotted') plt.grid(axis='x', alpha=0) plt.title('DBSCAN Epsilon Value for UMAP Data') plt.tight_layout() plt.show(); epsilon(X); Code dbscan = DBSCAN(eps=0.15, min_samples=2) labels = dbscan.fit_predict(df_umap.values) plt.figure(figsize=(10, 8)) unique_labels = np.unique(labels) colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))] for k, col in zip(unique_labels, colors): if k == -1: col = [0.6, 0.6, 0.6, 1] class_member_mask = (labels == k) xy = df_umap.values[class_member_mask] plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col), markeredgecolor='k', markersize=6) plt.title('DBSCAN Clustering') plt.xlabel('UMAP 1') plt.ylabel('UMAP 2') plt.grid(True) plt.show() Code dbscan_umap = DBSCAN(eps=2.23, min_samples=2) labels_umap = dbscan_umap.fit_predict(df_umap) results["DBSCAN"]["umap"]["Silhouette Coefficient"] = silhouette_score(df_umap, labels_umap) if len(np.unique(labels_umap)) > 1 else 0 results["DBSCAN"]["umap"]["Calinski-Harabasz Index"] = calinski_harabasz_score(df_umap, labels_umap) results["DBSCAN"]["umap"]["Davies-Bouldin Index"] = davies_bouldin_score(df_umap, labels_umap) for metric, value in results["DBSCAN"]["umap"].items(): print(f"{metric}: {value:.2f}") Silhouette Coefficient: 0.25 Calinski-Harabasz Index: 232.31 Davies-Bouldin Index: 0.63 5.2.3 DBSCAN PCA Code X = df_pca def epsilon(X): neighbors = NearestNeighbors(n_neighbors=2) nbrs = neighbors.fit(X) distances, indices = nbrs.kneighbors(X) distances = np.sort(distances, axis=0) distances_1 = distances[:, 1] plt.plot(distances_1, color='#5829A7') plt.xlabel('Total') plt.ylabel('Distance') for spine in plt.gca().spines.values(): spine.set_color('None') plt.grid(axis='y', alpha=0.5, color='#9B9A9C', linestyle='dotted') plt.grid(axis='x', alpha=0) plt.title('DBSCAN Epsilon Value for PCA Data') plt.tight_layout() plt.show(); epsilon(X); Code dbscan = DBSCAN(eps=1, min_samples=5) labels = dbscan.fit_predict(df_pca) plt.figure(figsize=(10, 8)) unique_labels = np.unique(labels) colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))] for k, col in zip(unique_labels, colors): if k == -1: col = [0.6, 0.6, 0.6, 1] class_member_mask = (labels == k) xy = df_pca[class_member_mask] plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col), markeredgecolor='k', markersize=6) plt.title('DBSCAN Clustering') plt.xlabel('PCA 1') plt.ylabel('PCA 2') plt.grid(True) plt.show() Code dbscan_pca = DBSCAN(eps=1, min_samples=5) labels_pca = dbscan_pca.fit_predict(df_pca) results["DBSCAN"]["pca"]["Silhouette Coefficient"] = silhouette_score(df_pca, labels_pca) if len(np.unique(labels_pca)) > 1 else 0 results["DBSCAN"]["pca"]["Calinski-Harabasz Index"] = calinski_harabasz_score(df_pca, labels_pca) results["DBSCAN"]["pca"]["Davies-Bouldin Index"] = davies_bouldin_score(df_pca, labels_pca) for metric, value in results["DBSCAN"]["pca"].items(): print(f"{metric}: {value:.2f}") Silhouette Coefficient: 0.80 Calinski-Harabasz Index: 1347.22 Davies-Bouldin Index: 0.78 5.3 OPTICS OPTICS (Ordering Points To Identify the Clustering Structure) OPTICS, yoğunluk tabanlı bir kümeleme algoritmasıdır ve DBSCAN’ın bir genelleştirmesi olarak düşünülebilir. Ancak, tek bir eps değeri yerine veri setindeki farklı yoğunluklardaki yapıları tanımlayabilmesiyle bilinir. Çalışma Prensibi: - Her veri noktası için ulaşılabilirlik mesafesi hesaplanır. Bu, bir noktanın belirli bir yoğunlukta diğer bir noktaya ne kadar yakın olduğunu belirler. - Bu mesafelere dayanarak bir ulaşılabilirlik grafiği oluşturulur. - Grafik üzerinde vadiler, yoğunluk tabanlı kümeleri gösterir. Avantajları: - Farklı yoğunluklardaki kümeleri tespit edebilir. - eps parametresinin sabit bir değerini seçmek zorunda kalmazsınız. - Otomatik olarak gürültüyü ayırt edebilir. Zorlukları: - Hesaplama maliyeti yüksek olabilir, özellikle büyük veri setleri için. - Sonuçların yorumlanması DBSCAN’a göre biraz daha zor olabilir. OPTICS, yoğunluğu değişen bölgelerin bulunduğu veri setleri için oldukça kullanışlıdır. Farklı yoğunluklardaki kümeler arasında geçişleri tespit etmede başarılıdır. 5.3.1 OPTICS Normal Code optics = OPTICS(min_samples=5, max_eps=2.2) labels = optics.fit_predict(df_scaled) plt.figure(figsize=(10, 8)) unique_labels = np.unique(labels) colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))] for k, col in zip(unique_labels, colors): if k == -1: col = [0.6, 0.6, 0.6, 1] class_member_mask = (labels == k) xy = df_scaled[class_member_mask] plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col), markeredgecolor='k', markersize=6) plt.title('OPTICS Clustering') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.grid(True) plt.show() Code optics_normal = OPTICS(min_samples=9) labels_normal = optics_normal.fit_predict(df_scaled) results["OPTICS"]["normal"]["Silhouette Coefficient"] = silhouette_score(df_scaled, labels_normal) if len(np.unique(labels_normal)) > 1 else 0 results["OPTICS"]["normal"]["Calinski-Harabasz Index"] = calinski_harabasz_score(df_scaled, labels_normal) results["OPTICS"]["normal"]["Davies-Bouldin Index"] = davies_bouldin_score(df_scaled, labels_normal) for metric, value in results["OPTICS"]["normal"].items(): print(f"{metric}: {value:.2f}") Silhouette Coefficient: -0.45 Calinski-Harabasz Index: 11.93 Davies-Bouldin Index: 1.33 5.3.2 OPTICS UMAP Code optics = OPTICS(min_samples=2, max_eps=0.15) labels = optics.fit_predict(df_umap.values) plt.figure(figsize=(10, 8)) unique_labels = np.unique(labels) colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))] for k, col in zip(unique_labels, colors): if k == -1: col = [0.6, 0.6, 0.6, 1] class_member_mask = (labels == k) xy = df_umap.values[class_member_mask] plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col), markeredgecolor='k', markersize=6) plt.title('OPTICS Clustering') plt.xlabel('UMAP 1') plt.ylabel('UMAP 2') plt.grid(True) plt.show() Code optics_umap = OPTICS(min_samples=2) labels_umap = optics_umap.fit_predict(df_umap) results["OPTICS"]["umap"]["Silhouette Coefficient"] = silhouette_score(df_umap, labels_umap) if len(np.unique(labels_umap)) > 1 else 0 results["OPTICS"]["umap"]["Calinski-Harabasz Index"] = calinski_harabasz_score(df_umap, labels_umap) results["OPTICS"]["umap"]["Davies-Bouldin Index"] = davies_bouldin_score(df_umap, labels_umap) for metric, value in results["OPTICS"]["umap"].items(): print(f"{metric}: {value:.2f}") Silhouette Coefficient: 0.24 Calinski-Harabasz Index: 10.24 Davies-Bouldin Index: 1.43 5.3.3 OPTICS PCA Code optics = OPTICS(min_samples=5, max_eps=1) labels = optics.fit_predict(df_pca) plt.figure(figsize=(10, 8)) unique_labels = np.unique(labels) colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))] for k, col in zip(unique_labels, colors): if k == -1: col = [0.6, 0.6, 0.6, 1] class_member_mask = (labels == k) xy = df_pca[class_member_mask] plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col), markeredgecolor='k', markersize=6) plt.title('OPTICS Clustering') plt.xlabel('PCA 1') plt.ylabel('PCA 2') plt.grid(True) Code optics_pca = OPTICS(min_samples=5) labels_pca = optics_pca.fit_predict(df_pca) results["OPTICS"]["pca"]["Silhouette Coefficient"] = silhouette_score(df_pca, labels_pca) if len(np.unique(labels_pca)) > 1 else 0 results["OPTICS"]["pca"]["Calinski-Harabasz Index"] = calinski_harabasz_score(df_pca, labels_pca) results["OPTICS"]["pca"]["Davies-Bouldin Index"] = davies_bouldin_score(df_pca, labels_pca) for metric, value in results["OPTICS"]["pca"].items(): print(f"{metric}: {value:.2f}") Silhouette Coefficient: -0.18 Calinski-Harabasz Index: 10.06 Davies-Bouldin Index: 1.68 6. Sonuçlar Code from IPython.display import display, Markdown def display_results(results): for method, data in results.items(): display(Markdown(f"### {method}")) for dataset, metrics in data.items(): display(Markdown(f"#### {dataset}")) for metric, value in metrics.items(): display(Markdown(f"- **{metric}**: {value:.2f}")) display_results(results) KMeans normal Silhouette Coefficient: 0.25 Calinski-Harabasz Index: 1604.40 Davies-Bouldin Index: 1.60 umap Silhouette Coefficient: 0.42 Calinski-Harabasz Index: 8208.00 Davies-Bouldin Index: 0.95 pca Silhouette Coefficient: 0.45 Calinski-Harabasz Index: 5337.49 Davies-Bouldin Index: 0.81 outlier_free Silhouette Coefficient: 0.32 Calinski-Harabasz Index: 4345.55 Davies-Bouldin Index: 1.42 DBSCAN normal Silhouette Coefficient: 0.52 Calinski-Harabasz Index: 939.76 Davies-Bouldin Index: 1.97 umap Silhouette Coefficient: 0.25 Calinski-Harabasz Index: 232.31 Davies-Bouldin Index: 0.63 pca Silhouette Coefficient: 0.80 Calinski-Harabasz Index: 1347.22 Davies-Bouldin Index: 0.78 OPTICS normal Silhouette Coefficient: -0.45 Calinski-Harabasz Index: 11.93 Davies-Bouldin Index: 1.33 umap Silhouette Coefficient: 0.24 Calinski-Harabasz Index: 10.24 Davies-Bouldin Index: 1.43 pca Silhouette Coefficient: -0.18 Calinski-Harabasz Index: 10.06 Davies-Bouldin Index: 1.68 Kümeleme Sonuçlarının Analizi KMeans Normal Silhouette Katsayısı (SC): 0.25 Bu ölçüt -1 ile 1 arasında değişir. Daha yüksek değerler, nesnenin kendi kümesine iyi uydurulduğunu ve komşu kümelerle zayıf bir şekilde eşleştiğini gösterir. 0.25 skoru, kümelerin bir miktar örtüştüğünü ve iyileştirme yapılabileceğini gösterir. Calinski-Harabasz İndeksi (CHI): 1604.40 Küme içi değişkenlik ile küme arası değişkenlik oranıdır. Daha yüksek değerler, kümelerin yoğun ve iyi ayrıldığını gösterir. Davies-Bouldin İndeksi (DBI): 1.60 Her kümenin en benzer kümeyle ortalama benzerlik oranıdır. 0’a yakın değerler daha iyidir. 1.60 skoru, ılımlı bir kümeleme yapısı olduğunu gösterir. UMAP SC: 0.41 UMAP uygulandıktan sonra normal verilere göre daha iyi tanımlanmış kümeleri gösteren bir iyileşme. CHI: 7902.77 UMAP’ın kümeleme yapısını iyileştirmeye yardımcı olduğunu gösteren önemli bir artış. DBI: 0.97 UMAP uygulandıktan sonra kümelerin daha iyi ayrıldığını gösteren bir azalma. PCA SC: 0.45 PCA uygulandıktan sonra UMAP ve normal verilere kıyasla daha iyi küme tanımı. CHI: 5337.49 UMAP’tan daha düşük ancak normalden daha yüksek; PCA’nın da iyi bir kümeleme yapısına yardımcı olduğunu gösteriyor. DBI: 0.81 Normal veri kullanımına kıyasla kümelerin daha iyi ayrıldığını gösteriyor. Outlier-free (Aykırı Değersiz) Bu kategorideki metrikler, aykırı değerlerin kaldırılmasının normal verilere göre kümeleme yapısını biraz daha iyi hale getirdiğini, ancak PCA veya UMAP gibi boyut indirgeme tekniklerini uygulamak kadar iyi olmadığını gösteriyor. DBSCAN DBSCAN, normal ve pca veri kümeleri için genellikle KMeans’den daha iyi SC puanları üretmiştir. Özellikle 0.80 SC ile pca veri kümesi çok iyi tanımlanmış kümeleri gösteriyor. DBI puanları da, özellikle pca veri kümesi için, KMeans’e göre daha iyi küme ayrımını yansıtmaktadır. Ancak, CHI puanı, normal veri kümesi için daha iyi olmasına rağmen, UMAP veri kümesi için önemli ölçüde düşmektedir. Bu, daha az yoğun kümeleri veya daha büyük küme örtüşmesini gösteriyor. OPTICS Normal: SC: -0.45 Negatif bir siluet puanı, kümelerin iyi tanımlanmadığını ve önemli ölçüde örtüştüğünü gösterir. Diğer metrikler de zayıf bir kümeleme yapısını yansıtmaktadır. UMAP & PCA: Bu veri kümeleri için metrikler de umut vaat etmemektedir. Negatif veya düşük siluet puanları ve çok düşük CHI puanları, zayıf küme tanımını ve yoğunluğunu gösterir. Özet UMAP veya PCA ile KMeans UMAP veya PCA ile KMeans en iyi sonucu veriyor gibi görünmektedir. PCA siluet katsayısında hafif bir üstünlük göstermekle birlikte, her iki yöntem de kümelerin iyi tanımlandığını gösteriyor. Bu, belirli bir uygulama için iki yaklaşımı da değerlendirmeye değer olabilir. DBSCAN DBSCAN ile PCA’nın birleşimi, oldukça yüksek bir siluet katsayısına sahip olup, bu da bu yaklaşımın da kümeleri oldukça iyi tanımladığını gösteriyor. Ancak, UMAP ile elde edilen sonuçlar DBSCAN için o kadar başarılı değil. OPTICS OPTICS’in performansı, kullanılan veri kümesine bağlı olarak diğer iki yönteme kıyasla genellikle daha düşüktür. Özellikle negatif siluet katsayıları, kümelerin oldukça zayıf tanımlandığını gösteriyor. Sonuç olarak, eğer birincil amacınız iyi tanımlanmış kümeler elde etmekse, PCA veya UMAP’ın KMeans ile birleştirilmesi tavsiye edilir. Öte yandan, daha karmaşık yapılarla başa çıkmak için DBSCAN’ı denemeye değer olabilir, özellikle PCA ile birleştirildiğinde. OPTICS’in genel performansı, bu özel veri kümesi için daha düşük olmasına rağmen, farklı veri kümeleri üzerinde farklı sonuçlar üretebilir, bu nedenle her zaman kullanmadan önce değerlendirme yapmak önemlidir. Code # Orijinal veri setinize etiketleri ekleyin. df['Cluster'] = kmeans_labels_pca # Her bir küme için sütun ortalamalarını alın. cluster_means = df.groupby('Cluster').mean() # Ortalama değerleri tablo olarak göster. cluster_means BALANCE BALANCE_FREQUENCY PURCHASES ONEOFF_PURCHASES INSTALLMENTS_PURCHASES CASH_ADVANCE PURCHASES_FREQUENCY ONEOFF_PURCHASES_FREQUENCY PURCHASES_INSTALLMENTS_FREQUENCY CASH_ADVANCE_FREQUENCY ... PAYMENTS_RANGE MINIMUM_PAYMENTS_RANGE BALANCE_FREQUENCY_RANGE PURCHASES_FREQUENCY_RANGE ONEOFF_PURCHASES_FREQUENCY_RANGE PURCHASES_INSTALLMENTS_FREQUENCY_RANGE CASH_ADVANCE_FREQUENCY_RANGE PRC_FULL_PAYMENT_RANGE PURCHASES_TRX_RANGE CASH_ADVANCE_TRX_RANGE Cluster 0 789.381289 0.835555 516.904913 264.930837 252.295136 316.614221 0.474579 0.140900 0.348978 0.067312 ... 1.869153 1.404809 8.548250 5.000981 1.566405 3.695944 0.802257 1.672718 2.052993 0.443409 1 3925.835034 0.956794 361.745825 241.267864 120.553232 3791.893111 0.214590 0.106232 0.128552 0.437004 ... 3.077906 2.484480 9.663421 2.309191 1.191722 1.390140 4.780280 0.364577 1.125380 2.623859 2 2284.681931 0.981539 4378.858533 2754.504803 1624.856664 498.773452 0.950954 0.650455 0.768528 0.067055 ... 3.704107 1.886840 9.885163 9.659681 6.824811 7.924560 0.768650 3.176865 6.145013 0.464376 3 rows × 33 columns Kümeleri tahminleme/anlamlandırma Küme 0 Bakiye (BALANCE): Bu grubun müşterileri ortalama seviyede bir bakiye taşıyor. Bu, ne çok yüksek ne de çok düşük bir harcama kapasitesine sahip oldukları anlamına gelir. Alışverişler (PURCHASES): Bu gruptaki müşteriler ortalama seviyede alışveriş yapmaktadırlar, ancak bu alışverişleri hem tek seferde hem de taksitlerle yapıyorlar. Nakit Avans (CASH_ADVANCE): Ortalama seviyede nakit avans kullanımı var. Satın Alma Sıklığı (PURCHASES_FREQUENCY): Bu müşteriler düzenli olarak alışveriş yaparlar, ancak oldukça sık değil. Kredi Limiti (CREDIT_LIMIT): Bu grubun kredi limiti diğer gruplara göre daha düşük olabilir. Ortalama kullanıcılar olarak değerlendirilebilir. Bu kullanıcılar, kredi kartlarını hem günlük alışverişlerde hem de büyük alışverişlerde kullanabilirler. Nakit avans kullanımının orta seviyede olması, bazen nakit ihtiyaçlarını kartlarından karşıladıklarını gösteriyor. Küme 1 Bakiye (BALANCE): Bu grubun müşterileri oldukça yüksek bir bakiye taşıyor, bu da yüksek harcama kapasitesine sahip oldukları anlamına gelir. Alışverişler (PURCHASES): Daha az alışveriş yaparlar, bu da bu grubun daha az aktif olduğu anlamına gelir. Nakit Avans (CASH_ADVANCE): Yüksek miktarda nakit avans kullanımı bu grupta belirgindir, bu da bu müşterilerin sıkça nakit ihtiyaçları olduğunu gösterir. Satın Alma Sıklığı (PURCHASES_FREQUENCY): Bu müşteriler daha az sıklıkla alışveriş yaparlar. Kredi Limiti (CREDIT_LIMIT): Bu grubun kredi limiti diğer gruplardan daha yüksektir. Bu grup, kredi kartını büyük alışverişler veya yüksek fiyatlı satın almalar için kullanan bireyleri içeriyor gibi gözüküyor. Yüksek bakiyeleri ve kredi limitleri, bu grubun maddi kapasitesinin ve harcama potansiyelinin yüksek olduğunu gösteriyor. Küme 2 Bakiye (BALANCE): Bu grubun bakiyesi yüksek, ancak Küme 1 kadar değil. Alışverişler (PURCHASES): Bu gruptaki müşteriler çok yüksek miktarda alışveriş yaparlar ve bu alışverişler hem tek seferde hem de taksitli olarak yapılır. Nakit Avans (CASH_ADVANCE): Nakit avans kullanımı ortalamanın biraz üstünde. Satın Alma Sıklığı (PURCHASES_FREQUENCY): Bu müşteri grubu sık sık alışveriş yapar. Kredi Limiti (CREDIT_LIMIT): Bu grubun kredi limiti, diğer iki gruba kıyasla ortalamadır. Bu grupta genç bireyler veya öğrencilerin yoğun olma ihtimali yüksek, bu grup, kartlarını günlük küçük harcamalar için kullanan bireyleri temsil ediyor olabilir. Bu yüzden sık alışveriş yapmalarına ve genellikle küçük tutarlar harcamalarına cevap olabilir. Ancak bu yorumların kesinliğini artırmak için ekstra demografik veya davranışsal bilgilere (örneğin yaş, meslek, gelir seviyesi gibi) ihtiyaç olabilir. Bu tür ek bilgiler, her bir kümeyi daha ayrıntılı ve doğru bir şekilde tanımlamamıza yardımcı olabilir. Maalesef üstünde çalıştığım veri setinde bunlar mevcut değil. Projenin devamında pydash kullanmak istediğim için yaş, cinsiyet ve şehir başlıklarını ekleyeceğim. (şehir önceden eklemiştim.) Bu eklemeler tamamen rastgele olup bu analize etki etmeyecek şekilde devam etmem için gereklidir. Bu analiz sürecini app ve dashboard haline getirmek için yaptığım dash uygulamasını buradan kontrol edebilirsiniz.