Pandas
ile ilgili bu yazımızda veri çerçevesi (DataFrame
) isimli veri yapısını ele alacağız. Önceki yazımızda etiketli verilerden oluşan serileri görmüştük. Seriler tek boyutlu bir veri yapısıyken, veri çerçevelerini her sütunu bir seriden oluşan iki boyutlu bir matris olarak düşünebiliriz. Serilerde bahsettiğimiz birçok yöntemi veri çerçevelerinde de kullanmak mümkün. Ayrıca SQL tablolarında kullanılan tablo birleştirme (JOIN
) gibi işlemleri de Pandas
ile yapmak mümkün.
Veri Çerçeveleri
Veri çerçevelerini birden fazla serinin bir araya gelmiş hali olarak düşünebiliriz. Veri çerçeveleri de seriler gibi etiketli bir veri yapısıdır, ancak serilerden farkı iki boyutlu olmasıdır. Serilerdeki gibi etiket değerlerine indeks (index
) denir. Veri çerçeveleri index
alanının yanında columns
alanını da içeriyor. columns
sütunların isimlerini içeren bir sıralı nesne.
Veri çerçevesi oluşturmak için serileri kullanmak mümkün. Linkten erişebileceğiniz IMF’nin gayrisafi yurt içi hasıla verisi ile ilk denemeyi yapabiliriz. 2016 ve 2017 yılları için serileri anlattığımız yazıdaki veri kümelerini oluşturalım.
# Pandas paketini yükleyelim
import pandas as pd
import numpy as np
# GSYİH değeri en yüksek olan 10 ülkenin değerlerini kullanacağız.
gdp_data_2017 = [19362.13, 11937.56, 4884.49, 3651.87, 2574.81, 2565.05, 2439.01,
2080.92, 1921.14, 1640.39]
# İndeks değerlerini içeren listeyi oluşturalım.
gdp_index_2017 = ['ABD', 'Çin', 'Japonya', 'Almanya', 'Fransa',
'Birleşik Krallık', 'Hindistan', 'Brezilya', 'İtalya', 'Kanada']
# Seriyi oluşturalım. İndeks değerini vermediğimizde, Pandas 0'dan başlayarak veriyi indeksler.
gdp_2017 = pd.Series(gdp_data_2017, index = gdp_index_2017, name = 'GDP_2017')
# Aynı işlemi 2016 yılı için yapalım.
d = {'ABD':18624.45,
'Çin':11232.11,
'Japonya':4936.54,
'Almanya':3479.23,
'Fransa':2466.47,
'Birleşik Krallık':2629.19,
'Hindistan':2263.79,
'Brezilya':1798.62,
'İtalya':1850.74,
'Kanada':1529.76,
'Kore':1411.04}
gdp_2016 = pd.Series(d, name = 'GDP_2016')
print(gdp_2016)
print(gdp_2017)
Oluşturduğumuz serileri birleştirmek için iki yol kullanacağız. Bunlardan biri pandas
altındaki concat
fonksiyonu, diğeri ise serilerden oluşan bir sözlük tanımlamak olacak.
concat
fonksiyonunu kullanırken sütunların isimlerini ayrıca belirtmemize gerek yok. Bunun yerine serilerin name
alanı sütun isimleri olarak atanıyor. Bir seride olup diğerinde olmayan değerler (Kore gibi) NaN
değeriyle gösterilir.
df = pd.concat([gdp_2017, gdp_2016], axis = 1)
print(df)
Veri çerçevesindeki değerlerin serilerdeki yerinden bağımsız olarak indeks alanına göre eşleştirildiğini görüyoruz. Ondalık işaretini virgüle çevirmek için aşağıdaki yerel ayarları kullanabiliriz. Aşağıdaki kutucukta yerel ayarları değiştiriyoruz ve ondalıklı sayıları formatlıyoruz. Son satırdaki grouping = False
binlik işaretini kullanmayacağımızı belirtiyor. Yerel ayarların formatlama ile kullanılması konusunda Kaan’ın sıralı nesneler ve dizeler için yazdığı yazıları incelemenizi tavsiye ederim.
import locale
loc = locale.getlocale()
# Yerel ayarları Türkiye standartlarına çeviriyoruz.
locale.setlocale(locale.LC_ALL, "Turkish_Turkey.1254")
# Küsuratlı sayıları virgülden sonra iki basamak içerecek şekilde formatlıyoruz.
# Binlik işaretini kullanmayacağız.
pd.set_option('display.float_format', lambda x: locale.format('%.2f', x, grouping = False))
Aşağıdaki örnekte, veri çerçevesini serilerden oluşan bir sözlük yardımıyla oluşturuyoruz. Sözlüğün anahtarı sütunun ismine atanır.
d = {'2017' : gdp_2017,
'2016' : gdp_2016}
df = pd.DataFrame(d)
print(df)
Ondalık işaretinin değiştiğini görebilirsiniz.
Sözlük listeleri de veri çerçevesi oluşturmak için kullanılabilir. Aşağıdaki örnekteki listedeki her bir sözlük bir ülkenin GSYİH değerine denk geliyor. Hangi ülkeler olduğunu ise veri çerçevesini oluştururken söylüyoruz. Belirtmediğimiz değerler de NaN
değerini alıyor.
data = [{'GDP_2016':3651.87, 'GDP_2017': 3479.23}, {'GDP_2016' : 2466.47}]
df = pd.DataFrame(data, index = ['Almanya', 'Fransa'])
print(df)
Veri çerçevelerinin matrisler gibi iki boyutlu bir veri yapısı olduğundan bahsetmiştik. Matrisler de veri çerçeveleri oluşturmak için kullanılabilir.
# 2x2'lik rassal sayılardan oluşan bir matris oluşturalım.
data = np.random.rand(2,2)
# Index ve columns değerlerini veri çerçevesini oluştururken tanımlayabiliriz.
df = pd.DataFrame(data, index = ['1. satır', '2. satır'], columns=['1. sütun', '2. sütun'])
print(df)
Uygulamalarınızda kullanacağınız boyuttaki verileri bahsettiğimiz yöntemlerle veri çerçevesine atamanın zorluğunu farketmişsinizdir. Neyse ki pandas
çeşitli formatlardaki dosyaları okumanızı sağlayacak fonksiyonlar içeriyor.
Dosya okuma
pandas
paketi csv, Excel, JSON formatlarındaki dosyaların yanında Stata, SAS programlarıyla oluşturulmuş dosyaları da okuyarak içeriğini bir veri çerçevesine atamanızı sağlayan fonksiyonlar içeriyor. Benim sıklıkla kullandığım read_clipboard
fonksiyonu ise kopyaladığınız bir veriyi (örneğin bir Excel tablosunu) veri çerçevesine dönüştürüyor.
read_csv
fonksiyonunda sıklıkla kullanabileceğiniz parametreleri aşağıda bulabilirsiniz:
sep
: kolonları ayıran karakter ya da kurallı ifade (varsayılan değer','
),header
: sütun isimlerini içeren satırın numarası (varsayılan değer 0, eğer böyle bir satır yoksaNone
),index_col
: indeks değerlerini içeren sütunun numarası,names
: sütun isimlerini içeren sıralı nesne.
read_excel
fonksiyonunda ek olarak birden fazla sayfa içeren dokümanlarda hangi sayfaları okutacağınızı belirten sheet_name
argümanını da kullanabilirsiniz. sheet_name
değeri sayfanın adı, indeksi (ya da bunların bir listesi) olabilir. Ayrıca None
değerini kullanmanız halinde bütün sayfaları okutabilirsiniz. Örnek olarak linkten indirebileceğiniz bir çevrimiçi alışveriş veri kümesini kullandım.
# Dosya tek bir sayfa içerdiği için sheet_name'e ihtiyaç duymadık.
# Benim bilgisayarımda Excel dosyası ile Jupyter Notebook dosyası
# aynı klasörde olduğundan adres belirtmedim.
df = pd.read_excel('Online Retail.xlsx', decimal = ',')
print(df.head())
Kolonların isimlerini değiştirelim.
df.columns = ['FaturaNo', 'UrunNo', 'Tanim', 'Adet', 'FaturaTarihi', 'BirimFiyat', 'MusteriNo', 'Ulke']
print(df.head())
Temel Metotlar ve Erişim
Veri çerçevelerinde, serilerde gördüğümüz dim
, shape
, size
alanlarını ve erişim için kullandığımız loc
ve iloc
fonksiyonları kullanabiliriz. Serilerden farklı olarak veri çerçeveleri iki boyutlu, size
alanı da bu nedenle sütun ve satır sayısının çarpımına eşit.
print('Boyut: {}'.format(df.ndim))
print('Şekil: {}'.format(df.shape))
print('Uzunluk: {}'.format(df.size))
print('Sütunlar: {}'.format(df.columns))
Erişim için de yine serilerde gördüğümüz iloc
ve loc
metotlarını kullanabiliriz. Aynı zamanda Kaan’ın Sıralı Nesneler İşlemler yazısında bahsettiği dilimleme yöntemlerini kullanabiliriz.
print('Veri çerçevesinin 0,0 indeksindeki değer: {}'.format(df.iloc[0,0]))
print('Veri çerçevesinin ilk satırındaki değerler:\n{}'.format(df.iloc[0,:]))
Verideki eksik değerler özel ilgi göstermemizi gerektirecek durumlara işaret edebilir. Şimdi sütunlardaki eksik değerlerin sayısına bakalım. isnull
veri çerçevesinin boyutunda 0 ve 1 (True
/False
) değerlerinden oluşan bir veri çerçevesi döndürüyor. Bu veri çerçevesi NaN
olan hücreler için True
, diğer hücreler için False
değerine sahip. Sütunlar üzerinden toplarsak eksik değer içeren hücre sayısını bulabiliriz.
print('Eksik hücre sayısı')
print(df.isnull().sum())
Müşteri numarası olmayan 135080 satır var. Bu satırları veri setinden çıkaralım.
df = df[~df['MusteriNo'].isnull()]
print('Şekil: {}'.format(df.shape))
print('Eksik hücre sayısı')
print(df.isnull().sum())
Alternatif olarak eksik değerleri istediğiniz başka bir değerle değiştirmeniz de mümkün. Bu amaçla fillna
fonksiyonunu kullanabilirsiniz. Örnek olarak eksik değerleri 0 değeriyle doldurmak için df.fillna(0, inplace = True)
yazmanız yeterli. Buradaki inplace
argümanı değişikliğin veri çerçevesi üzerinde yapılmasını sağlar. Bunu kullanmak istemezseniz bir atama yapmanız gerekecek (df = df.fillna(0)
). İki seçeneği de kullanmamanız haline orijinal veri çerçevesi değişmeyecektir.
Müşteri numaraları tamsayı olması gerekirken ondalıklı olarak okunduğu için tamsayıya çevirelim.
# Aşağıdaki satırda sütunlara ulaşmanın iki farklı yolunu görüyoruz.
# Veri_çerçevesi['sütun_adı'] ve Veri_çerçevesi.Sütun_adı
df['MusteriNo'] = df.MusteriNo.astype('int')
print(df.head())
Veri İşleme
Veri çerçevesinde ürünler için birim fiyat ve satın alınan adet değerleri var. Müşterilerin o ürün için toplam harcamasını içeren bir sütun ekleyelim. Yeni sütunun adı Miktar
olsun.
df['Miktar'] = df['BirimFiyat'] * df['Adet']
print(df.head())
FaturaNo
ve o faturaya ait toplam miktarı içeren yeni bir veri çerçevesi oluşturalım. groupby
fonksiyonuyla her alışverişin toplam miktarını bulabiliriz. Groupby
fonksiyonunun kullanımını Veri Defteri’nin ilk yazılarından birinde anlatmıştık.
df_fis = df.groupby(['FaturaNo']).agg({'Miktar' : 'sum'}).reset_index()
df_fis.columns = ['FaturaNo', 'ToplamMiktar']
print(df_fis.head())
İlk veri çerçevesine ToplamMiktar
sütununu eklemek için pandas
paketinin sunduğu birleştirme işlemlerinden yararlanabiliriz. Bu amaçla merge
fonksiyonunu kullanacağız.
merge
işlemi için iki veri çerçevesinin hangi sütunlarının nasıl birleştirileceğini belirtmek gerekiyor. merge
fonksiyonu SQL tablolarında kullanılan birleştirme (JOIN
) işlemlerini destekliyor. İki veri çerçevesini birleştirmek için FaturaNo
anahtarını kullanalım (on = 'FaturaNo'
). Farklı isimlere sahip sütunlar üzerinden birleştirme yapmak için right_on = ...
ve left_on = ...
şeklinde veri çerçevelerindeki sütun isimlerini fonksiyona ekleyebilirsiniz.
how
argümanı için kullanabileceğiniz değerler:
- “
inner
“: Sadece iki tabloda da bulunan anahtar değerlerini birleştirir. Bir tabloda olmayan değerler silinir. - “
right
“: İlk tabloda bulunan değerler korunur ve ikinci tabloda eşleşen değerler tabloya eklenir. İkinci tabloda bulunmayan değerlerNaN
ile belirtilir. - “
left
“: İkinci tabloda bulunan değerler korunur ve ilk tabloda eşleşen değerler tabloya eklenir. İlk tabloda bulunmayan değerlerNaN
ile belirtilir. - “
outer
“: İki tablodan en az birinde bulunan değerler korunur. Bir tabloda olmayan eksik değerlerNaN
ile belirtilir.
df_yeni = pd.merge(df,df_fis, how= 'inner', on = 'FaturaNo')
print(df_yeni.head())
print('Şekil: {}'.format(df_yeni.shape))
print(df_yeni[df_yeni['FaturaNo'] == 536365])
Tekrar eden verileri tekilleştirmek için drop_duplicates
fonksiyonunu kullanabiliriz. Aşağıda müşteri numaralarını tekilleştirerek kaç müşteri olduğunu buluyoruz. Ben sütunları kopyalamayı tercih ettim. Bunu yapmamanız durumunda Python referans modelinden kaynaklı bir uyarı mesajı alacaksınız. Bu konu hakkında Kaan’ın yazısını okumanızı tavsiye ederim.
# Sadece ürün bilgilerini içeren sütunları alıyoruz.
# Burada copy işlemini kullanmazsak bir uyarı mesajı alıyoruz.
df_musteri = df[['MusteriNo']].copy()
df_musteri.drop_duplicates(inplace = True)
print(df_musteri.head())
print('Şekil: {}'.format(df_musteri.shape))
print('Müşteri sayısı: {}'.format(df_musteri.shape[0]))
Veri çerçeveleri scikit-learn
, statsmodel
gibi bir çok paket tarafından destekleniyor. Tensorflow
ve lightgbm
gibi popüler paketlerle de veri çerçevelerini kullanabilirsiniz. Yapay öğrenmede sıklıkla kullanılan bu paketlerden scikit-learn paketiyle ilgili bir giriş yazısı yazmıştık. İleride, diğer paketlerle ilgili yazılar yazmayı planlıyoruz.
Bu yazının Jupyter Notebook dosyasına Github dizinimizden ulaşabilirsiniz.