Python ile Tidy Data

Veri bilimci olarak, veri setlerini standartlaştırılmış bir yapı halinde kullanmaya alışmamız lazım. Veri temizleme, veri bilimideki en sık yapılan iştir. İstediğiniz veri ile uğraşın yada istediğiniz analizi yapın, eninde sonunda veriyi temizlediğiniz bir noktaya varıcaksınız. Verinizi standart bir biçimde düzenlemek işlerinizi daha da kolaylaştıracaktır.

Düzenli Veri (Tidy Data) Nedir?

“Tidy Data” kavramını 2014 yılında Hadley Wickham yazdığı makalesinde tanıtmıştır. Tidy Data kavramını 3 maddede açıklıyoruz:

  • Her sütun bir değişkeni temsil eder.
  • Her satır bir gözlemi temsil eder.
  • Her bir gözlem birimi bir tablo oluşturur.

Dağınık veriye örnek vericek olursak:

Düzenli veriye örnek vericek olursak:

Dağınık Veri Setini Düzenlemek

Artık veri setini düzenlemeye başlayabiliriz. Burdaki amacımız veriyi analiz etmek değil, veriyi analiz etmek için standart bir hale getirmektir. Bu yazıda uğraşacağımız 5 tane dağınık veri seti tipi vardır:

  • Sütun başlıkları değişken ismi değildir, birer değerdir.
  • Birden çok değişken bir sütunda saklanmıştır.
  • Değişkenler hem sütun hem satırda depolanmıştır.
  • Birden çok gözlem birimi türü aynı tabloda saklanmıştır.
  • Tek bir gözlem birimi birden fazla tabloda saklanmıştır.

Sütun başlıkları değişken ismi değildir, birer değerdir

Bu problemde ilk olarak Pew Research Center veri setini kullanacağız. Bu veri seti gelir ile din arasındaki ilişkiyi inceler. Veri setinin problemi ise sütun başlıkları olası gelir değerlerinden oluşmaktadır.

Öncelikle kullancağımız kütüphaneleri çalışma ortamımıza ekliyoruz.

import pandas as pd
import datetime
from os import listdir
from os.path import isfile, join
import glob
import re

Artık veri setimizi yükleyebiliriz.

df = pd.read_csv("pew-raw.csv")
df.head()

Bu verimizin düzenli halinde gelir değerleri sütun başlıkları olmak yerine income sütunu altında birer değer olmalıdır.

dformatted_df = pd.melt(df,
                       ["religion"],
                       var_name="income",
                       value_name="freq")
formatted_df = formatted_df.sort_values(by=["religion"])
formatted_df.head(10)

Veri setimizin düzenli halinin çıktısı aşağıdaki gibidir

Bu problemde ikinci olarak Billboard Top 100 veri setini kullancağız. Bu veri seti bize Billboard Top 100 girdikten sonraki 75 hafta boyunca şarkıların haftalık sıralamasını veriyor. Veri setinin problemi ise sütun başlıkları olası hafta numaralarından oluşmaktadır. Ayrıca eğer bir şarkı 75 haftadan daha az sürede Billboard Top 100’e girmişse, geri kalan haftalar eksik değerler ile dolmuştur.
Verimizi yükleyelim

df = pd.read_csv("billboard.csv", encoding="mac_latin2")
df.head(10)

Bu veri setinin düzenli halinde hafta numaraları birer sütun başlığı olmak yerine tek bir sütun altında değer olarak toplanmalıdır. Bunu yapmak için, bütün hafta sütunlarını pandas kütüphanesi içindeki melt fonksiyonunu kullanarak date isimli bir sütuna toplamalıyız. Her bir kayıt için hafta başına bir satır oluşturacağız.

Öncelikle birleştirmek istemediğimiz sütunları bir liste içine kaydedelim.

id_vars = ["year",
           "artist.inverted",
           "track",
           "time",
           "genre",
           "date.entered",
           "date.peaked"]

Şimdi ise ‘melt’ fonksiyonunu kullanarak birleştirme işlemini yapabiliriz.

df = pd.melt(frame=df,id_vars=id_vars, var_name="week", value_name="rank")

melt fonksiyonundaki var_name argümanı ile birleştirdiğimiz sütunları aktaracağımız yeni sütunun adını, value_name argümanı ile ise bu yeni sütunun değerlerini saklayan sütunun adını atamamıza yarıyor.

Yukarıda veri setinin çıktısında gördüğümüz gibi hafta sütunlarının adı sadece haftanın numarasında oluşmuyor. Örneğin 1. haftayı ifade eden sütunun adı x1st.week tir. Bizim her bir hafta sütununun içinden numaraları yakalayıp kullanmamız lazım. Ayrıca rank sütunumuzun değerleri tam sayıya çevirmemiz lazım. Bu işlemleri yapmak için;

df["week"] = df['week'].str.extract('(\d+)', expand=False).astype(int)
df["rank"] = df["rank"].astype(int)

kodlarını yazmamız lazım. str.extract metodu ile karakter ifadenin içindeki istediğimiz şablonu çıkartabiliriz. astype metodu ile sütun içindeki değerleri istediğimiz tipe çevirebiliyoruz.
Bu işlemden sonra eksik değer içeren gözlemleri df = df.dropna() komutu ile siliyoruz.

Şimdi ise date sütununu oluşturalım.

df['date'] = pd.to_datetime(df['date.entered']) + pd.to_timedelta(df['week'], unit='w') - pd.DateOffset(weeks=1)

pd.to_datetime fonksiyonu ile karakter olan date.entered sütununu tarih formatına çeviriyoruz. pd.to_timedelta fonksiyonu ile week sütunundaki değerlerinin gün bazındaki karşılığına çeviriyoruz. Örnek vermek gerekirse 13 haftayı 91 güne çeviriyoruz. Bu fonksiyonun içindeki unit argümanı ile sadece gün değil, diğer zaman birimlerini de yazarak çevirme işlemi yapabiliriz. pd.DateOffset fonksiyonu ile de yukarıdaki tarih toplama işleminde 1 haftalık bir süre çıkartıyoruz.

Artık date sütunumuzu da oluşturduğumuza göre tablomuzun son haline bakabiliriz.

df = df[["year", 
         "artist.inverted",
         "track",
         "time",
         "genre",
         "week",
         "rank",
         "date"]]

df = df.sort_values(ascending=True, by=["year","artist.inverted","track","week","rank"])

Görüldüğü gibi veri setinin daha düzenlenmiş hali yukarıdaki gibidir. Ancak yinede Hadley Wickham tanımlarına tam olarak uymamaktadır. Aynı şarkının çok fazla tekrarlanmış olduğunu görüyoruz. Bir sonraki problemimizde bu sorunlar üzerine değineceğiz.

Birden çok gözlem birimi türü aynı tabloda saklanmıştır

En son Billboard tablosunda bahsettiğimiz problem, bir tablo içinde birden çok gözlem birimi bulunmaktadır.

Öncelikle songs adında her bir şarkının detayının bulunduğu bir tablo oluşturacağız.

songs_cols = ["year", "artist.inverted", "track", "time", "genre"]
songs = billboard[songs_cols].drop_duplicates()
songs = songs.reset_index(drop=True)
songs["song_id"] = songs.index
songs.head(10)

Yukarıdaki kodda ilk satırda, oluşturacağımız tablonun sütunlarını belirledik. 2. satırda ile billboard tablomuzdaki her bir şarkının tek satır olacak şekilde diğer kopyalarını siliyoruz. 3. satırda ise oluşturduğumuz songs tablosunun indeks değerlerini sıfırlıyoruz. Burda kullandığımız drop=True değeri ile eski indeks değerlerini siliyoruz. Ve son olarak tablomuza songs_id sütunu atayarak bu sütunu da indeks sütunu yapıyoruz.

Şimdi ise sadece song_id, date ve rank değerlerini içeren ranks adında bir tablo oluşturacağız.

ranks = pd.merge(billboard, songs, on=["year","artist.inverted", "track", "time", "genre"])
ranks = ranks[["song_id", "date","rank"]]
ranks.head(10)

Birden çok değişken bir sütunda saklanmıştır

Bu problemde Tubercolosis Records from World Health Organization veri seti ile çalışacağız. Bu veri setinde onaylanmış tüberküloz vakalarının ülke, yıl, yaş ve cinsiyet bazında verisi bulunmaktadır. Burdaki problemimiz ise bazı sütunlar birden çok değişken içeriyor. Ayrıca çok fazla sıfır ve eksik değer vardır. Bu problem veri toplama sürecinden kaynaklanmaktadır ve bu veri seti için bu problemin çözülmesi önem taşımaktadır.

Önce verimize bakalım

df = pd.read_csv("tb-raw.csv")
df


Bu veriyi düzenli hale getirmek için sütun isimlerindeki farklı isimleri silip, bunları tek bir sütuna indirmemiz gerekiyor. İlk önce bu sütunları melt fonksiyonu ile sex_and_age adlı sütun altına alıp ardından bu sütunu sex, age_lower ve age_upper olarak 3 sütuna bölmemiz gerekiyor. Bu adımlardan sonra düzenli verimizi tam olarak oluşturabiliriz.

df = pd.melt(df, id_vars=["country","year"], value_name="cases", var_name="sex_and_age")

tmp_df = df["sex_and_age"].str.extract("(\D)(\d+)(\d{2})")    

tmp_df.columns = ["sex", "age_lower", "age_upper"]

tmp_df["age"] = tmp_df["age_lower"] + "-" + tmp_df["age_upper"]

df = pd.concat([df, tmp_df], axis=1)

df = df.drop(['sex_and_age',"age_lower","age_upper"], axis=1)
df = df.dropna()
df = df.sort(ascending=True,columns=["country", "year", "sex", "age"])
df.head(10)

Bu işlemlerin sonucunda tablomuz;

Değişkenler hem sütun hem satırda depolanmıştır

Bu problemde Global Historical Climatology Network veri seti ile çalışacağız. Bu veri setinde 2010 yılında 5 aylık süre zarfında Meksika’daki hava istasyonunda (MX17004) kaydedilen günlük hava kayıtları bulunmaktadır. Variables are stored in both rows (tmin, tmax) and columns (days). Bu verideki problem ise değişkenler hem satırda (tmin, tmax) hemde sütunda (days) saklanmıştır.

Öncelikle veriyi inceleyelim.

df = pd.read_csv("weather-raw.csv")
df


Bu veriyi düzenli hale getirmek için yanlış yerleştirilmiş 3 değişkeni (tmin, tmax, days) alıp 3 ayrı değişken (tmin, tmax, date) olarak düzenlemeliyiz.

df["day"] = df["day_raw"].str.extract("d(\d+)", expand=False)  
df["id"] = "MX17004"

df[["year","month","day"]] = df[["year","month","day"]].apply(lambda x: pd.to_numeric(x, errors='ignore'))

def create_date_from_year_month_day(row):
    return datetime.datetime(year=row["year"], month=int(row["month"]), day=row["day"])

df["date"] = df.apply(lambda row: create_date_from_year_month_day(row), axis=1)
df = df.drop(['year',"month","day", "day_raw"], axis=1)
df = df.dropna()

df = df.pivot_table(index=["id","date"], columns="element", values="value")
df.reset_index(drop=False, inplace=True)

Yukarıdaki kodda ilk olarak günleri sayı olarak gün sütunlarından çıkartıyoruz ve bu değerleri day adında yeni bir sütuna atıyoruz. Daha sonra year, month ve day sütunlarını sayısal değerlere çeviriyoruz. Bu işlemden sonra year, month ve day değerlerini kullanarak date sütunu oluşturuyoruz. Son olarak element sütununun içindeki tmin ve tmax değerlerini sütun haline getiriyoruz.

Tek bir gözlem birimi birden fazla tabloda saklanmıştır

Bu problemde veri setimiz ise 2014/2015 yılları arasında Illinois eyaletinde doğan çocukların isimlerini veriyor. Burdaki problem ise veri, birden fazla tabloya bölünmüştür. Ayrıca Year değişkeni belge isminin içindedir.

Öncelikle yıl değerini belge isminden çıkarmak için bir fonksiyon yazıyoruz.

def extract_year(string):
    match = re.match("(\d{4})", string) 
    if match != None: return match.group(1)

Elimizde 2 tane tablo var; bir tanesi 2014 yılında doğan bebekler, ikincisi ise 2015 yılında doğan bebekler. İki tablonunda isim olarak tek farkları yıl değerleridir. Doğal olarak iki tablonun ismi de 201*-baby-names-illinois.csv şeklinde eşleşiyor. Bu eşleşmeyi kullanarak iki tabloyu da

allFiles = glob.glob("201*-baby-names-illinois.csv")

kodu ile allFiles değişkenine atadık. glob.glob fonksiyonu ile istediğiniz şablondaki karakterleri aratabilirsiniz.

Bu işlemden sonra boş bir DataFrame oluşturup bunun içine iki tablomuzuda ekleyip, tabloların sütun isimlerini küçük harfe çevirdikten sonra year sütununa tabloların yıl değerlerini ekliyoruz.

frame = pd.DataFrame()
df_list= []
df = pd.read_csv(file_,index_col=None, header=0)
df.columns = map(str.lower, df.columns)
df["year"] = extract_year(file_)
df_list.append(df)

df = pd.concat(df_list)


Ve böylece Python ile Tidy Data yazımızında sonuna geldik. Düzenli veri hakkında daha fazla bilgi almak istiyorsanız Hadley Wickham’ın makalesini okuyabilirsiniz. Bu makalenin linkini kaynakçada bulabilirsiniz.

Kaynakça:
http://www.jeannicholashould.com/tidy-data-in-python.html
https://www.jstatsoft.org/article/view/v059i10

Yazar Hakkında
Toplam 10 yazı
Alperen Balık
Alperen Balık
Yıldız Teknik Üniversitesi İstatistik Bölümü Mezunu. Veri Bilimcisi. İlgilendiği alanlar; Makine Öğrenmesi, Dashboard Tasarlama, Yazılım Geliştirme
Yorumlar (Yorum yapılmamış)

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

×

Bir Şeyler Ara