Spark Dataframe İçindeki Kategorik Nitelikleri Otomatik Olarak Seçmek
Merhaba. Spark dataframe ile çalışırken zaman zaman içindeki kategorik değişkenleri seçeriz. Özellikle makine öğrenmesi öncesinde veri hazırlığı aşamasında bunu mutlaka yapmalıyız. Çünkü kategorik nitelikler veri hazırlığı sürecinde stringIndexer, OneHotEncoder gibi daha farklı aşamalardan geçer. Bu yazımızda Spark dataframe içindeki nitelikleri kategorik ve nümerik olarak ayırt eden ve iki farklı liste içinde bunları toplayan spark kodlarını yazacağız.
Benim yaptığım çalışma esnasında kullandığım ortam bilgileri:
İşletim sistemi: Windows 10 64 bit Pro
IDE: Intellij IDEA Community Edition
Spark 2.3.1
Dil: Scala 2.11
Kütüphaneler:
import org.apache.spark.sql.types._ import org.apache.spark.sql.{Column, DataFrame, Dataset , SparkSession, functions => F} import org.apache.log4j.{Level, Logger}
Log seviyesini ERROR yapalım. Böylelikle bilgi logları arasında sonuçlarımızı kaybetmeyiz.
Logger.getLogger("org").setLevel(Level.ERROR)
SparkSession ve Context:
val spark = SparkSession.builder() .appName("Kategorik ve Nümerik Nitelikleri Ayırma").master("local[*]") .config("spark.driver.memory", "2g") .config("spark.executor.memory", "4g") .config("spark.sql.codegen.wholeStage", "false") .getOrCreate() val sc = spark.sparkContext import spark.implicits._
Dataframe oluşturma:
val hastalarDF = Seq( (8, "Ali",98.3,"KBB"), (64, "Mehmet",78.4,"GÖZ"), (27, "Cemal",69.9,"CERRAHİ"), (53, "Eyüp",78.4,"CİLDİYE"), (33, "Simge",69.9,"GÖĞÜS") ).toDF("yas", "isim","deger","birim")
Oluşturuduğumuz dataframe’e göz atma:
hastalarDF.show()
Sonuç:
+---+------+-----+-------+ |yas| isim|deger| birim| +---+------+-----+-------+ | 8| Ali| 98.3| KBB| | 64|Mehmet| 78.4| GÖZ| | 27| Cemal| 69.9|CERRAHİ| | 53| Eyüp| 78.4|CİLDİYE| | 33| Simge| 69.9| GÖĞÜS| +---+------+-----+-------+
Yukarıda iki tane kategorik (isim ve birim), iki tane de nümerik (yas ve deger) nitelik var. Bunları aslında elimizle de yazarız ancak nitelik sayısı çoğaldığında bunu elle yapmak kolay olmayabilir. Bu sebeple şimdi yazacağımız fonksiyon işimizi kolaylaştıracaktır.
Kategorik ile nümerik nitelikleri ayıran fonksiyon:
def identifyCategoricAndNumeric(df: DataFrame): (Array[String], Array[String]) = { var categoricCols = Array[String]() var numericCols = Array[String]() for (col <- df.columns){ if(df.schema(col).dataType == StringType){ categoricCols = categoricCols :+ col }else{ numericCols = numericCols :+ col } } (categoricCols, numericCols) }
Yukarıda yapılan işlem çok basit. Parametre olarak ilgili dataframe’i alıyoruz, sütunları içinde for döngüsü ile dolaşıyoruz. Her bir sütunun veri tipinin StringType olup olmadığını kontrol ediyoruz. Kontrolden geçenleri iki farklı liste içinde biriktiriyoruz. Sonuç olarak bu iki listeyi demet (categoricCols, numericCols) şeklinde döndürüyoruz.
Şimdi bu fonksiyonu dataframe üzerinde uygulayalım.
val (kategorik, numerik) = identifyCategoricAndNumeric(hastalarDF)
Yukarıda bir fonksiyondan dönen iki listeyi (array) iki değişkende tuttuk. Şimdi bunları yazdırıp bakalım fonksiyonumuz doğru çalışmış mı?
println("\nKategorik nitelikler:") kategorik.foreach(println(_)) println("\nNümerik nitelikler:") numerik.foreach(println(_))
Sonuç:
Kategorik nitelikler: isim birim Nümerik nitelikler: yas deger
Evet sonuç beklediğimiz gibi. Kategorik ve nümerik nitelik isimlerini iki farklı listede topladık. Peki bunun bize ne faydası var? Şu faydası var: makine öğrenmesinde veri hazırlığında nümerik ve kategorik niteliklere ayrı işlemler yapıyoruz. Bu aşamalarda ve modelin tekrar tekrar denenmesi aşamalarında kolaylık sağlıyor. Bazen yeni modeli farklı niteliklerle denemek isteyebiliyoruz. Örneğin çoklu lineer regresyonda geriye doğru eleme yönteminde.
Hoşçakalın…