Spark MLlib Kullanarak Kümeleme Analizi

Makine öğrenmesi (machine learning) algoritmalarını kabaca ikiye ayırmak mümkündür: denetimli (supervised) ve denetimsiz (unsupervised). Her iki yöntemin de kullanım amaç ve yerleri farklı farklıdır.  Bu yazımızda denetimsiz yöntemin en yaygın algoritması K-Ortalamaları (K-Means), iris veri setini ve Spark MLlib kütüphanesini kullanarak örnek çalışma yapacağız. Burada amacım teorik olarak K-Ortalamalar yönteminin nasıl çalıştığını açıklamaktan ziyade örnek üzerinden pratik yapmak ve okuyucunun datascience yeteneklerini pekiştirmektir. Spark’ın 1.6 sürümü ve RDD tabanlı MLlib kütüphanesi, dil olarak PySpark kullanılacaktır. Spark2 ile beraber dataframe bazlı Spark ML kütüphanesini oluşturuldu.  Spark2 kullananların bu kütüpheneyi kullanmasını tavsiye ederim.
Öncelikle iris veri setini HDFS’e alalım. Şuan iris veri seti metin formatında (.txt uzantılı) burada bulunuyor (UCI Machine Learning Repository‘de de bulunabilir).

Komut satırımızı açıyoruz. bir dizin seçiyoruz. Ben /home/cloudera seçtim. wget "http://www.datascience.istanbul/data/iris.txt" komutuyla mevcut dizine veri setini indiriyoruz. Iris veri setini hatırlayalım. Toplam 150 kayıt ve 5 nitelikten oluşuyor. İlk dört nitelik nümerik ve yaprak uzunluk ve genişlikleri ile ilgili değerlere sahip. Beşinci değişken ise kategorik ve çiçeğin hangi sınıfta yer aldığına dair değerlere sahip. K-Ortalamalar algoritması numerik nitelikler ile çalıştığı ve beşinci nitelik hedef nitelik olduğu için biz beşinci niteliği kümeleme için kullanmayacağız.

Şuan namenode sunucuda local diskte bulunan veri setini HDFS’e aktaralım. Bunun için şu komutları kullanıyorum: hdfs dfs -put /home/cloudera/iris.txt /user/cloudera

Yukarıda gördüğümüz üzere iris veri seti artık HDFS’te. HDFS dizini olarak /user/cloudera/iris.txt Veri setini HDFS’e indirmeyi başardıktan sonra şimdi Jupyter’i açıp kümeleme çalışmaya başlayabiliriz. Gerekli kütüphaneleri indirelim.

from pyspark.mllib.clustering import KMeans, KMeansModel
from numpy import array
from math import sqrt

Veriyi alıp parse edelim ve Spark veri yapısında çalışmaya başlayalım.

data = sc.textFile("/user/cloudera/iris.txt")
parsedData = data.map(lambda line: array([x for x in line.split(',')]))

Bakalım veriyi Spark RDD olarak almış mıyız?

parsedData.take(5)
[array([u'5.1', u'3.5', u'1.4', u'0.2', u'Iris-setosa'], 
       dtype='<U11'), array([u'4.9', u'3.0', u'1.4', u'0.2', u'Iris-setosa'], 
       dtype='<U11'), array([u'4.7', u'3.2', u'1.3', u'0.2', u'Iris-setosa'], 
       dtype='<U11'), array([u'4.6', u'3.1', u'1.5', u'0.2', u'Iris-setosa'], 
       dtype='<U11'), array([u'5.0', u'3.6', u'1.4', u'0.2', u'Iris-setosa'], 
       dtype='<U11')]

Evet almışız ancak beşinci niteliğimiz olan çiçek sınıfı (Iris-setosa yazıp duran yerler :)) hala duruyor. Onu kaldırıyoruz çünkü denetimsiz öğrenmede hedef değişken ile işimiz yok. İlk dört niteliği float’a çevirip yeni bir RDD’ye atıyoruz.

iris_ilk_dort_nitelik = parsedData.map(lambda x: array([float(x[0]),float(x[1]),float(x[2]),float(x[3])]))
[array([ 5.1,  3.5,  1.4,  0.2]),
 array([ 4.9,  3. ,  1.4,  0.2]),
 array([ 4.7,  3.2,  1.3,  0.2]),
 array([ 4.6,  3.1,  1.5,  0.2]),
 array([ 5. ,  3.6,  1.4,  0.2])]

Şimdi hata fonksiyonumuzu yazalım. Yani küme merkezine olan uzaklığı hesaplayacak fonksiyon.

def error(point):
 center = clusters.centers[clusters.predict(point)]
 return sqrt(sum([x**2 for x in (point - center)]))

Şimdi her bir k değeri (ayırmak istediğimiz küme sayısı) için maliyetimize bir bakalım.

for k in range (1,6):
 clusters = KMeans.train(iris_ilk_dort_nitelik, k, maxIterations=10, initializationMode="random")
 WSSSE = iris_ilk_dort_nitelik.map(lambda point: error(point)).reduce(lambda x, y: x + y)
 
 print("With "+ str(k)+ " clusters: WSSSE: "+ str(WSSSE))
With 1 clusters: WSSSE: 291.455123856
With 2 clusters: WSSSE: 128.404195237
With 3 clusters: WSSSE: 97.3259242343
With 4 clusters: WSSSE: 83.7861984508
With 5 clusters: WSSSE: 80.4000863093

Bildiğimiz gibi iris veri seti üç doğal kümeden oluşuyor. Bununla ilgili yazımı inceleyebilirsiniz. Yukarıdaki listeye baktığımızda küme sayısı 2’den 3’e çıkınca en küçük kareler toplamı çok keskin bir düşüş yaşıyor. Bu da bize ideal k sayısı hakkında güzel bir işaret veriyor. Kısmet olursa önümüzdeki günlerde k sayısının nasıl seçileceği ve kategorik değişkenlerle nasıl kümeleme analizi yapılacağına dair yazılar yazmayı düşünüyorum. Şayet modelimizi daha sonra da kullanmayı düşünüyorsak modeli kaydedebiliriz.

clusters.save(sc, "K-OrtalamamarModeli-1")

Sonra modeli tekrar çağırmak istersek:

K_OrtalamamarModeli_1 = KMeansModel.load(sc, "K-OrtalamamarModeli-1")

Bu yazıda da bu kadar. Veriyle kalınız…

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir