11. Pandas#

Önceki bölümde gördüğümüz Numpy paketi, veri saklama açısından oldukça hızlı ve etkin bir paket olmakla birlikte farklı türde verilerin bir arada kullanılması, verilerden seçim yapma gibi konularda yetersiz kalabilmektedir. Pandas paketi hem yüksek performanslı hem de esnek bir veri analizi ihtiyacından doğmuş ve Wes McKinney tarafından geliştirilmiştir. Pandas da esas olarak iki temel veri nesnesi bulunmaktadır: seriler (series) ve veri tabloları (dataframes).

11.1. Pandas Serileri#

Pandas serilerini sıra numalaraları olan (endekslenmiş) bir boyutlu diziler olarak düşünebiliriz. Pandas serisi aşağıdaki gibi tanımlanır. Nasıl ki Numpy paketini aktarırken geleneksel olarak np kısaltması kullanılıyorsa pandas paketi için de genel olarak pd kısaltması kullanılıyor.

import pandas as pd

pandas_seri = pd.Series( [5, 7, 3, 10, 8, 6] )
pandas_seri
0     5
1     7
2     3
3    10
4     8
5     6
dtype: int64

Varsayılan olaran Pandas serilerinin endeksi 0’dan başlayan ardışık tamsayılardır. Ancak dilersek farklı endeks isimleri de kullanabiliriz.

pandas_seri = pd.Series([5, 7, 3, 10, 8, 6], 
                        index = ['a', 'b', 'c', 'd', 'e', 'f'])
pandas_seri
a     5
b     7
c     3
d    10
e     8
f     6
dtype: int64

Bu yönüyle serileri bir çeşit sözlük (dictionary) veri yapısı gibi de düşünebiliriz. Ancak sözlüklerde arka arkaya gelen verileri seçmek mümkün değilken serilerde bu mümkündür.

11.2. Pandas Data Frame#

Veri analizinde kullanılan verilerin formatı çok farklı olabilmektedir. Buna karşın günlük çalışmalarımızda kullandığımız veriler çoğu zaman satır ve sütunlardan oluşan tablolardan oluşmaktadır. Bu tür verileri iki boyutlu veriler olarak da isimlendirebiliriz. Bu nedenledir ki basit veri işlemlerinde en çok kullanılan program MS Excel veya benzeri programlardır. Bu tür programlar ile satır ve sütunlarda gösterilebilecek verileri rahatlıkla saklamak ve bunlar üzerinde çeşitli analizler ve hesaplamalar yapmak mümkündür. Bu tür programların kullanım kolaylığı da yaygın olarak kullanılmalarında bir başka etkendir. Örneğin, R programlama dilinin yaygınlaşmasının en önemli sebeplerinden birisi de farklı veri tipindeki sütunlardan oluşan verilerle analiz, modelleme gibi işlemleri kolaylaştırmasıdır.

Diğer yandan kullanılan veri kümelerinin büyüklüğü arttıkça bu tür programlarda veri işleme ve analiz çok zor ve yavaş bir hale gelmektedir. Bilgisayar donanım teknolojinin önceki yıllara nazaran çok daha gelişmiş olduğu günümüzde dahi birçok bilgisayar birkaç yüz bin satırlık bir dosya bile hele bir de formüller içeriyorsa bilgisayarı zorlayabilmekte ve çalışmaları oldukça yavaşlatabilmektedir. Aşağıda görülen veri seti yapay öğrenme konusunda çok sık kullanılan iris veri kümesinin bir bölümünü göstermektedir. Bu veri kümesinde 150 iris çiçeğine ait (tabloda bir kısmı gösterilmiştir) çanak (sepal) ve taç (petal) yapraklarının en ve boy ölçümleri yapılmış ve üç farklı tür için bu ölçümler kaydedilmiştir.

iris

Tablo şeklindeki bir başka deyişle iki boyutlu veri kümelerinde her satır bir gözlemi ya da bir ölçümü belirtmektedir. Her sütun ise bu gözlemlere ilişkin farklı özellikleri yani değişkenleri belirtmektedir. Örneğin, yukarıdaki tabloda her satır bir çiçek için yapılan ölçümü ifade etmektedir. Sütunlarda ise her bir ölçüme ait farklı özellikler (çanak yaprak en ve boyu ile taç yaprak en ve boyu) ve çiçek türü (setosa, versicolor, virginica) yer almaktadır.

Neyse ki Matlab, R gibi diller gibi Python’da da iki (ve daha fazla) boyutlu veri kümeleri için kullanılabilecek paketler mevcuttur. Bunlar arasında yer alan numpy paketini daha önce görmüştük. Numpy paketinin bir eksikliği, numpy dizilerinin sadece aynı türde verilerden oluşabilmesidir. Ancak, gerçek hayatta kullandığımız birçok veri kümesi farklı sütunlarda farklı veri türleri içerebilmektedir. Örneğin, yukarıdaki tabloda ilk dört sütundaki veriler sayısal, son sütundaki veri tipi ise metin türündedir.

Pandas paketinde yukarıdaki gibi iki boyutlu veri kümeleri data frame (veri çerçevesi) olarak isimlendirilir (bundan sonra data frame terimi kullanılacaktır). Veri çerçeveleri, Python’da veri analizini son derece kolaylaştıran çok kullanışlı veri yapılarıdır. R programlama dilini bilenler için Pandas data frame, R’daki data frame ile aynıdır. Data frame yukarıda anlattığımız iki boyutlu veri kümesi özelliklerini taşır. Her satırda bir gözlem, her sütunda da farklı bir değişken yer alır. Bir sütunda yer alan tüm veriler aynı tiptedir ama farklı sütunlarda farklı veri türleri yer alabilir. Data frameler, veri bilimi açısından çok faydalı veri yapılarıdır. Bunları kullanarak betimsel ve çıkarımsal veri analizi yapmak, istatistiksel modeller kurmak, verileri görselleştirmek daha kolaydır. Bunlardan olayı veri biliminde Python kullananlar için Pandas modülünden faydalanmak neredeyse standart hale gelmiştir.

Bir pandas data frame oluşturmak için farklı yöntemler vardır. Bunlardan bir tanesi sözlük veri yapısını kullanmaktır. Şimdi yukarıda yer alan tabloyu oluşturmak için önce bu verileri bir sözlük olarak tanımlayalım.

iris_dict = {
'Sepal_Length':[5.1, 4.9, 4.7, 4.6, 5.0, 6.7, 6.3, 6.5, 6.2, 5.9],
'Sepal_Width' :[3.5, 3.0, 3.2, 3.1, 3.6, 3.0, 2.5, 3.0, 3.4, 3.0],
'Petal_Length':[1.4, 1.4, 1.3, 1.5, 1.4, 5.2, 5.0, 5.2, 5.4, 5.1],
'Petal_Width' :[0.2, 0.2, 0.2, 0.2, 0.2, 2.3, 1.9, 2.0, 2.3, 1.8],
'Species'     :['setosa', 'setosa', 'setosa', 'setosa', 'setosa', 
                'virginica', 'virginica', 'virginica','virginica',     
                'virginica']
}

iris_dict
{'Sepal_Length': [5.1, 4.9, 4.7, 4.6, 5.0, 6.7, 6.3, 6.5, 6.2, 5.9],
 'Sepal_Width': [3.5, 3.0, 3.2, 3.1, 3.6, 3.0, 2.5, 3.0, 3.4, 3.0],
 'Petal_Length': [1.4, 1.4, 1.3, 1.5, 1.4, 5.2, 5.0, 5.2, 5.4, 5.1],
 'Petal_Width': [0.2, 0.2, 0.2, 0.2, 0.2, 2.3, 1.9, 2.0, 2.3, 1.8],
 'Species': ['setosa',
  'setosa',
  'setosa',
  'setosa',
  'setosa',
  'virginica',
  'virginica',
  'virginica',
  'virginica',
  'virginica']}

Sonrasında da pandas paketini import komutu ile içeri aktarıyoruz.

import pandas as pd

Son olarak yukarıda tanımladığımız sözlüğü pandas DataFrame veri tipine dönüştürmek için .DataFrame() metodunu kullanıyoruz. Oluşturulan dataframe’in satırları sıfırdan başlamak üzere numaralandırılır.

iris = pd.DataFrame(iris_dict)
print(iris)
   Sepal_Length  Sepal_Width  Petal_Length  Petal_Width    Species
0           5.1          3.5           1.4          0.2     setosa
1           4.9          3.0           1.4          0.2     setosa
2           4.7          3.2           1.3          0.2     setosa
3           4.6          3.1           1.5          0.2     setosa
4           5.0          3.6           1.4          0.2     setosa
5           6.7          3.0           5.2          2.3  virginica
6           6.3          2.5           5.0          1.9  virginica
7           6.5          3.0           5.2          2.0  virginica
8           6.2          3.4           5.4          2.3  virginica
9           5.9          3.0           5.1          1.8  virginica

Şimdi biraz daha uzun bir yöntem görelim. Bu yöntemi pek kullanmayacak olsak da farklı veri yapılarını tekrar etmek için iyi bir fırsat. Bu yöntemde dataframe sütunlarını önce listeler olarak tanımlıyoruz. Daha sonra sütun isimleri ve sütunları zip fonksiyonunu kullanarak tuple verilerden oluşan bir listeye çeviriyoruz. Burada zipledikten sonra tekrar list fonksiyonunu kullandığımıza dikkat edin. Sonraki aşamada zip veri yapısını sözlüğe ve en son olarak da sözlüğü Pandas data frame’e çeviriyoruz.

# Önce sütunları liste olarak tanımlayalım. 

Sepal_Length = [5.1, 4.9, 4.7, 4.6, 5.0, 6.7, 6.3, 6.5, 6.2, 5.9]
Sepal_Width  = [3.5, 3.0, 3.2, 3.1, 3.6, 3.0, 2.5, 3.0, 3.4, 3.0]
Petal_Length = [1.4, 1.4, 1.3, 1.5, 1.4, 5.2, 5.0, 5.2, 5.4, 5.1]
Petal_Width  = [0.2, 0.2, 0.2, 0.2, 0.2, 2.3, 1.9, 2.0, 2.3, 1.8]
Species = ['setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'virginica',
           'virginica', 'virginica', 'virginica', 'virginica']


sutun_isimleri = ['Sepal_Length', 'Sepal_Width', 'Petal_Length', 'Petal_Width', 'Species']
sutunlar = [Sepal_Length, Sepal_Width, Petal_Length, Petal_Width]
# Sütun isimleri ve sütunları zip fonksiyonu ile bir araya getirelim.
zip_veri = list(zip(sutun_isimleri, sutunlar))
print(zip_veri)
[('Sepal_Length', [5.1, 4.9, 4.7, 4.6, 5.0, 6.7, 6.3, 6.5, 6.2, 5.9]), ('Sepal_Width', [3.5, 3.0, 3.2, 3.1, 3.6, 3.0, 2.5, 3.0, 3.4, 3.0]), ('Petal_Length', [1.4, 1.4, 1.3, 1.5, 1.4, 5.2, 5.0, 5.2, 5.4, 5.1]), ('Petal_Width', [0.2, 0.2, 0.2, 0.2, 0.2, 2.3, 1.9, 2.0, 2.3, 1.8])]
# Ziplenmiş veriyi sözlük veri yapısına çevirelim
veri = dict(zip_veri)
print(veri)
{'Sepal_Length': [5.1, 4.9, 4.7, 4.6, 5.0, 6.7, 6.3, 6.5, 6.2, 5.9], 'Sepal_Width': [3.5, 3.0, 3.2, 3.1, 3.6, 3.0, 2.5, 3.0, 3.4, 3.0], 'Petal_Length': [1.4, 1.4, 1.3, 1.5, 1.4, 5.2, 5.0, 5.2, 5.4, 5.1], 'Petal_Width': [0.2, 0.2, 0.2, 0.2, 0.2, 2.3, 1.9, 2.0, 2.3, 1.8]}
# Son olarak sözlüğü Veri Çerçevesine çevirelim.
iris = pd.DataFrame(veri)
print(iris)
   Sepal_Length  Sepal_Width  Petal_Length  Petal_Width
0           5.1          3.5           1.4          0.2
1           4.9          3.0           1.4          0.2
2           4.7          3.2           1.3          0.2
3           4.6          3.1           1.5          0.2
4           5.0          3.6           1.4          0.2
5           6.7          3.0           5.2          2.3
6           6.3          2.5           5.0          1.9
7           6.5          3.0           5.2          2.0
8           6.2          3.4           5.4          2.3
9           5.9          3.0           5.1          1.8

Varolan bir veri çerçevesine yeni bir sütun eklemek de mümkündür.

iris['Gözlem_No'] = 1
print(iris)
   Sepal_Length  Sepal_Width  Petal_Length  Petal_Width  Gözlem_No
0           5.1          3.5           1.4          0.2          1
1           4.9          3.0           1.4          0.2          1
2           4.7          3.2           1.3          0.2          1
3           4.6          3.1           1.5          0.2          1
4           5.0          3.6           1.4          0.2          1
5           6.7          3.0           5.2          2.3          1
6           6.3          2.5           5.0          1.9          1
7           6.5          3.0           5.2          2.0          1
8           6.2          3.4           5.4          2.3          1
9           5.9          3.0           5.1          1.8          1

Yukarıda aktardığımız, sözlükten data frame üretme yöntemi günlük hayatta kullanılabilecek bir yöntem değildir. Gerçekte çok büyük verilerle çalıştığımızı düşünürsek tek tek bütün verilerin sözlük olarak girilmesi mümkün değildir.

Günlük hayatta kullandığımız veriler genelce excel, csv gibi formatlarda gelir. Pandas ile farklı formatlardan veri okuma konusunu sonraki bölümlerde ayrıntılı olarak göreceğiz. Şimdilik bir şekilde iris veri setini datframe olarak okuduğumuzu düşünelim. Aşağıda bunu yapıyoruz. Şimdilik aşağıda yer alan kodu görmezden gelin ve sadece iris veri setini dataframe olarak okuduğumuzu düşünelim.

import seaborn as sns

iris = sns.load_dataset("iris")

Data frame hangi sütunlardan oluşuyor? Bunu görmek için .columns özelliğini kullanabiliriz.

iris.columns
Index(['sepal_length', 'sepal_width', 'petal_length', 'petal_width',
       'species'],
      dtype='object')

Aynı şekilde bir data frame’in sütun isimlerini değiştirmek de mümkündür.

iris.columns = ["SepalLength", "SepalWidth", "PetalLength", "PetalWidth", "Species"]
print(iris)
     SepalLength  SepalWidth  PetalLength  PetalWidth    Species
0            5.1         3.5          1.4         0.2     setosa
1            4.9         3.0          1.4         0.2     setosa
2            4.7         3.2          1.3         0.2     setosa
3            4.6         3.1          1.5         0.2     setosa
4            5.0         3.6          1.4         0.2     setosa
..           ...         ...          ...         ...        ...
145          6.7         3.0          5.2         2.3  virginica
146          6.3         2.5          5.0         1.9  virginica
147          6.5         3.0          5.2         2.0  virginica
148          6.2         3.4          5.4         2.3  virginica
149          5.9         3.0          5.1         1.8  virginica

[150 rows x 5 columns]

Iris data frameinin genel yapısını incelemek için .head() metodunu kullanabiliriz. Bu metod da argüman olarak görmek istediğimiz satır sayısını iletebiliriz. Herhangi bir değer beştir.

iris.head(10)
SepalLength SepalWidth PetalLength PetalWidth Species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
5 5.4 3.9 1.7 0.4 setosa
6 4.6 3.4 1.4 0.3 setosa
7 5.0 3.4 1.5 0.2 setosa
8 4.4 2.9 1.4 0.2 setosa
9 4.9 3.1 1.5 0.1 setosa

Benzer şekilde, son satırları görmek için de .tail() metodu kullanılır. Bu metoda da aynı biçimde sondan kaç satırı görmek istediğimiz yazılabilir.

iris.tail(4)
SepalLength SepalWidth PetalLength PetalWidth Species
146 6.3 2.5 5.0 1.9 virginica
147 6.5 3.0 5.2 2.0 virginica
148 6.2 3.4 5.4 2.3 virginica
149 5.9 3.0 5.1 1.8 virginica

Yukarıdaki komutu Jupyter Python defteri kullanarak yazdım ve yukarıda gördüğünüz tablo formatlarını da yine aynı programdan aldım. PyCharm gibi entegre kodlama programlarında sadece yazdırmak istediğiniz veri yapısının adını girmeniz (örneğin iris) herhangi bir sonuç vermeyecektir. Bir veri yapısının tamamını ya da bir kısmını yazdırmak için print() fonksiyonunu kullanmanız gerekir. Diğer yandan Jupyter gibi daha çok veri analizi için geliştirilmiş ortamlarda doğrudan verinin adını yazmanız yetecektir. Jupyter’de print fonksiyonu kullanırsanız da sonuç alırsınız ancak format biraz daha farklı olur.

print(iris.tail(4))
     SepalLength  SepalWidth  PetalLength  PetalWidth    Species
146          6.3         2.5          5.0         1.9  virginica
147          6.5         3.0          5.2         2.0  virginica
148          6.2         3.4          5.4         2.3  virginica
149          5.9         3.0          5.1         1.8  virginica

Data frame boyutlarına yani kaç satır ve kaç sütundan oluştuğuna bakalım.

iris.shape
(150, 5)

Data frame bilgilerini alabileceğimiz bir diğer metod da .info() metodudur ancak bu metod istatistiksel özellikler yerine sütunların veri tipi, veri çerçevesindeki satır sayısı, her bir sütundaki veri sayısı gibi değerleri verir.

iris.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 5 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   SepalLength  150 non-null    float64
 1   SepalWidth   150 non-null    float64
 2   PetalLength  150 non-null    float64
 3   PetalWidth   150 non-null    float64
 4   Species      150 non-null    object 
dtypes: float64(4), object(1)
memory usage: 6.0+ KB

Bir data frame’i olduğu gibi başka bir data frame’e aktarmak için .copy() metodunu kullanabiliriz.

iris_yeni = iris.copy()

Pandas paketinin, Numpy paketi üzerinde geliştirildiğini daha önce belirtmiştik. İstenirse bir pandas veri çerçevesini .values özelliğini kullanarak numpy dizisine çevirebiliriz.

np_dizi = iris.values
print(np_dizi)
[[5.1 3.5 1.4 0.2 'setosa']
 [4.9 3.0 1.4 0.2 'setosa']
 [4.7 3.2 1.3 0.2 'setosa']
 [4.6 3.1 1.5 0.2 'setosa']
 [5.0 3.6 1.4 0.2 'setosa']
 [5.4 3.9 1.7 0.4 'setosa']
 [4.6 3.4 1.4 0.3 'setosa']
 [5.0 3.4 1.5 0.2 'setosa']
 [4.4 2.9 1.4 0.2 'setosa']
 [4.9 3.1 1.5 0.1 'setosa']
 [5.4 3.7 1.5 0.2 'setosa']
 [4.8 3.4 1.6 0.2 'setosa']
 [4.8 3.0 1.4 0.1 'setosa']
 [4.3 3.0 1.1 0.1 'setosa']
 [5.8 4.0 1.2 0.2 'setosa']
 [5.7 4.4 1.5 0.4 'setosa']
 [5.4 3.9 1.3 0.4 'setosa']
 [5.1 3.5 1.4 0.3 'setosa']
 [5.7 3.8 1.7 0.3 'setosa']
 [5.1 3.8 1.5 0.3 'setosa']
 [5.4 3.4 1.7 0.2 'setosa']
 [5.1 3.7 1.5 0.4 'setosa']
 [4.6 3.6 1.0 0.2 'setosa']
 [5.1 3.3 1.7 0.5 'setosa']
 [4.8 3.4 1.9 0.2 'setosa']
 [5.0 3.0 1.6 0.2 'setosa']
 [5.0 3.4 1.6 0.4 'setosa']
 [5.2 3.5 1.5 0.2 'setosa']
 [5.2 3.4 1.4 0.2 'setosa']
 [4.7 3.2 1.6 0.2 'setosa']
 [4.8 3.1 1.6 0.2 'setosa']
 [5.4 3.4 1.5 0.4 'setosa']
 [5.2 4.1 1.5 0.1 'setosa']
 [5.5 4.2 1.4 0.2 'setosa']
 [4.9 3.1 1.5 0.2 'setosa']
 [5.0 3.2 1.2 0.2 'setosa']
 [5.5 3.5 1.3 0.2 'setosa']
 [4.9 3.6 1.4 0.1 'setosa']
 [4.4 3.0 1.3 0.2 'setosa']
 [5.1 3.4 1.5 0.2 'setosa']
 [5.0 3.5 1.3 0.3 'setosa']
 [4.5 2.3 1.3 0.3 'setosa']
 [4.4 3.2 1.3 0.2 'setosa']
 [5.0 3.5 1.6 0.6 'setosa']
 [5.1 3.8 1.9 0.4 'setosa']
 [4.8 3.0 1.4 0.3 'setosa']
 [5.1 3.8 1.6 0.2 'setosa']
 [4.6 3.2 1.4 0.2 'setosa']
 [5.3 3.7 1.5 0.2 'setosa']
 [5.0 3.3 1.4 0.2 'setosa']
 [7.0 3.2 4.7 1.4 'versicolor']
 [6.4 3.2 4.5 1.5 'versicolor']
 [6.9 3.1 4.9 1.5 'versicolor']
 [5.5 2.3 4.0 1.3 'versicolor']
 [6.5 2.8 4.6 1.5 'versicolor']
 [5.7 2.8 4.5 1.3 'versicolor']
 [6.3 3.3 4.7 1.6 'versicolor']
 [4.9 2.4 3.3 1.0 'versicolor']
 [6.6 2.9 4.6 1.3 'versicolor']
 [5.2 2.7 3.9 1.4 'versicolor']
 [5.0 2.0 3.5 1.0 'versicolor']
 [5.9 3.0 4.2 1.5 'versicolor']
 [6.0 2.2 4.0 1.0 'versicolor']
 [6.1 2.9 4.7 1.4 'versicolor']
 [5.6 2.9 3.6 1.3 'versicolor']
 [6.7 3.1 4.4 1.4 'versicolor']
 [5.6 3.0 4.5 1.5 'versicolor']
 [5.8 2.7 4.1 1.0 'versicolor']
 [6.2 2.2 4.5 1.5 'versicolor']
 [5.6 2.5 3.9 1.1 'versicolor']
 [5.9 3.2 4.8 1.8 'versicolor']
 [6.1 2.8 4.0 1.3 'versicolor']
 [6.3 2.5 4.9 1.5 'versicolor']
 [6.1 2.8 4.7 1.2 'versicolor']
 [6.4 2.9 4.3 1.3 'versicolor']
 [6.6 3.0 4.4 1.4 'versicolor']
 [6.8 2.8 4.8 1.4 'versicolor']
 [6.7 3.0 5.0 1.7 'versicolor']
 [6.0 2.9 4.5 1.5 'versicolor']
 [5.7 2.6 3.5 1.0 'versicolor']
 [5.5 2.4 3.8 1.1 'versicolor']
 [5.5 2.4 3.7 1.0 'versicolor']
 [5.8 2.7 3.9 1.2 'versicolor']
 [6.0 2.7 5.1 1.6 'versicolor']
 [5.4 3.0 4.5 1.5 'versicolor']
 [6.0 3.4 4.5 1.6 'versicolor']
 [6.7 3.1 4.7 1.5 'versicolor']
 [6.3 2.3 4.4 1.3 'versicolor']
 [5.6 3.0 4.1 1.3 'versicolor']
 [5.5 2.5 4.0 1.3 'versicolor']
 [5.5 2.6 4.4 1.2 'versicolor']
 [6.1 3.0 4.6 1.4 'versicolor']
 [5.8 2.6 4.0 1.2 'versicolor']
 [5.0 2.3 3.3 1.0 'versicolor']
 [5.6 2.7 4.2 1.3 'versicolor']
 [5.7 3.0 4.2 1.2 'versicolor']
 [5.7 2.9 4.2 1.3 'versicolor']
 [6.2 2.9 4.3 1.3 'versicolor']
 [5.1 2.5 3.0 1.1 'versicolor']
 [5.7 2.8 4.1 1.3 'versicolor']
 [6.3 3.3 6.0 2.5 'virginica']
 [5.8 2.7 5.1 1.9 'virginica']
 [7.1 3.0 5.9 2.1 'virginica']
 [6.3 2.9 5.6 1.8 'virginica']
 [6.5 3.0 5.8 2.2 'virginica']
 [7.6 3.0 6.6 2.1 'virginica']
 [4.9 2.5 4.5 1.7 'virginica']
 [7.3 2.9 6.3 1.8 'virginica']
 [6.7 2.5 5.8 1.8 'virginica']
 [7.2 3.6 6.1 2.5 'virginica']
 [6.5 3.2 5.1 2.0 'virginica']
 [6.4 2.7 5.3 1.9 'virginica']
 [6.8 3.0 5.5 2.1 'virginica']
 [5.7 2.5 5.0 2.0 'virginica']
 [5.8 2.8 5.1 2.4 'virginica']
 [6.4 3.2 5.3 2.3 'virginica']
 [6.5 3.0 5.5 1.8 'virginica']
 [7.7 3.8 6.7 2.2 'virginica']
 [7.7 2.6 6.9 2.3 'virginica']
 [6.0 2.2 5.0 1.5 'virginica']
 [6.9 3.2 5.7 2.3 'virginica']
 [5.6 2.8 4.9 2.0 'virginica']
 [7.7 2.8 6.7 2.0 'virginica']
 [6.3 2.7 4.9 1.8 'virginica']
 [6.7 3.3 5.7 2.1 'virginica']
 [7.2 3.2 6.0 1.8 'virginica']
 [6.2 2.8 4.8 1.8 'virginica']
 [6.1 3.0 4.9 1.8 'virginica']
 [6.4 2.8 5.6 2.1 'virginica']
 [7.2 3.0 5.8 1.6 'virginica']
 [7.4 2.8 6.1 1.9 'virginica']
 [7.9 3.8 6.4 2.0 'virginica']
 [6.4 2.8 5.6 2.2 'virginica']
 [6.3 2.8 5.1 1.5 'virginica']
 [6.1 2.6 5.6 1.4 'virginica']
 [7.7 3.0 6.1 2.3 'virginica']
 [6.3 3.4 5.6 2.4 'virginica']
 [6.4 3.1 5.5 1.8 'virginica']
 [6.0 3.0 4.8 1.8 'virginica']
 [6.9 3.1 5.4 2.1 'virginica']
 [6.7 3.1 5.6 2.4 'virginica']
 [6.9 3.1 5.1 2.3 'virginica']
 [5.8 2.7 5.1 1.9 'virginica']
 [6.8 3.2 5.9 2.3 'virginica']
 [6.7 3.3 5.7 2.5 'virginica']
 [6.7 3.0 5.2 2.3 'virginica']
 [6.3 2.5 5.0 1.9 'virginica']
 [6.5 3.0 5.2 2.0 'virginica']
 [6.2 3.4 5.4 2.3 'virginica']
 [5.9 3.0 5.1 1.8 'virginica']]

Numpy için geçerli olan metodları pandas data frame’ler için de uygulayabiliriz. Örneğin sayısal değerlerden oluşan bir veri çerçevesindeki değerlerin doğal logaritmasını bulmak için numpy paketindeki .log() metodunu uygulayabiliriz.

import numpy as np
# Önce iris'in sayısal sütunlarını seçelim
dizi = iris.iloc[:,[0,1,2,3]]
dizi_log = np.log(dizi)
print(dizi_log.head())
   SepalLength  SepalWidth  PetalLength  PetalWidth
0     1.629241    1.252763     0.336472   -1.609438
1     1.589235    1.098612     0.336472   -1.609438
2     1.547563    1.163151     0.262364   -1.609438
3     1.526056    1.131402     0.405465   -1.609438
4     1.609438    1.280934     0.336472   -1.609438

Şimdiye kadar gördüğümüz pandas serileri ve data frameler esasen bir ve iki boyutlu veri yapılarıdır. Ancak, pandas üç ve daha fazla boyutlu veri yapılarına da izin vermektedir. Bunu, pandas verilerinde çoklu indeks ekleyerek yapıyoruz. Önce bir pandas serisine çoklu indeks eklemeyi görelim. Aşağıdaki örnekte farklı hisse senetlerinin 2016 ve 2017 yılı kapanış fiyatlarını görüyoruz.

indeks = [('ABC', 2016), ('ABC', 2017),
          ('DEF', 2016), ('DEF', 2017),
          ('XYZ', 2016), ('XYZ', 2017),
          ('KLM', 2016), ('KLM', 2017)]
fiyatlar = [32.5, 12.3, 24.7, 18.6, 20.3, 7.2, 51.9, 56.2]

hisseler = pd.Series(fiyatlar, index = indeks)
hisseler
(ABC, 2016)    32.5
(ABC, 2017)    12.3
(DEF, 2016)    24.7
(DEF, 2017)    18.6
(XYZ, 2016)    20.3
(XYZ, 2017)     7.2
(KLM, 2016)    51.9
(KLM, 2017)    56.2
dtype: float64

Verileri bu şekilde indeksleyerek seride seçim de yapabiliriz.

hisseler[('XYZ',2016):('KLM',2017)]
(XYZ, 2016)    20.3
(XYZ, 2017)     7.2
(KLM, 2016)    51.9
(KLM, 2017)    56.2
dtype: float64

Yukarıdaki gibi çoklu indeks kullanmanın daha etkin bir yöntemi ise pandas MultiIndex kullanmaktır.

indeks = pd.MultiIndex.from_tuples(indeks)
indeks
MultiIndex([('ABC', 2016),
            ('ABC', 2017),
            ('DEF', 2016),
            ('DEF', 2017),
            ('XYZ', 2016),
            ('XYZ', 2017),
            ('KLM', 2016),
            ('KLM', 2017)],
           )
hisseler = pd.Series(fiyatlar, index=indeks)
hisseler
ABC  2016    32.5
     2017    12.3
DEF  2016    24.7
     2017    18.6
XYZ  2016    20.3
     2017     7.2
KLM  2016    51.9
     2017    56.2
dtype: float64

İndeksleri isimlendirmek de mümkündür.

hisseler.index.names = ['Hisse', 'Yıl']
hisseler
Hisse  Yıl 
ABC    2016    32.5
       2017    12.3
DEF    2016    24.7
       2017    18.6
XYZ    2016    20.3
       2017     7.2
KLM    2016    51.9
       2017    56.2
dtype: float64

Yukarıdaki hisseler verisi bir boyutlu pandas verisi ancak ilk iki sütunda belirtilen iki indeksle gösteriliyor. Bu seriyi pandas modülündeki .unstack() metodunu kullanarak data frame’e çevirebiliriz.

hisseler.unstack()
Yıl 2016 2017
Hisse
ABC 32.5 12.3
DEF 24.7 18.6
KLM 51.9 56.2
XYZ 20.3 7.2

Data frame de .stack() metodu ile eski haline çevrilebilir. MultiIndex ile çoklu indeks oluşturmanın üç farklı yöntemi vardır.

pd.MultiIndex.from_tuples([('x', 1),('x',2), ('y',1), ('y',2)])
MultiIndex([('x', 1),
            ('x', 2),
            ('y', 1),
            ('y', 2)],
           )
pd.MultiIndex.from_arrays([['x', 'x', 'y', 'y'], [1, 2, 1, 2]])
MultiIndex([('x', 1),
            ('x', 2),
            ('y', 1),
            ('y', 2)],
           )
pd.MultiIndex.from_product([['x', 'y'], [1, 2]])
MultiIndex([('x', 1),
            ('x', 2),
            ('y', 1),
            ('y', 2)],
           )

Nasıl ki satırlar için çoklu indeks oluşturabiliyorsak sütunlar için de aynı şekilde çoklu indeks oluşturabiliriz. Çoklu indeks kullanımı özellikle panel verilerle yapılan çalışmalarda oldukça faydalıdır. Şimdi yukarıdaki hisse senedi tablosuna sütunlarına her çeyrek için kapanış fiyatı ve hacim bilgisini ekleyelim.

indeks = pd.MultiIndex.from_product([['ABC', 'DEF', 'KLM'], [2016, 2017]])
sutunlar = pd.MultiIndex.from_product([['Q1', 'Q2', 'Q3', 'Q4'], ['Hacim', 'Kapanış']])

veri = np.array([10762, 32.5, 12638, 33.5, 13689, 35.2, 18414, 37.4,
                 10688, 12.3, 14348, 13.2, 15924, 15.3, 15243, 17.9,
                 14841, 24.7, 14966, 22.1, 13098, 19.3, 17439, 15.4,
                 15607, 18.6, 16166, 13.4, 10627, 15.1, 13396, 15.3,
                 12565, 20.3, 17469, 21.4, 18964, 22.5, 15187, 23.6,
                 13203,  7.2, 10629,  7.2, 15239,  8.2, 18307,  9.1])
veri = np.reshape(veri, (6, 8))

hisseler = pd.DataFrame(veri, index = indeks, columns = sutunlar)
hisseler
Q1 Q2 Q3 Q4
Hacim Kapanış Hacim Kapanış Hacim Kapanış Hacim Kapanış
ABC 2016 10762.0 32.5 12638.0 33.5 13689.0 35.2 18414.0 37.4
2017 10688.0 12.3 14348.0 13.2 15924.0 15.3 15243.0 17.9
DEF 2016 14841.0 24.7 14966.0 22.1 13098.0 19.3 17439.0 15.4
2017 15607.0 18.6 16166.0 13.4 10627.0 15.1 13396.0 15.3
KLM 2016 12565.0 20.3 17469.0 21.4 18964.0 22.5 15187.0 23.6
2017 13203.0 7.2 10629.0 7.2 15239.0 8.2 18307.0 9.1

11.3. Data Frame’de Seçim Yapma#

Bir data framedeki herhangi bir sütunu seçmek ya da görmek için df[“sütun_ismi”] formatı kullanılır. Önce data frame ismi ve yanında köşeli parantez içinde, tırnak ya da kesme işareti içinde görülmek istenen sütun ismi yazılır. Yukarıdaki iris veri setinde PetalLength sütununu görmek için iris["PetalLength"] yazarız.

iris["SepalLength"]
0      5.1
1      4.9
2      4.7
3      4.6
4      5.0
      ... 
145    6.7
146    6.3
147    6.5
148    6.2
149    5.9
Name: SepalLength, Length: 150, dtype: float64

Veri setinin yanında tek köşeli parantez kullanırsak sütundaki veriyi bir boyutlu olarak indirir. Bunu bir liste olarak da düşünebilirsiniz. Nitekim, bu şekilde çektiğimiz verinin türünü incelediğimizde bir boyutlu Series veri tipi olduğunu görürüz.

type(iris["SepalLength"])
pandas.core.series.Series

Yukarıda da görüldüğü gibi veri çerçevesinden çektiğimiz sütunun türü .Series yani bir boyutlu bir dizidir. Eğer istediğimiz sütunun da veri çerçevesi gibi davranmasını istiyorsak sütun ismini iki köşeli parantez içine yazmamız gerekir. Sorgulamayı iris[["SepalLength"]] şeklinde iki köşeli parantez içinde yaparsak aşağıdaki şekilde bir pandas data frame ile karşılaşırız.

iris[["SepalLength"]]
SepalLength
0 5.1
1 4.9
2 4.7
3 4.6
4 5.0
... ...
145 6.7
146 6.3
147 6.5
148 6.2
149 5.9

150 rows × 1 columns

Görüldüğü gibi data frame’den bir sütunu bir adet köşeli parantezle çekince bir boyutlu seri, iki adet köşeli parantezle çekince DataFrame veri yapısı ile karşılaşıyoruz.

Peki birden fazla sütunu çekmek istersek ne yapmamız gerekiyor? Sorgulamayı, bir adet köşeli parantezle yaptığımızda bir boyutlu seri üretildiğini söyledik. Bu nedenle örneğin iris["SepalLength", "SepalWidth"] şeklinde yazarsak hata mesajı ile karşılaşırız. Bu nedenle birden fazla değişkeni seçmek için iki adet köşeli parantez kullanmalıyız.

iris[["SepalLength", "SepalWidth"]]
SepalLength SepalWidth
0 5.1 3.5
1 4.9 3.0
2 4.7 3.2
3 4.6 3.1
4 5.0 3.6
... ... ...
145 6.7 3.0
146 6.3 2.5
147 6.5 3.0
148 6.2 3.4
149 5.9 3.0

150 rows × 2 columns

Sütunları nasıl seçeceğimizi gördük. Şimdi de satırları nasıl seçeceğimizi görelim. Yine iris data frame ile devam edelim. Bir data frame’de belirli satırları seçmek için istediğimiz satır numaralarını arada iki nokta olacak şekilde yazıyoruz. Burada iki noktayı tekrar hatırlatmakta fayda var. Python’da indeks numaraları sıfırdan başlıyor ve indeks sondaki sayıyı kapsamıyor. Yani [2:5] indeks numaralarını yazdığımda, 2 indeks numarası ile başlayan ve 4 indeks numarası ile biten satırlar seçilecek, 5 indeks numarasına sahip satır seçilmeyecektir. İndeks numaralarının sıfırdan başladığını düşünürsek yaptığımız seçim 3. sıradaki satırla başlayıp 5. sıradaki satırla sona erecektir. Sonuç olarak iris[2:5] yazdığımızda aşağıdaki şekilde çerçeve içinde belirtilmiş olan satırlar seçilecektir.

iris data frame

Hatırlayacağınız gibi iki boyutlu numpy dizilerinde hem satır hem de sütunlarda seçim yapmak mümkündü. Yani belirli sütunların belirli satırlarını seçebiliyorduk. Ancak, yukarıda gösterdiğimiz seçim yöntemi hem satır hem de sütunda seçim yapmaya izin vermemektedir. Pandas paketinde satır ve sütunlardan kolayca seçim yapabilmek için .loc ve .iloc metodları geliştirilmiştir. Bunlardan, loc, location (konum), iloc ise integer location (sayısal konum) ifadelerini temsil etmektedir.

Örnek olarak aşağıdaki şekilde görülen hisselerin bir günlük açılış, en düşük, en yüksek ve kapanış fiyatlarını gösteren veri çerçevesini dikkate alalım. Aşağıdaki veri çerçevesinde satırların numaralarla değil hisse isimleri ile belirtildiğini görüyoruz. Bir data frame’de satırları bu şekilde isimlendirmek de mümkündür. Satır isimlendirme için .index() metodu kullanılır. Aşağıdaki data framein isminin hisseler olduğunu varsayalım. Bu durumda, satırları isimlendirmek için hisseler.index = ["ABC", "DEF", "KLM", "XYZ", "IJK", "VYZ", "ERN", "HEA"] yazmamız yeterlidir. Data framei bir csv dosyasından okutuyorsak ve satır isimleri de ilk sütunda ise bu durumda .read_csv() metodunda dosya yolu ve isminden sonra ikinci bir argüman olarak index_col = 0 yazmamız gerekiyor.

acilis

en_dusuk

en_yuksek

kapanis

ABC

3.25

3.15

3.50

3.15

DEF

5.48

5.00

6.00

6.00

KLM

15.75

15.25

16.75

16.50

XYZ

80.20

75.00

85.25

84.30

IJK

17.50

16.00

19.00

18.20

VYZ

25.70

24.10

27.50

26.80

ERN

95.00

90.20

99.50

97.50

HEA

55.00

53.00

57.40

59.30

Yukarıdaki data frame’in isminin hisseler olduğunu varsayalım. Şimdi önce ERN hissesine ait bilgileri görmek isteyelim. Öncelikle dataframe’i oluşturacağız.

hisseler_dict = {'acilis'  : [3.25, 5.48, 15.75, 80.20, 17.50, 25.70, 95.00, 55.00],
                'en_dusuk' : [3.15, 5.00, 15.25, 75.00, 16.00, 24.10, 90.20, 53.00],
                'en_yuksek': [3.50, 6.00, 16.75, 85.25, 19.00, 27.50, 99.50, 57.40],
                'kapanis'  : [3.15, 6.00, 16.50, 84.30, 18.20, 26.80, 97.50, 59.30]}

hisseler = pd.DataFrame(hisseler_dict, index = ["ABC", "DEF", "KLM", "XYZ", "IJK", "VYZ", "ERN", "HEA"])
hisseler
acilis en_dusuk en_yuksek kapanis
ABC 3.25 3.15 3.50 3.15
DEF 5.48 5.00 6.00 6.00
KLM 15.75 15.25 16.75 16.50
XYZ 80.20 75.00 85.25 84.30
IJK 17.50 16.00 19.00 18.20
VYZ 25.70 24.10 27.50 26.80
ERN 95.00 90.20 99.50 97.50
HEA 55.00 53.00 57.40 59.30

Satır isimleri ile seçim yapmak için .loc[] (location) metodunu kullanıyoruz.

hisseler.loc["ERN"]
acilis       95.0
en_dusuk     90.2
en_yuksek    99.5
kapanis      97.5
Name: ERN, dtype: float64

Seçimi bir adet köşeli parantez kullanarak yaptığımız için sonuç seri formatında geldi. Yine data frame formatında gelmesini sağlamak için iki adet köşeli parantez kullanmamız gerektiğini hatırlayalım.

hisseler.loc[["ERN"]]
acilis en_dusuk en_yuksek kapanis
ERN 95.0 90.2 99.5 97.5

Bu şekilde birden fazla satır seçmek de mümkündür.

hisseler.loc[["ERN", "HEA"]]
acilis en_dusuk en_yuksek kapanis
ERN 95.0 90.2 99.5 97.5
HEA 55.0 53.0 57.4 59.3

Bir sütun ve satırdaki değeri almak için sütun ve satır isimlerini sırayla köşeli parantez içinde aşağıda görüldüğü gibi belirtmek de mümkündür. Önce sütun daha sonra satır ismi belirttiğimize dikkat edin.

hisseler['acilis']['ERN']
95.0

Aynı seçimi aşağıdaki şekilde de yapabiliriz.

hisseler.acilis['ERN']
95.0

Şimdi de birden fazla satır ve sütun ismi kullanarak seçim yapmayı görelim. Bu tür seçimlerde .loc özelliğini kullanırız. Bunun için de istediğimiz satır ve sütunları virgülle ayrılmış iki ayrı liste olarak iletmemiz gerekiyor.

hisseler.loc[["ERN", "HEA"], ["en_dusuk", "en_yuksek"]]
en_dusuk en_yuksek
ERN 90.2 99.5
HEA 53.0 57.4

Yukarıdaki seçimi bir adet satır ve sütun için de yapabileceğimizi unutmayın.

hisseler.loc['ERN', 'acilis']
95.0

Belirli değişkenlere ait tüm satırları seçtirmek için satır ismi yazmayıp bunun yerine önceki bölümlerde gördüğümüz gibi : yazmamız yeterlidir.

hisseler.loc[:, ["en_dusuk", "en_yuksek"]]
en_dusuk en_yuksek
ABC 3.15 3.50
DEF 5.00 6.00
KLM 15.25 16.75
XYZ 75.00 85.25
IJK 16.00 19.00
VYZ 24.10 27.50
ERN 90.20 99.50
HEA 53.00 57.40

Yukarıda tüm satırlar için mutlaka : kullanmamız gerektiğine dikkat edin. Bunun yerine sadece hisseler.loc[["en_dusuk", "en_yuksek"]] yazarsanız hata mesajı ile karşılaşırsınız.

Satır ve sütun isimleri yerine indeks numaraları ile seçim yapmak için iloc fonksiyonu kullanılır. Bu kullanım şeklinde tek fark satır ve sütunların isimleri yerine indeks numaralarını kullanmamızdır.

hisseler.iloc[1]
acilis       5.48
en_dusuk     5.00
en_yuksek    6.00
kapanis      6.00
Name: DEF, dtype: float64
hisseler.iloc[[1]]
acilis en_dusuk en_yuksek kapanis
DEF 5.48 5.0 6.0 6.0
hisseler.iloc[6,0]
95.0
hisseler.iloc[[1,2,3]]
acilis en_dusuk en_yuksek kapanis
DEF 5.48 5.00 6.00 6.0
KLM 15.75 15.25 16.75 16.5
XYZ 80.20 75.00 85.25 84.3

Yine iki adet köşeli parantez kullandığımıza dikkat edin. Bir tane köşeli parantez kullanmamız halinde sonuç aşağıdaki gibi olacaktır.

hisseler.iloc[1]
acilis       5.48
en_dusuk     5.00
en_yuksek    6.00
kapanis      6.00
Name: DEF, dtype: float64

Artık, sonucu yine data frame olarak almak için çift köşeli parantez kullanmamız gerektiğini biliyoruz.

Birden fazla satır ve sütunda seçim yapmak için yine loc fonksiyonunda olduğu şekilde ama bu defa satır ve sütun indeks numaralarını belirterek yazıyoruz.

hisseler.iloc[[1,2,3], [2,3]]
en_yuksek kapanis
DEF 6.00 6.0
KLM 16.75 16.5
XYZ 85.25 84.3

Sütun ismi ve index numaralarını bir arada kullanmak da mümkündür. Örneğin, ilk 4 sıradaki hissenin kapanış fiyatlarını görelim:

hisseler['kapanis'][0:4]
ABC     3.15
DEF     6.00
KLM    16.50
XYZ    84.30
Name: kapanis, dtype: float64

Satır seçimine 0:4 yazdığımızda 0, 1, 2, ve 3. sıradaki yani ilk dört sıradaki verileri çektiğimize dikkat edin. “:” işaretini satır veya sütun isimleriyle de kullanabiliriz.

hisseler.loc['ABC':'KLM', 'en_dusuk':'kapanis']
en_dusuk en_yuksek kapanis
ABC 3.15 3.50 3.15
DEF 5.00 6.00 6.00
KLM 15.25 16.75 16.50

Satır ya da sütunları ters sırada yazdırmak da mümkündür.

hisseler.loc['KLM':'ABC':-1]
acilis en_dusuk en_yuksek kapanis
KLM 15.75 15.25 16.75 16.50
DEF 5.48 5.00 6.00 6.00
ABC 3.25 3.15 3.50 3.15

Buraya kadar satır ve sütunlardan seçim yapmak için çok sayıda yöntem aktardık. Bunlar kullanımların özellikle ilk kullanımlarda karıştırılması normaldir. Kolay başvuru için yukarıda aktardığımız satır ve sütun seçim yöntemlerini aşağıdaki tabloda özetliyoruz.

Kullanım

Sonuç

hisseler[“kapanis”]

Sütunu bir boyutlu seri olarak alır

hisseler[[“kapanis”]]

Sütunu pandas veri çerçevesi olarak alır

hisseler[[“en_yuksek”, “kapanis”]]

Sütunları pandas data frame olarak alır

hisseler[2:5]

3. satırdan (indeks no:2) başlayarak 5. satır (indeks no :4) dahil olacak şekilde satırları alır

hisseler.loc[“ERN”]

Satırı bir boyutlu seri olarak alır

hisseler.loc[[“ERN”]]

Satırı pandas data frame olarak alır

hisseler.loc[[“ERN”, “HEA”]]

Satırları pandas data frame olarak alır

hisseler.loc[[“ERN”, “HEA”], [“en_yuksek”]]

Satır ve sütunları pandas data frame olarak alır

hisseler.loc[:, [“en_dusuk”, “en_yuksek”]]

İstenen sütunların tüm satırları alır

hisseler.iloc[[1]]

İndeks numarası 1 olan (2. sıradaki) satırı alır

hisseler.iloc[[1,2,3], [2,3]]

İndeks numarası 1,2 ve 3 olan satırlar ile 2,3 olan sütunlar

Bir pandas veri çerçevesine for döngüsü uygularsak ne olur? Yukarıda kullandığımız hisseler veri çerçevesine for döngüsü uygulayalım.

for i in hisseler:
    print(i)
acilis
en_dusuk
en_yuksek
kapanis

Görüldüğü gibi sadece değişken (sütun) isimleri yazdırılıyor. Bir pandas data framedeki bilgilere erişmek için pandas paketinde yer alan .iterrows() metodu kullanılır. Şimdi bu metodu kullanarak bir for döngüsü yazalım.

for hisse, satir in hisseler.iterrows():
    print(hisse)
    print(satir)
ABC
acilis       3.25
en_dusuk     3.15
en_yuksek    3.50
kapanis      3.15
Name: ABC, dtype: float64
DEF
acilis       5.48
en_dusuk     5.00
en_yuksek    6.00
kapanis      6.00
Name: DEF, dtype: float64
KLM
acilis       15.75
en_dusuk     15.25
en_yuksek    16.75
kapanis      16.50
Name: KLM, dtype: float64
XYZ
acilis       80.20
en_dusuk     75.00
en_yuksek    85.25
kapanis      84.30
Name: XYZ, dtype: float64
IJK
acilis       17.5
en_dusuk     16.0
en_yuksek    19.0
kapanis      18.2
Name: IJK, dtype: float64
VYZ
acilis       25.7
en_dusuk     24.1
en_yuksek    27.5
kapanis      26.8
Name: VYZ, dtype: float64
ERN
acilis       95.0
en_dusuk     90.2
en_yuksek    99.5
kapanis      97.5
Name: ERN, dtype: float64
HEA
acilis       55.0
en_dusuk     53.0
en_yuksek    57.4
kapanis      59.3
Name: HEA, dtype: float64

Diyelim ki her defasında sadece belirli bir sütundaki verilere erişmek istiyoruz.

for hisse, satir in hisseler.iterrows():
    print(hisse + " : " + str(satir["kapanis"]))
ABC : 3.15
DEF : 6.0
KLM : 16.5
XYZ : 84.3
IJK : 18.2
VYZ : 26.8
ERN : 97.5
HEA : 59.3

For döngüsü kullanarak pandas data frameine yeni bir sütun da ekleyebiliriz. Şimdi her bir hissenin günlük açılış fiyatı ile kapanış fiyatı arasındaki farkı alarak günlük_fark isminde bir sütun oluşturmak istediğimizi düşünelim. Bunu aşağıdaki şekilde kolayca gerçekleştirebiliriz.

for hisse, satir in hisseler.iterrows():
    hisseler.loc[hisse, "gunluk_fark"] = satir["kapanis"] - satir["acilis"]
hisseler
acilis en_dusuk en_yuksek kapanis gunluk_fark
ABC 3.25 3.15 3.50 3.15 -0.10
DEF 5.48 5.00 6.00 6.00 0.52
KLM 15.75 15.25 16.75 16.50 0.75
XYZ 80.20 75.00 85.25 84.30 4.10
IJK 17.50 16.00 19.00 18.20 0.70
VYZ 25.70 24.10 27.50 26.80 1.10
ERN 95.00 90.20 99.50 97.50 2.50
HEA 55.00 53.00 57.40 59.30 4.30

Aslında, yukarıdaki for döngüsünü, data framelerde döngülerin nasıl çalıştığını görmek için yazdık. Ama yeni bir sütun eklemenin çok daha kolay ve hızlı bir yolu vardır. Aşağıdaki kod da yukarıdaki sonucun aynısını çok daha kısa bir sürede verecektir.

hisseler["gunluk_fark"] = hisseler["kapanis"] - hisseler["acilis"]

11.4. Pandas ile Veri Analizi#

Bir veri kümesi ile çalışmaya başlamadan önce ilk olarak verilerin özelliklerine bakılır. Bu özellikle de genellikle minimum, maksimum, ortalama, standart sapma, medyan, %25’lik dilim, %75’lik dilim gibi değerlerdir. Pandas modülünde bu özelliklerin hepsini bir arada gösteren .describe() metodu mevcuttur. Şimdi yine iris veri setini bu metodu kullanarak inceleyelim .

import seaborn as sns
iris = sns.load_dataset('iris')
iris.head()
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
import matplotlib.pyplot as plt
import pandas as pd
iris.describe()
sepal_length sepal_width petal_length petal_width
count 150.000000 150.000000 150.000000 150.000000
mean 5.843333 3.057333 3.758000 1.199333
std 0.828066 0.435866 1.765298 0.762238
min 4.300000 2.000000 1.000000 0.100000
25% 5.100000 2.800000 1.600000 0.300000
50% 5.800000 3.000000 4.350000 1.300000
75% 6.400000 3.300000 5.100000 1.800000
max 7.900000 4.400000 6.900000 2.500000

Her bir sütun için yukarıdan aşağıda sırasıyla count (veri sayısı), mean (ortalama), std (standart sapma), min (en düşük değer), 25% (%25 yüzdelik), 50% (medyan), 75% (%75 yüzdelik) ve max (en yüksek değer) görülmektedir.

Yukarıdaki tabloda sadece sayısal verilere ilişkin özet bilgileri görüyoruz. Ancak iris veri çerçevesinde bir de Species yani tür bilgisini içeren bir sütun bulunuyor. Bu sütuna ait özet bilgileri de .describe() metodu ile görebiliriz. Aşağıda yer alan sonucu incelediğimizde bu sütunda üç farklı değer olduğunu anlıyoruz. Bunlardan en sık görülenin setosa türü olduğu belirtilmiş. Bu kısma dikkat etmek gerekiyor. Aslında iris veri setinde her bir türe ait (setosa, versicolor, virginica) gözlem var. Ancak ilk sırada setosa yer aldığı için top (en çok) görülenin setosa olduğu belirtiliyor. Freq bilgisi ise en sık görülen türe ait kaç gözlem olduğunu belirtiyor.

iris['species'].describe()
count        150
unique         3
top       setosa
freq          50
Name: species, dtype: object

Yukarıdaki gibi sınıf, tür, kategori belirten değişkenler kategorik değişkenler olarak adlandırılır. Veri biliminde sıklıkla kategorik değişkenlerle çalışmamız gerekir. Bir sütunda hangi kategorik değişkenlerin yer aldığını görmek için .unique() metodunu kullanabiliriz. Bu metod, özellikle çok büyük veri setlerinde oldukça kullanışlı olabilir.

iris['species'].unique()
array(['setosa', 'versicolor', 'virginica'], dtype=object)

Sayısal bilgilere ilişkin ortalama, standart sapma vb. özet değerleri ayrı ayrı hesaplamak için de Pandas metodları bulunmaktadır.

iris.count()
sepal_length    150
sepal_width     150
petal_length    150
petal_width     150
species         150
dtype: int64

Sadece istediğimiz sütunları seçerek bunlara ilişkin değerleri de görebiliriz. Örneğin, Petal_Length ve Petal_Width sütunlarının veri sayısını görmek istiyorsak iris[['Petal_Length', 'Petal_Width']].count() yazmamız gerekir. Buradaki çift köşeli parantez yapısına dikkat edin. Bu şekilde yazıyoruz çünkü istediğimiz sütunları liste olarak iletiyoruz. Bunu daha iyi anlamak için aşağıdaki şekilde de yazabiliriz.

veriler = ['petal_length', 'petal_width']
iris[veriler].count()
petal_length    150
petal_width     150
dtype: int64

Aynı şekilde diğer değerleri hesaplamak için de aşağıda belirtilen metodlar kullanılır.

Hesaplama

Metod

Ortalama

.mean()

Standart sapma

.std()

Medyan

.median()

Yüzdelik dilim

.quantile(y)

iris.iloc[:, 0:4].std()
sepal_length    0.828066
sepal_width     0.435866
petal_length    1.765298
petal_width     0.762238
dtype: float64

Gösterilen metodlar arasında .quantile() metodunu açıklamamız gerekiyor. Bu metodu kullanırken hangi yüzdelik dilimi istediğimizi, ondalık sayı şeklinde belirtmemiz gerekiyor. Örneğin, %25’lik dilimi hesaplamak için .quantile(0.25) yazmamız gerekir.

iris.iloc[:, 0:4].quantile(0.25)
sepal_length    5.1
sepal_width     2.8
petal_length    1.6
petal_width     0.3
Name: 0.25, dtype: float64
iris.iloc[:, 0:4].quantile([0.25, 0.75])
sepal_length sepal_width petal_length petal_width
0.25 5.1 2.8 1.6 0.3
0.75 6.4 3.3 5.1 1.8

Herhangi bir sütuna ait bir değeri görmek için bu sütunu seçtirip istediğimiz metodu uygulayabiliriz.

iris['petal_length'].min()
1.0
iris['petal_width'].max()
2.5

Şimdiye kadar gördüğümüz metodları, sütunların yanı sıra satırlara da uygulayabiliriz. Yani satır bazında minimum, maximum, ortalama vb. gibi değerleri hesaplatabiliriz. Bunun için uyguladığımız metod içinde axis='columns' argümanını belirtmemiz gerekir.

iris.iloc[:, 0:4].mean(axis='columns')
0      2.550
1      2.375
2      2.350
3      2.350
4      2.550
       ...  
145    4.300
146    3.925
147    4.175
148    4.325
149    3.950
Length: 150, dtype: float64
iris.iloc[:, 0:4].std(axis='columns')
0      2.179449
1      2.036950
2      1.997498
3      1.912241
4      2.156386
         ...   
145    2.021551
146    2.075853
147    2.046745
148    1.791415
149    1.884144
Length: 150, dtype: float64

Iris veri setinin üç farklı türe ait gözlemlerden meydana geldiğini daha önce belirtmiştik. Şimdiye kadar verdiğimiz örneklerde her üç türe ait gözlemleri bir arada değerlendirdik ve tür farklılıklarını dikkate almadık. Peki ya her bir türe ait istatistiksel değerleri ayrı ayrı hesaplamak istersek ne yapacağız? Bunun için mantıksal seçim kurallarını uygulayabiliriz. Varsayalım ki versicolor türüne ait özet bilgileri görmek istiyorum. Öncelikle, versicolor türüne ait gözlemleri seçip sonra da yaptığım seçime istediğim metodu uygulayabilirim.

Önce versicolor türüne ait gözlemlerin hangi satırlarda yer aldığını görelim. Aşağıda, kosul olarak belirttiğimiz değişken bize False veya True değerlerden oluşan bir seri verecek.

kosul = iris['species'] == 'versicolor'
type(kosul)
pandas.core.series.Series
kosul
0      False
1      False
2      False
3      False
4      False
       ...  
145    False
146    False
147    False
148    False
149    False
Name: species, Length: 150, dtype: bool

Şimdi, bu kosul değerini kullanarak iris veri çerçevesinde sadece versicolor türlerinin olduğu satırları seçtirebiliriz.

versicolor = iris.loc[kosul,:]
versicolor.head()
sepal_length sepal_width petal_length petal_width species
50 7.0 3.2 4.7 1.4 versicolor
51 6.4 3.2 4.5 1.5 versicolor
52 6.9 3.1 4.9 1.5 versicolor
53 5.5 2.3 4.0 1.3 versicolor
54 6.5 2.8 4.6 1.5 versicolor
versicolor.describe()
sepal_length sepal_width petal_length petal_width
count 50.000000 50.000000 50.000000 50.000000
mean 5.936000 2.770000 4.260000 1.326000
std 0.516171 0.313798 0.469911 0.197753
min 4.900000 2.000000 3.000000 1.000000
25% 5.600000 2.525000 4.000000 1.200000
50% 5.900000 2.800000 4.350000 1.300000
75% 6.300000 3.000000 4.600000 1.500000
max 7.000000 3.400000 5.100000 1.800000

Anlaşılması kolay olsun diye ayrı bir kosul serisi tanımladık ama aslında istediğimiz işi iki satırı birleştirerek da yapabiliriz.

iris[iris['species']=='virginica'].describe()
sepal_length sepal_width petal_length petal_width
count 50.00000 50.000000 50.000000 50.00000
mean 6.58800 2.974000 5.552000 2.02600
std 0.63588 0.322497 0.551895 0.27465
min 4.90000 2.200000 4.500000 1.40000
25% 6.22500 2.800000 5.100000 1.80000
50% 6.50000 3.000000 5.550000 2.00000
75% 6.90000 3.175000 5.875000 2.30000
max 7.90000 3.800000 6.900000 2.50000

Özellikle iris[iris['species']=='virginica'] formatına dikkat etmenizi öneririm. Daha önce Python, R veya Matlab gibi bir dil kullanmadıysanız bu format size anlaşılması zor gibi gelebilir. Ancak, zamanla kullana kullana alışacağınızı söyleyebilirim. Burada, iris veri seti içinde (iris[ ]) species sütununun değeri ‘virginica’ olanları (iris['species'] == 'virginica') seçiyoruz. Daha farklı bir anlatımla istediğimiz koşulu iris[ ] veri çerçevesinde köşeli parantezlerin içine yazıyoruz: iris[koşul]. Peki koşulumuz ne? Species sütununun değerinin ‘virginica’ olması, yani: iris['spesies'] == 'virginica'.

Metin tipi sütunlarda koşullu seçim yapmanın bir diğer yolu da .str (string yani metin) metodunu uygulamaktır. Yukarıda uyguladığımız seçimi şimdi de bu metodla yapmaya çalışalım.

kosul = iris['species'].str.contains('setosa')
setosa = iris[kosul]
setosa.head()
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa

Yukarıdaki kodda özellikle üçüncü satırda yer alan .str.contains() yapısına dikkat edin. Burada önce .str metodunu, ardından da .contains (yani içerir) metodunu kullanıyoruz.

Şimdi farklı bir örnek görelim: Sepal_Length değeri 7.5’ten büyük olan kayıtları seçelim.

iris[iris.sepal_length > 7.5]
sepal_length sepal_width petal_length petal_width species
105 7.6 3.0 6.6 2.1 virginica
117 7.7 3.8 6.7 2.2 virginica
118 7.7 2.6 6.9 2.3 virginica
122 7.7 2.8 6.7 2.0 virginica
131 7.9 3.8 6.4 2.0 virginica
135 7.7 3.0 6.1 2.3 virginica

Birden fazla şartı bir arada kullanarak çoklu seçimler de yaptırabiliriz. Örneğin, Sepal_Length değeri 6.5’ten fazla, Petal_Length değeri 4.5’ten az olan satırları seçelim. Aşağıdaki ifadede koşulları parantez içinde belirtmezseniz hata mesajı alırsınız.

iris[(iris.sepal_length > 6.5) & (iris.petal_length < 4.5)]
sepal_length sepal_width petal_length petal_width species
65 6.7 3.1 4.4 1.4 versicolor
75 6.6 3.0 4.4 1.4 versicolor

Bir başka örnek:

iris[(iris.sepal_length > 7.5) | (iris.petal_length > 6.5)]
sepal_length sepal_width petal_length petal_width species
105 7.6 3.0 6.6 2.1 virginica
117 7.7 3.8 6.7 2.2 virginica
118 7.7 2.6 6.9 2.3 virginica
122 7.7 2.8 6.7 2.0 virginica
131 7.9 3.8 6.4 2.0 virginica
135 7.7 3.0 6.1 2.3 virginica

Bir sütun verilerine koşul uygulayarak bir başka sütundan veri çekmek de mümkündür. Örneğin, sepal_length değeri 7.5’tan büyük olan satırların petal_length değerlerini görelim.

iris.petal_length[iris.sepal_length > 7.5]
105    6.6
117    6.7
118    6.9
122    6.7
131    6.4
135    6.1
Name: petal_length, dtype: float64

Buraya kadar anlattıklarımız dışında Pandas modülünde kullanılan farklı metodlar da vardır. Örneğin bir veri çerçevesinde hiç sıfır içermeyen sütunları görmek için .all(), sıfırdan farklı değerler içeren sütunları görmek için .any(), NaN değeri içeren sütunları görmek için .isnull(), içermeyenleri görmek için .notnull() metodları mevcuttur.

Son olarak Pandas veri çerçevelerinde gerçekleştirilebilecek yeniden şekillendirme ve manipülasyon işlemlerine göz atalım. Örneklerimizde kullanmak üzere aşağıdaki df veri çerçevesini oluşturalım.

degisken = np.repeat(['A', 'B', 'C', 'D'], [3,3,3,3], axis=0)
deger = np.random.random(12)
df_dict = {'degisken':degisken, 'deger':deger}
df = pd.DataFrame(df_dict)
df = df[['degisken', 'deger']]
df
degisken deger
0 A 0.711506
1 A 0.442056
2 A 0.304883
3 B 0.222076
4 B 0.552175
5 B 0.856324
6 C 0.521371
7 C 0.430587
8 C 0.171475
9 D 0.121785
10 D 0.985840
11 D 0.548228

Şimdi bu veri çerçevesini öyle değiştirelim ki tarih sütunu yine kalsın ama sütun isimleri A, B, C, D değişken isimleri olsun. Bunun için kullanabileceğimiz Pandas metodlarından birisi .pivot() metodudur. Excel’de pivot işlemi yapanlar bu metodun nasıl çalıştığını tahmin edebilirler.

df2 = df.pivot(columns='degisken', values='deger')
df2
degisken A B C D
0 0.711506 NaN NaN NaN
1 0.442056 NaN NaN NaN
2 0.304883 NaN NaN NaN
3 NaN 0.222076 NaN NaN
4 NaN 0.552175 NaN NaN
5 NaN 0.856324 NaN NaN
6 NaN NaN 0.521371 NaN
7 NaN NaN 0.430587 NaN
8 NaN NaN 0.171475 NaN
9 NaN NaN NaN 0.121785
10 NaN NaN NaN 0.985840
11 NaN NaN NaN 0.548228

Sütunları tekrar satır şeklinde yazmak için .melt() metodunu kullanabiliriz.

df3 = df2.melt(value_vars=['A', 'B', 'C', 'D'], value_name='deger').dropna()
df3
degisken deger
0 A 0.711506
1 A 0.442056
2 A 0.304883
15 B 0.222076
16 B 0.552175
17 B 0.856324
30 C 0.521371
31 C 0.430587
32 C 0.171475
45 D 0.121785
46 D 0.985840
47 D 0.548228

İki veri çerçevesini anahtar bir sütun kullanarak birleştirmek için .merge() fonksiyonu kullanılır. Örnek olarak aşağıdaki iki Pandas veri çerçevesini ele alalım.

df1 = pd.DataFrame({"X" : ["Ali", "Baran", "Mehmet"],
                    "Y1" : [97, 85, 76]})
df1
X Y1
0 Ali 97
1 Baran 85
2 Mehmet 76
df2 = pd.DataFrame({"X" : ["Ali", "Baran", "Umut"],
                    "Y1" : [75, 94, 96]})
df2
X Y1
0 Ali 75
1 Baran 94
2 Umut 96

İki veri çerçevesini birleştirirken kullanabileceğimiz yöntemler, left, right, inner ve outer yöntemleridir. Aşağıdaki örneklerde bu yöntemleri kullanırken önce df1 ve sonra df2 yazdığımıza dikkat edin. Bu, özellikle left ve right yöntemleri için önemlidir.

İlk yani left yönteminde, önce yazılan veri çerçevesi esas alınır. Argüman olarak birleştirilecek iki veri çerçevesinin isimleri, birleştirme yöntemi (how) ve veri çerçeveleri birleştirilirken hangi sütunun dikkate alınacağı (on) belirtilir.

df3 = pd.merge(df1, df2, how='left', on='X')
df3
X Y1_x Y1_y
0 Ali 97 75.0
1 Baran 85 94.0
2 Mehmet 76 NaN
df4 = pd.merge(df1, df2, how = 'right', on='X')
df4
X Y1_x Y1_y
0 Ali 97.0 75
1 Baran 85.0 94
2 Umut NaN 96

Left ve right yöntemlerinin çalışma mantığı benzerdir. Diğer yandan, how = 'inner' seçildiğinde birleştirilecek sütunun sadece her iki veri çerçevesinde de yer alan satırları yani kesişim kümesi dikkate alınır.

df5 = pd.merge(df1, df2, how='inner', on='X')
df5
X Y1_x Y1_y
0 Ali 97 75
1 Baran 85 94

Son olarak how='outer' seçtiğimizde de birleştirilecek sütundaki tüm satırlar yani bileşim kümesi dikkate alınır. Veri çerçevelerinden birinde olmayan değerler için NaN atanır.

df6 = pd.merge(df1, df2, how='outer', on='X')
df6
X Y1_x Y1_y
0 Ali 97.0 75.0
1 Baran 85.0 94.0
2 Mehmet 76.0 NaN
3 Umut NaN 96.0