800100715151 Astronomide Veritabanları

Ders - 05 Pandas Paketiyle Veri İşleme

Doç. Dr. Özgür Baştürk
Ankara Üniversitesi, Astronomi ve Uzay Bilimleri Bölümü
obasturk at ankara.edu.tr
http://ozgur.astrotux.org

Pandas Paketiyle Veriyi İşlenmek Üzere Hazırlama

Verileri pandas paketiyle işlemeye başlamadan önce, veriyi hazırlamak ve veri yapıları oluşturacak şekilde birleştirmek gerekir. Böylece daha sonra pandas kütüphanesi tarafından sağlanan araçlar ile manipüle edilebilirler. Veri hazırlama için farklı prosedürler aşağıda listelenmiştir.

  • Veriyi Yükleme
  • Veriyi Bir Araya Getirme
    • Bağlama (ing. merging)
    • Ucuca Ekleme (ing. concatenating)
    • Birleştirme (ing. combining)
  • Veri Yapısının Yeniden Şekillendirme (ing. pivoting)
  • Veri Çıkarma (ing. removing)

Veri yükleme için çeşitli yöntemlerle (sözlükler, listeler, numpy dizileri kullanarak) pandas serileri (pandas.Series) ve veriçerçeveleri (pandas.DataFrame) oluşturmayı Pandas'a Giriş dersimizde görmüştük. Ayrıca dosyalardan veriyi pandas.read_csv fonksiyonuyla okuyarak veriçerçevelerine yüklemeyi de örneklendirmiştik. Ancak, farklı kaynaklarda ve muhtemelen farklı formatlarda saklanan veriyi aldıktan ve bir veriçerçevesinde (DataFrame'de) birleştirmek gibi hazırlık işlemlerine de ihtiyaç duyulabilir. Örneğin bir ötegezegene ve barınak yıldızına ilişkin pek çok bilgi exoplanet.eu ya da NASA Exoplanet Archive gibi kataloglardan alınabiliyor olsa da özellikle yıldıza ilişkin bilgilerin daha güncel olarak bulunabileceği Gaia veritabanı ya da tayfsal parametrelerinin bulunduğu veritabanlarından alınarak yıldıza ilişkin bazı bilgilerin güncellenmesi ya da diğer bazılarının eklenmesi istenebilir. Bu bölümde verilerin bütünleşik bir veri yapısına dönüştürülmesi için yapılması gerekli işlemler tartışılacaktır.

pandas nesnelerinde tutulan veriler farklı şekillerde bir araya getirilebilirler:

  • Veriyi bağlama (ing. merging): pandas.merge() fonksiyonu, bir veya daha fazla anahtara bağlı olarak bir veritabanı çerçevesindeki (DataFrame'deki) satırları birbirine bağlar. SQL dilindeki $join$ metoduna benzer niteliktedir.

  • Veriyi ucuca ekleme (ing. concatenating): pandas.concat() fonksiyonu veri nesnelerini (Series ve DataFrame) bir eksen boyunca ucuca ekler.

  • Veriyi birleştirme (ing. combining): pandas.DataFrame.combine_first() fonksiyonu, başka bir yapıdan veri alarak veri yapısındaki eksik değerleri doldurmak ya da güncelleme için bağlamanızı sağlayan bir yöntemdir.

Verinin Birbirine Bağlanması: Merging

SQL'e aşinalığı olanlar için $JOIN$ işlemine karşılık gelen bu birleştirme işlemi, bir veriçerçevesindeki satırların bir veya daha fazla anahtar kullanarak bağlanmasını sağlar. pandas fonksiyonlarından merge() bu amaçla kullanılır. Örnek olarak, iki veriçerçevesi ($DataFrame$) tanımlayalım ve bunları birbirine pandas.merge() fonksiyonuyla bağlayalım.

In [1]:
import pandas as pd
yldz_mV = pd.DataFrame(\
            {'id':['Arcturus','Deneb','Betelgeuse','Spica','Rigel','Merak', 'Vega', 'Altair','Bellatrix'],\
             'mV': [-0.05,1.25,0.42,0.97,0.13,2.37,0.03,0.76,1.64]}) 
yldz_par = pd.DataFrame(\
            {'id':['Arcturus','Betelgeuse','Rigel','Deneb','Vega','Fomalhaut','Polaris'],\
             'par': [88.83,6.55,3.78,2.31,130.23,129.01,7.54]}) 
print("Gorsel Parlakliklar:")
print(yldz_mV)
print("Paralakslar:")
print(yldz_par)
print("Baglanmis Vericercevesi")
print(pd.merge(yldz_mV,yldz_par))
Gorsel Parlakliklar:
           id    mV
0    Arcturus -0.05
1       Deneb  1.25
2  Betelgeuse  0.42
3       Spica  0.97
4       Rigel  0.13
5       Merak  2.37
6        Vega  0.03
7      Altair  0.76
8   Bellatrix  1.64
Paralakslar:
           id     par
0    Arcturus   88.83
1  Betelgeuse    6.55
2       Rigel    3.78
3       Deneb    2.31
4        Vega  130.23
5   Fomalhaut  129.01
6     Polaris    7.54
Baglanmis Vericercevesi
           id    mV     par
0    Arcturus -0.05   88.83
1       Deneb  1.25    2.31
2  Betelgeuse  0.42    6.55
3       Rigel  0.13    3.78
4        Vega  0.03  130.23

Sonuçtan da görebileceğiniz gibi, döndürülen veriçerçevesi, iki veriçerçevesinde de bulunan her iki sütunun yalnızca ortak olan yıldız adlarındaki tüm satırlarını içermektedir. Bu durumda merge fonksiyonunu herhangi bir sütunu belirtmeden kullandık. Çoğu zaman entegrasyonu hangi sütun üzerinden yapacağımızı belirlememiz gerekir. Bunun nasıl yapılabileceğine ilişkin seçenekleri görmeden önce iki veriçerçevesinin birbirine ne şekillerde bağlanabileceğine bakalım.

Veri Çerçevelerini Bağlama Türleri

Bire bir Bağlama

Yukarıda bir örneğini gördüğümüz bu bağlama türü (ing. one-to-one join) en basiti olup bağlanmak istenen iki sütunun tek bir sütuna dönüştürülmesi sırasında doğrudan bire-bir eşleşebilen ve birbirini tekrar etmeyen (ing. duplicate) satırların her iki veriçerçevesinde de bulunan sütunlardaki bilgilerinin de eklenmesiyle yeni bir veriçerçevesiin oluşmasını sağlar.

Yukarıdaki örnek bu şekilde bir birleştirmedir. Her iki veriçerçevesinde de $id$ sütununda yer alan yıldız adları tektir ve birbirlerini karşılar. Daha sonra dıştan bağlama (outer join) işleminde göreceğiniz gibi her iki veriçerçevesindeki yıldızların da bulunduğu bir veriçerçevesi elde edilebilir. Ancak pandas.merge() fonksiyonunun doğal davranış şekli içten bağlama (inner join), bir başka deyişle kesişim almadır. Dolayısıyla yukarıdaki örnekte her iki veriçerçevesinde de bulunan yıldızlar yeni veriçerçevesine alınmıştır.

Bir başka örnek için bu kez her iki veriçerçevesinde de aynı satırların bulunduğu ve yine satırların birbirini tekrar etmediği bir durumu inceleyelim.

In [2]:
gezegen_yorunge = pd.DataFrame(\
            {'id':['Merkur','Venus','Dunya','Mars','Jupiter','Saturn', 'Uranus', 'Neptun'],\
             'e': [0.205, 0.007, 0.017, 0.094, 0.049, 0.057, 0.046, 0.011],\
             'i [derece]': [7.0, 3.4, 0.0, 1.9, 1.3, 2.5, 0.8, 1.8],\
             'P [gun]' : [88.0, 224.7, 365.2, 687.0, 4331, 10747, 30589, 59800],\
             'psi [derece]': [0.034, 177.4, 23.4, 25.2, 3.1, 26.7, 97.8, 28.3]})
gezegen_fiziksel = pd.DataFrame(\
            {'id':['Merkur','Venus','Dunya','Mars','Jupiter','Saturn', 'Uranus', 'Neptun'],\
             'Mp [x10^24 kg]': [0.330, 4.87, 5.97, 0.642, 1898, 568, 86.8, 102],\
             'Rp [km]': [2439.5, 6052., 6378., 3396., 71492., 60268., 25559., 24764.],\
             'rho [g/cm^3]': [5.427, 5.243, 5.514, 3.933, 1.326, 0.687, 1.271, 1.638],\
             'Prot [saat]': [1407.6, -5832.5, 23.9, 24.6, 9.9, 10.7, -17.2, 16.1]})
print("Baglanmis Vericercevesi")
print(pd.merge(gezegen_yorunge,gezegen_fiziksel))
Baglanmis Vericercevesi
   P [gun]      e  i [derece]       id  psi [derece]  Mp [x10^24 kg]  \
0     88.0  0.205         7.0   Merkur         0.034           0.330   
1    224.7  0.007         3.4    Venus       177.400           4.870   
2    365.2  0.017         0.0    Dunya        23.400           5.970   
3    687.0  0.094         1.9     Mars        25.200           0.642   
4   4331.0  0.049         1.3  Jupiter         3.100        1898.000   
5  10747.0  0.057         2.5   Saturn        26.700         568.000   
6  30589.0  0.046         0.8   Uranus        97.800          86.800   
7  59800.0  0.011         1.8   Neptun        28.300         102.000   

   Prot [saat]  Rp [km]  rho [g/cm^3]  
0       1407.6   2439.5         5.427  
1      -5832.5   6052.0         5.243  
2         23.9   6378.0         5.514  
3         24.6   3396.0         3.933  
4          9.9  71492.0         1.326  
5         10.7  60268.0         0.687  
6        -17.2  25559.0         1.271  
7         16.1  24764.0         1.638  

Çoktan bire Bağlama

Bağlanan sütunlardan birinin tekrarlanan (ing. duplicate) satırların bulunduğu bağlama türüdür (ing. many-to-one joins). Bu bağlama türüne bir örnek vermek üzere yeni bir veriçerçevesi tanımlayıp yukarıdaki çerçevelerle bağlayalım.

In [3]:
gezegen_fiziksel = pd.DataFrame(\
            {'id':['Merkur','Venus','Dunya','Mars','Jupiter','Saturn', 'Uranus', 'Neptun'],\
             'Mp [x10^24 kg]': [0.330, 4.87, 5.97, 0.642, 1898, 568, 86.8, 102],\
             'Rp [km]': [2439.5, 6052., 6378., 3396., 71492., 60268., 25559., 24764.],\
             'rho [g/cm^3]': [5.427, 5.243, 5.514, 3.933, 1.326, 0.687, 1.271, 1.638],\
             'Prot [saat]': [1407.6, -5832.5, 23.9, 24.6, 9.9, 10.7, -17.2, 16.1],\
             'tur': ['kayac', 'kayac', 'kayac', 'kayac', 'gaz', 'gaz', 'buz', 'buz']})
gezegen_tur = pd.DataFrame(\
            {'tur' : ['kayac','gaz','buz'],\
             'yer' : ['ic gezegen','dis gezegen','dis gezegen']})
print("Baglanmis Vericercevesi")
print(pd.merge(gezegen_fiziksel,gezegen_tur))
Baglanmis Vericercevesi
   Mp [x10^24 kg]  Prot [saat]  Rp [km]       id  rho [g/cm^3]    tur  \
0           0.330       1407.6   2439.5   Merkur         5.427  kayac   
1           4.870      -5832.5   6052.0    Venus         5.243  kayac   
2           5.970         23.9   6378.0    Dunya         5.514  kayac   
3           0.642         24.6   3396.0     Mars         3.933  kayac   
4        1898.000          9.9  71492.0  Jupiter         1.326    gaz   
5         568.000         10.7  60268.0   Saturn         0.687    gaz   
6          86.800        -17.2  25559.0   Uranus         1.271    buz   
7         102.000         16.1  24764.0   Neptun         1.638    buz   

           yer  
0   ic gezegen  
1   ic gezegen  
2   ic gezegen  
3   ic gezegen  
4  dis gezegen  
5  dis gezegen  
6  dis gezegen  
7  dis gezegen  

Çoktan çoka Bağlama

Bağlanan sütunlardan her ikisinde de tekrarlanan (ing. duplicate) satırların içerildiği bağlama türüdür (ing. many-to-many joins). Aşağıdaki örnekte daha önce oluşturduğumuz yldz_mV ve yldz_par_sptype veriçerçevelerine her iki tarafta da tekrarlanan satırlar içeren ve yıldızların tayf türünü gösteren $sptype$ sütunu eklenmiştir. Bu durumda yapılan birleştirme bir many-to-many join işlemidir.

In [4]:
yldz_mV_sptype = pd.DataFrame(\
            {'id':['Arcturus','Deneb','Betelgeuse','Spica','Rigel','Merak', 'Vega', 'Altair','Bellatrix'],\
             'sptype':['K1.5 III', 'A2 Ia', 'M1 Iab', 'B1 V', 'B8 Ia','A0 V', 'A0 V', 'A7 V', 'B1 V'],\
             'mV': [-0.05,1.25,0.42,0.97,0.13,2.37,0.03,0.76,1.64]})
yldz_par_sptype = pd.DataFrame(\
            {'id':['Arcturus','Betelgeuse','Rigel','Deneb','Vega','Fomalhaut','Polaris'],\
             'sptype':['K1.5 III', 'M1 Iab', 'B8 Ia', 'A2 Ia', 'A0 V', 'A0 V', 'F8 Ib'],\
             'par': [88.83,6.55,3.78,2.31,130.23,129.01,7.54]})
print("Gorsel Parlakliklar ve Tayf Turleri:")
print(yldz_mV_sptype)
print("Paralakslar ve Tayf Turleri:")
print(yldz_par_sptype)
print("ID Uzerinden Baglanmis Vericercevesi")
print(pd.merge(yldz_mV_sptype,yldz_par_sptype))
Gorsel Parlakliklar ve Tayf Turleri:
           id    mV    sptype
0    Arcturus -0.05  K1.5 III
1       Deneb  1.25     A2 Ia
2  Betelgeuse  0.42    M1 Iab
3       Spica  0.97      B1 V
4       Rigel  0.13     B8 Ia
5       Merak  2.37      A0 V
6        Vega  0.03      A0 V
7      Altair  0.76      A7 V
8   Bellatrix  1.64      B1 V
Paralakslar ve Tayf Turleri:
           id     par    sptype
0    Arcturus   88.83  K1.5 III
1  Betelgeuse    6.55    M1 Iab
2       Rigel    3.78     B8 Ia
3       Deneb    2.31     A2 Ia
4        Vega  130.23      A0 V
5   Fomalhaut  129.01      A0 V
6     Polaris    7.54     F8 Ib
ID Uzerinden Baglanmis Vericercevesi
           id    mV    sptype     par
0    Arcturus -0.05  K1.5 III   88.83
1       Deneb  1.25     A2 Ia    2.31
2  Betelgeuse  0.42    M1 Iab    6.55
3       Rigel  0.13     B8 Ia    3.78
4        Vega  0.03      A0 V  130.23

Farklı Sütunlar Üzerinden Bağlama

Görüldüğü gibi her iki veri çerçevesinde ortak olan yıldızlar (Arcturus, Deneb, Betelgeuse, Rigel ve Vega) olduğu için iki veriçerçevesi birbirine $ID$ sütunu üzerinden bağlandı. Ancak biz aynı olan tayf türlerinden bağlamak istiyor da olabliirdik. Bunu on parametresini istenen sütun adına ($sptype$) ayarlayarak yapabiliriz. Her ne kadar bu parametre herhangi bir sütuna verilmediğinde her iki veri setinde aynı olan ilk sütunlar bağlama için seçilse de hangi sütun üzerinden bağlama yapılmak istendiğini her zaman belirtmekte, bir başka deyişle her zaman on parametresini hangi sütun üzerinden bağlama yapılmak isteniyorsa ona ayarlamakta fayda vardır.

In [5]:
print("Tayf Turu Uzerinden Baglanmis Vericercevesi")
print(pd.merge(yldz_mV_sptype,yldz_par_sptype, on='sptype'))
Tayf Turu Uzerinden Baglanmis Vericercevesi
         id_x    mV    sptype        id_y     par
0    Arcturus -0.05  K1.5 III    Arcturus   88.83
1       Deneb  1.25     A2 Ia       Deneb    2.31
2  Betelgeuse  0.42    M1 Iab  Betelgeuse    6.55
3       Rigel  0.13     B8 Ia       Rigel    3.78
4       Merak  2.37      A0 V        Vega  130.23
5       Merak  2.37      A0 V   Fomalhaut  129.01
6        Vega  0.03      A0 V        Vega  130.23
7        Vega  0.03      A0 V   Fomalhaut  129.01

Görüldüğü gibi her iki verçevesi tayf türü üzerinden bağlandığı zaman yıldız adları farklı olabilmekte, bu durumda da merge işlemiyle yeni oluşturulan veriçerçevesinde iki ayrı id sütunu oluşmaktadır (id_x ve id_y). İstendiği takdirde sondaki "_x" ve "_y" yerine istenen başka bir metin de kullanılabilir, bunun için suffixes parametresi istenen metinlere ayarlanır. Özet olarak $merge$ işleminin sonucu hangi kriterle bağlama yapıldığına bağlı olarak değişebilmektedir.

Bununla birlikte, genellikle, bunun tersi bir problemle karşılaşılır: iki farklı veri setinde aynı bilgiyi içeren iki farklı sütun adının olması! Bu durumu gidermek için birinci ve ikinci veriçerçevesi için anahtar sütunu belirten left_on ve right_on seçeneklerinin kullanılması gerekir. Öncelikle yldz_mV_sptype veriçerçevesindeki sütun isimlerini değiştirelim.

In [6]:
yldz_mV_sptype.columns = ['yildiz','V','tayfturu']
print(yldz_mV_sptype)
       yildiz     V  tayfturu
0    Arcturus -0.05  K1.5 III
1       Deneb  1.25     A2 Ia
2  Betelgeuse  0.42    M1 Iab
3       Spica  0.97      B1 V
4       Rigel  0.13     B8 Ia
5       Merak  2.37      A0 V
6        Vega  0.03      A0 V
7      Altair  0.76      A7 V
8   Bellatrix  1.64      B1 V
In [7]:
print(pd.merge(yldz_mV_sptype, yldz_par_sptype, left_on='yildiz', right_on='id'))
       yildiz     V  tayfturu          id     par    sptype
0    Arcturus -0.05  K1.5 III    Arcturus   88.83  K1.5 III
1       Deneb  1.25     A2 Ia       Deneb    2.31     A2 Ia
2  Betelgeuse  0.42    M1 Iab  Betelgeuse    6.55    M1 Iab
3       Rigel  0.13     B8 Ia       Rigel    3.78     B8 Ia
4        Vega  0.03      A0 V        Vega  130.23      A0 V
In [8]:
print(pd.merge(yldz_mV_sptype, yldz_par_sptype, left_on='tayfturu', right_on='sptype'))
       yildiz     V  tayfturu          id     par    sptype
0    Arcturus -0.05  K1.5 III    Arcturus   88.83  K1.5 III
1       Deneb  1.25     A2 Ia       Deneb    2.31     A2 Ia
2  Betelgeuse  0.42    M1 Iab  Betelgeuse    6.55    M1 Iab
3       Rigel  0.13     B8 Ia       Rigel    3.78     B8 Ia
4       Merak  2.37      A0 V        Vega  130.23      A0 V
5       Merak  2.37      A0 V   Fomalhaut  129.01      A0 V
6        Vega  0.03      A0 V        Vega  130.23      A0 V
7        Vega  0.03      A0 V   Fomalhaut  129.01      A0 V

Varsayılan olarak, merge fonksiyonu bir SQL diliyle "inner join" işlemi gerçekleştirir; bir başka deyiişle, sonuçtaki kesişen satırlar alınır. Her iki veriçerçevesinde de bulunmayan satırlar ise kaybedilir. Diğer olası seçenekler "left join", "right join" ve "outer join" 'dir ve how parametresinin uygun şekilde ayarlanmasıyla kullanılabilir. Bu seçeneklerin nasıl çalıştğını örnekleyerek anlamak için öncelikle yldz_mV_sptype veriçerçevesinin başlıklarını eski haline dönüştürelim.

In [9]:
yldz_mV_sptype.columns = ['id','mV','sptype']
print(yldz_mV_sptype)
           id    mV    sptype
0    Arcturus -0.05  K1.5 III
1       Deneb  1.25     A2 Ia
2  Betelgeuse  0.42    M1 Iab
3       Spica  0.97      B1 V
4       Rigel  0.13     B8 Ia
5       Merak  2.37      A0 V
6        Vega  0.03      A0 V
7      Altair  0.76      A7 V
8   Bellatrix  1.64      B1 V
In [10]:
print(pd.merge(yldz_mV_sptype,yldz_par_sptype, on='id'))
           id    mV  sptype_x     par  sptype_y
0    Arcturus -0.05  K1.5 III   88.83  K1.5 III
1       Deneb  1.25     A2 Ia    2.31     A2 Ia
2  Betelgeuse  0.42    M1 Iab    6.55    M1 Iab
3       Rigel  0.13     B8 Ia    3.78     B8 Ia
4        Vega  0.03      A0 V  130.23      A0 V
In [11]:
print(pd.merge(yldz_mV_sptype,yldz_par_sptype, on='id', how="outer"))
            id    mV  sptype_x     par  sptype_y
0     Arcturus -0.05  K1.5 III   88.83  K1.5 III
1        Deneb  1.25     A2 Ia    2.31     A2 Ia
2   Betelgeuse  0.42    M1 Iab    6.55    M1 Iab
3        Spica  0.97      B1 V     NaN       NaN
4        Rigel  0.13     B8 Ia    3.78     B8 Ia
5        Merak  2.37      A0 V     NaN       NaN
6         Vega  0.03      A0 V  130.23      A0 V
7       Altair  0.76      A7 V     NaN       NaN
8    Bellatrix  1.64      B1 V     NaN       NaN
9    Fomalhaut   NaN       NaN  129.01      A0 V
10     Polaris   NaN       NaN    7.54     F8 Ib

Görüldüğü gibi dıştan bağlamada ($outer$) karşılıklı gelemeyen satırlar için sol ve sağ tarafta $NaN$ değerleri oluşmuştur. outer join, özünde bir bileşke işlemidir ve her iki veriçerçevesinde ortak olmayan satırlar da alınır. Bu sırasıyla $left$ ve $right$ seçeneklerinin nasıl çalıştığı konusunda fikir verir. Özünde bu her iki seçenek de birer outer join seçeneğidir.

In [12]:
print(pd.merge(yldz_mV_sptype,yldz_par_sptype, on='id', how="left"))
           id    mV  sptype_x     par  sptype_y
0    Arcturus -0.05  K1.5 III   88.83  K1.5 III
1       Deneb  1.25     A2 Ia    2.31     A2 Ia
2  Betelgeuse  0.42    M1 Iab    6.55    M1 Iab
3       Spica  0.97      B1 V     NaN       NaN
4       Rigel  0.13     B8 Ia    3.78     B8 Ia
5       Merak  2.37      A0 V     NaN       NaN
6        Vega  0.03      A0 V  130.23      A0 V
7      Altair  0.76      A7 V     NaN       NaN
8   Bellatrix  1.64      B1 V     NaN       NaN

Görüldüğü gibi sol taraftaki (fonksiyona ilk olarak verilen) yldz_mV_sptype veriçerçevesinde bulunan tüm yıldızların bilinen parametreleri entegre çerçevede bulunurken; sağdaki (fonksiyona ikinci olarak geçirilen) yldz_par_sptype veriçerçevesindeki sütunlarda bilgisi olan sadece Vega yıldızının paralaks ve tayf türü bilgileri geçirilmiştir. Sol dış birleştirme (left outer join) kullanıldığında oluşan yeni veriçerçevesinde sol taraftaki (fonksiyona ilk sırada sağlanan) tüm satırlar bulunurken, sağ taraftaki veriçerçevesinde sadece sol taraftaki veriçerçevesinde de bulunan satırlar alınır; eşleşmeyen satırlar ise alınmaz. Ayrıca sütunların sıralamasında da öncelik sol taraftaki veriçerçevesinin sütunlarındadır. Bu durum $right$ seçeneğinde tam ters şekilde çalışır.

In [13]:
print(pd.merge(yldz_mV_sptype,yldz_par_sptype, on='id', how="right"))
           id    mV  sptype_x     par  sptype_y
0    Arcturus -0.05  K1.5 III   88.83  K1.5 III
1       Deneb  1.25     A2 Ia    2.31     A2 Ia
2  Betelgeuse  0.42    M1 Iab    6.55    M1 Iab
3       Rigel  0.13     B8 Ia    3.78     B8 Ia
4        Vega  0.03      A0 V  130.23      A0 V
5   Fomalhaut   NaN       NaN  129.01      A0 V
6     Polaris   NaN       NaN    7.54     F8 Ib

Birden fazla anahtar (sütun adı) üzerinden entegrasyon amaçlandığında istenen sütunlar on parametresine bir liste dahilinde sağlanır.

In [14]:
print(pd.merge(yldz_mV_sptype,yldz_par_sptype, on=['id','sptype'], how="outer"))
            id    mV    sptype     par
0     Arcturus -0.05  K1.5 III   88.83
1        Deneb  1.25     A2 Ia    2.31
2   Betelgeuse  0.42    M1 Iab    6.55
3        Spica  0.97      B1 V     NaN
4        Rigel  0.13     B8 Ia    3.78
5        Merak  2.37      A0 V     NaN
6         Vega  0.03      A0 V  130.23
7       Altair  0.76      A7 V     NaN
8    Bellatrix  1.64      B1 V     NaN
9    Fomalhaut   NaN      A0 V  129.01
10     Polaris   NaN     F8 Ib    7.54

İndeks Üzerinden Bağlama İşlemleri

Bazı durumlarda, bir veriçerçevesinin sütunları anahtar olarak düşünülmek yerine, indeksleri veriçerçevelerini birbirine bağlamak için kullanılmak istenebilir. Hangi indekslerin dikkate alınacağını belirtmek için, left_index veya right_index seçeneklerini etkinleştirmek (True olarak ayarlamak) gerekir. Bu durumda aynı indekse sahip satırlar birleştirilirken, left_index soldaki (fonksiyona ilk geçirilen) veriçerçevesinin aynı sütunlarını $x$, sağdaki veriçerçevesinin sütunlarını $y$ ile isimlendirir. Örnekte sağdaki veriçerçevesinin (yldz_par_sptype) 0-6 indeksleri arasında kayıtlar olduğundan bağlanmış veriçerçevesinde de sadece bu indeksler vardır. Soldaki veriçerçevesinin (yldz_mV_sptype) 7 ve 8. indekslerindeki $Altair$ ve $Bellatrix$ bağlanmış veriçerçevesinde yoktur.

In [15]:
print(pd.merge(yldz_mV_sptype,yldz_par_sptype, how="inner", right_index=True, left_index=True))
         id_x    mV  sptype_x        id_y     par  sptype_y
0    Arcturus -0.05  K1.5 III    Arcturus   88.83  K1.5 III
1       Deneb  1.25     A2 Ia  Betelgeuse    6.55    M1 Iab
2  Betelgeuse  0.42    M1 Iab       Rigel    3.78     B8 Ia
3       Spica  0.97      B1 V       Deneb    2.31     A2 Ia
4       Rigel  0.13     B8 Ia        Vega  130.23      A0 V
5       Merak  2.37      A0 V   Fomalhaut  129.01      A0 V
6        Vega  0.03      A0 V     Polaris    7.54     F8 Ib

join Metodu

Ancak DataFrame nesneleri, indeksler üzerinden bağlamak istediğinizde çok daha işlevli olan join() fonskiyonuna sahiptir. Bu fonksiyonun kullanımını örneklemeden önce yine birinci veriçerçevesinin sütun başlıklarını farklı olacak şekilde ayarlayalım.

In [16]:
yldz_mV_sptype.columns = ['yldiz','V','tayfturu']

join arkaplanda merge fonksiyonunu kullanır ancak ondan farklı olarak veriçerçevesi ve seriler üzerinde tanımlanmış bir metot yapısındadır. Yukarıdaki gibi bir isim değişikliği yapılmaz ve her iki veriçerçevesinde de aynı sütunlar bulunursa $join$ işleminin yapıldığı tarafa göre sütunların yeniden isimlendirilmesi için lsuffix ve rsuffix parametreleri istenen metinlere ayarlanır.

In [17]:
yldz_mV_sptype.join(yldz_par_sptype, how="inner")
Out[17]:
yldiz V tayfturu id par sptype
0 Arcturus -0.05 K1.5 III Arcturus 88.83 K1.5 III
1 Deneb 1.25 A2 Ia Betelgeuse 6.55 M1 Iab
2 Betelgeuse 0.42 M1 Iab Rigel 3.78 B8 Ia
3 Spica 0.97 B1 V Deneb 2.31 A2 Ia
4 Rigel 0.13 B8 Ia Vega 130.23 A0 V
5 Merak 2.37 A0 V Fomalhaut 129.01 A0 V
6 Vega 0.03 A0 V Polaris 7.54 F8 Ib

Görüldüğü gibi $join$ ile yapılan bağlama indeksler üzerindendir. Bağlama yapılırken kesişim istendiğini belirtmek üzere how parametresi $inner$ seçeneğine ayarlanmıştır. Bu nedenle her iki veriçerçevesinde de bulunan $0,1,..,6$ numaralı indekslerdeki satırlar her iki veriçerçevesinden de alınarak bir bağlama işlemi yapılmıştır. Eğer bir önceki örnekte olduğu gibi tüm sütun isimleri farklı değil de bazıları aynı olsaydı, bağlama işlemi yaparken sol ve sağ taraftan gerekecek aynı isimli sütunları yeniden isimlendirmek için hangi metnin sırasıyla bu sütun isimlerinin sonuna ekleneceğini belirtmek için lsuffix ve rsuffix parametrelerini istenen metinlere ayarlamak gerekecekti.

In [18]:
yldz_mV_sptype.columns = ['id','mV','sptype']
yldz_mV_sptype.join(yldz_par_sptype, rsuffix="_sag", lsuffix="_sol", how="outer")
Out[18]:
id_sol mV sptype_sol id_sag par sptype_sag
0 Arcturus -0.05 K1.5 III Arcturus 88.83 K1.5 III
1 Deneb 1.25 A2 Ia Betelgeuse 6.55 M1 Iab
2 Betelgeuse 0.42 M1 Iab Rigel 3.78 B8 Ia
3 Spica 0.97 B1 V Deneb 2.31 A2 Ia
4 Rigel 0.13 B8 Ia Vega 130.23 A0 V
5 Merak 2.37 A0 V Fomalhaut 129.01 A0 V
6 Vega 0.03 A0 V Polaris 7.54 F8 Ib
7 Altair 0.76 A7 V NaN NaN NaN
8 Bellatrix 1.64 B1 V NaN NaN NaN

Ayrıca bu bağlamada dıştan bağlama ("outer join") (bileşke) işlemi uuygulandığından sol taraftaki veriçerçevesinin bütun satırları alınmış, sağ tarafta sol tarafla eşleşmeyen tüm satır değerleri $NaN$ olarak belirlenmiştir.

Veriçerçevesi ve Serileri Ucuca Ekleme: Concatenating

Seri halinde veri saklayan diğer tüm Python nesnelerinde olduğu gibi pandas veriçerçeveleri ve serileri de ucuca eklenebilir. Bunun için pandas.concatenate fonksiyonu kullanılır.

Önce serilerle örnekleyelim.

In [19]:
import numpy as  np
import pandas as pd
seri1 = pd.Series(np.random.rand(4), index=[1,2,3,4])
seri2 = pd.Series(np.random.rand(4), index=[5,6,7,8])
print(pd.concat([seri1,seri2]))
1    0.299884
2    0.393397
3    0.400547
4    0.149404
5    0.368428
6    0.943045
7    0.856207
8    0.114923
dtype: float64

concatenate fonksiyonu varsayılan olarak $axis = 0$ parametresiyle çalışır ve satır üzerinden ucuca ekleme yapar. axis parametresi $axis = 1$ ya da $axis = 'col'$ değerlerine ayarlanırsa ucuca ekleme sütun üzerinden yapılır. Sütunda ucuca ekleme sırasında oluşacak her yeni sütuna $0$'dan başlanarak $1, 2, ... $ numaralı indeksler atanır. Satırda aynı olmayan indekslere NaN değeri (ing. "not a number") verilir.

In [20]:
print(pd.concat([seri1,seri2],axis = 1))
          0         1
1  0.299884       NaN
2  0.393397       NaN
3  0.400547       NaN
4  0.149404       NaN
5       NaN  0.368428
6       NaN  0.943045
7       NaN  0.856207
8       NaN  0.114923

Varsayılan bu davranış şekli join parametresinin $inner$ değerine ayarlanmasıyla değiştirilebilir. Gerek SQL, gerekse de pandas 'ta inner join özünde bir kesişim işlemidir. Burada dikkat edilmesi gereken bu şekilde (içten) ucuca eklenecek iki serinin indekslerinin aynı olması gereğidir, aksi takdirde bir kesişim işlemi gerçekleşmez. Bu nedenle ilk örnek olarak iki aynı seriyi burada ucuca ekledik.

In [21]:
print(pd.concat([seri1,seri1],axis = 1, join='inner'))
          0         1
1  0.299884  0.299884
2  0.393397  0.393397
3  0.400547  0.400547
4  0.149404  0.149404

Ucuca eklenen seri ya da veriçerçevelerinin ucuca eklendikleri yerleri belirlemek üzere keys parametresi ile hiyerarşik bir indeksleme yapılabilir.

In [22]:
print(pd.concat([seri1,seri2], keys=[1,2]))
1  1    0.299884
   2    0.393397
   3    0.400547
   4    0.149404
2  5    0.368428
   6    0.943045
   7    0.856207
   8    0.114923
dtype: float64

Dıştan birleştirmelerde ($axis = 1$, "outer join") bu anahtarlar sütun ismi olur. Ucuca ekleme işlemlerinde varsayılan birleştirme (join) metodu "outer join" olduğu için bunu ayrıca how parametresi üzerinden belirlemek gerekmez.

In [23]:
print(pd.concat([seri1,seri2], axis = 1, keys=['A','B']))
          A         B
1  0.299884       NaN
2  0.393397       NaN
3  0.400547       NaN
4  0.149404       NaN
5       NaN  0.368428
6       NaN  0.943045
7       NaN  0.856207
8       NaN  0.114923

Veriçerçevelerinin Ucuca Eklenmesi

concatenate fonksiyonu seri nesnesi ($pd.Series$) üzerinde çalıştığı şekliyle veriçerçevesi ($pd.DataFrame$) nesneleri üzerinde de çalışır. Ancak veriçerçevesi en az iki boyutlu bir nesne olduğu için yapılabilecek işlemlerin karmaşıklığı da daha fazla olabilmektedir.

Yine klasik bir ucuca ekleme işleminin öncelikle varsayılan modda (satırda) nasıl yapıldığına bir örnekle bakalım.

In [24]:
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.random.rand(9).reshape(3,3), index=[1,2,3], columns=['A','B','C'])
df2 = pd.DataFrame(np.random.rand(9).reshape(3,3), index=[4,5,6], columns=['A','B','C'])
pd.concat([df1, df2], keys=[1,2])
Out[24]:
A B C
1 1 0.815066 0.574374 0.724567
2 0.044213 0.373693 0.424400
3 0.725209 0.764804 0.149464
2 4 0.437308 0.278557 0.642888
5 0.881661 0.453831 0.022568
6 0.484597 0.874412 0.127058

Görüldüğü gibi ucuca eklenen iki veri setinden birincisi ($df1$) ilk üç satırda yer alırken, keys parametresi ile bu verisetine ikinci bir indeks olarak $1$ değeri atanmıştır. İkinci veri seti birincinin ucuna satırda eklenince, indeksleri $4,5,6$ olduğundan bir sorun çıkmamış, son üç satırda indeksleriyle birlikte yer almıştır. keys parametresi ile bu verisetine de ikinci bir indeks olarak $2$ değeri atanmıştır.

Aynı veriçerçevelerini axis parametresini $1$ değerine ayarlayarak bu kez sütunda ucuca getirmeyi deneyelim.

In [25]:
 pd.concat([df1, df2], axis=1)
Out[25]:
A B C A B C
1 0.815066 0.574374 0.724567 NaN NaN NaN
2 0.044213 0.373693 0.424400 NaN NaN NaN
3 0.725209 0.764804 0.149464 NaN NaN NaN
4 NaN NaN NaN 0.437308 0.278557 0.642888
5 NaN NaN NaN 0.881661 0.453831 0.022568
6 NaN NaN NaN 0.484597 0.874412 0.127058

Görüldüğü gibi bu kez veriçerçeveleri sütunda ucuca getirilmiş, birinci veriçerçevesi $1,2,3$ indesklerine sahipken, ikinci veriçerçevesinin sahip olduğu $4,5,6$ indekslerine sahip olmadığı için bu indesklere NaN değeri gelmiş, tersi durum sütunda birincinin ucuna eklenen ikinci veriçerçevesi için de gerçekleşmiştir. Eğer bu iki veriçerçevesi tanımlanırken indeksleri de aynı tanımlanmış olsaydı nasıl bir durumla karşılaşacağımıza bakalım.

In [26]:
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.random.rand(9).reshape(3,3), index=[1,2,3], columns=['A','B','C'])
df2 = pd.DataFrame(np.random.rand(9).reshape(3,3), index=[1,2,3], columns=['A','B','C'])
pd.concat([df1, df2], keys=['X','Y'])
Out[26]:
A B C
X 1 0.953530 0.774270 0.343359
2 0.892603 0.268337 0.489064
3 0.208043 0.729170 0.129085
Y 1 0.407932 0.476524 0.967848
2 0.346985 0.133676 0.414156
3 0.770843 0.575258 0.810299

Satırda ucuca eklemede ortak sütun isimleri korunarak, ikinci veriçerçevesindeki indeksler aynı şekilde korunarak birincinin ucuna eklenmiş ve son üç satıra gelmiştir. Bu durum aynı indekslerden ikişer tane olmasına yol açmaktadır. Bu durumdan keys parametresi sırasıyla $X$ ve $Y$ değerlerine atanmak suretiyle yapılan çoklu indesklemeyle kaçınabileceği gibi bu durum hiç bir şekilde istenmiyorsa kodun hata vermesi de sağlanabilir. verify_integrity parametresi bu durumu denetler. Birden fazla satırın aynı indekse sahip olması her zaman istenen bir durum değildir; zira veriçerçevesinin bütünlüğünü ("integrity") bozar. Bu parametre $True$ değerine ayarlandığında ucuca ekleme işlemi aynı indeksten iki tane oluşmasıyla sonuçlanacaksa bu engellenir ve bir hata mesajı üretilebilir.

In [27]:
try:
    pd.concat([df1, df2], verify_integrity=True)
except ValueError as e:
    print("ValueError:", e)
ValueError: Indexes have overlapping values: Int64Index([1, 2, 3], dtype='int64')

Ancak bu durumun bir sorun oluşturmayacağı değerlendiriliyorsa aynı indekse sahip istendiği sayıda satır veriçerçevesinde bulunabilir. Bu durum veriçerçevelerinin bir esnekliği olsa da indeksleme, dilimleme ve çağırma işlemlerinde bariz sorunlara yol açacağı gerekçesiyle veriçerçevesinin bütünlüğünü bozar.

In [28]:
pd.concat([df1, df2])
Out[28]:
A B C
1 0.953530 0.774270 0.343359
2 0.892603 0.268337 0.489064
3 0.208043 0.729170 0.129085
1 0.407932 0.476524 0.967848
2 0.346985 0.133676 0.414156
3 0.770843 0.575258 0.810299

Aynı indeksten birden fazla oluşmasına engel olmak için bir başka çözüm indeksleri bütünüyle gözardı etmek ve indeks yönetimini pandas 'a bırakmaktır. Bunun için ignore_index parametresi $True$ değerine ayarlanır. Yukarıdaki örnekte olduğu gibi indekslerin önem taşımadığı ve zaten tamsayı olduğu durumlarda bu kolaylıkla uygulanabilir; ancak bu durumun sorun olarak değerlendirilebileceği indekslerin metinler olduğu örneklerle de karşılaşılabilir. Bir örnekle görelim:

In [29]:
pd.concat([df1, df2], ignore_index=True)
Out[29]:
A B C
0 0.953530 0.774270 0.343359
1 0.892603 0.268337 0.489064
2 0.208043 0.729170 0.129085
3 0.407932 0.476524 0.967848
4 0.346985 0.133676 0.414156
5 0.770843 0.575258 0.810299

Görüldüğü üzere her iki veriçerçevesinin indeksleri göz ardı edilmiş ve 0'dan başlanarak yeni bir indeksleme yapılmıştır.

Bu kez birleştirmeyi sütunda yapmayı deneyelim ve axis parametresini $'col'$ değerine ayarlayalım.

In [30]:
pd.concat([df1, df2], axis=1)
Out[30]:
A B C A B C
1 0.953530 0.774270 0.343359 0.407932 0.476524 0.967848
2 0.892603 0.268337 0.489064 0.346985 0.133676 0.414156
3 0.208043 0.729170 0.129085 0.770843 0.575258 0.810299

Görüldüğü üzere aynı isimde sütunların varlığı da bir problem olmamakta sütunlar yanyana eklenebilmektedir. Yine istenirse bu durumdan ignore_index ya da çoklu indeksleme (keys parametresi üzerinden) yoluyla kaçınılabileceği gibi kodun hata vermesi de sağlanabilir (verify_integrity = True).

In [31]:
pd.concat([df1, df2], axis=1, ignore_index=True)
Out[31]:
0 1 2 3 4 5
1 0.953530 0.774270 0.343359 0.407932 0.476524 0.967848
2 0.892603 0.268337 0.489064 0.346985 0.133676 0.414156
3 0.208043 0.729170 0.129085 0.770843 0.575258 0.810299

Kesişim ve Bileşke Yöntemleriyle Ucuca Ekleme

Veriçerçeve ve serilerinin bağlanmasında (ing. merging) gördüğünüz join metodu, aynı lineer cebir işlemlerine karşılık gelecek şekilde verilerin ucuca eklenmesinde de kullanılabilmektedir. Yukarıdaki örnekte olduğu gibi aynı ismi taşıyan sütunlardaki verilerin doğrudan alta alta yazılması (bileşkesinin alınması) yerine bir kesişiminin de alınması istenebilir. Bu durumun pandas.merge fonksiyonundaki join metodununun $inner$ (kesişim) ve $outer$ (bileşke) değerlerine atanmasıyla sağlandğını hatırlıyorsunuz. Ucucua eklemede de join metodu bu değerlere atanarak amaçlanan şekilde işlemin yapılması sağlanabilir. Birer örnekle görelim.

In [32]:
df1 = pd.DataFrame({'e':[0.205, 0.007, 0.017, 0.094],
                  'i': [7.0, 3.4, 0.0, 1.9],
                  'P': [88.0, 224.7, 365.2, 687.0],
                  'psi': [0.034, 177.4, 23.4, 25.2]},
                    index=['merkur','venus','dunya','mars'])
df2 = pd.DataFrame({'e':[0.049, 0.057, 0.046, 0.011],
                  'P': [4331, 10747, 30589, 59800],
                  'rho': [1.326, 0.687, 1.271, 1.638]},
                  index=['jupiter','saturn','uranus','neptun'])
print("Ic gezegenler:")
print(df1)
print("----------------")
print("Dıs gezegenler:")
print(df2)
print("---------------------")
print("pd.concat([df1,df2]")
print(pd.concat([df1,df2], sort=False))
Ic gezegenler:
            P      e    i      psi
merkur   88.0  0.205  7.0    0.034
venus   224.7  0.007  3.4  177.400
dunya   365.2  0.017  0.0   23.400
mars    687.0  0.094  1.9   25.200
----------------
Dıs gezegenler:
             P      e    rho
jupiter   4331  0.049  1.326
saturn   10747  0.057  0.687
uranus   30589  0.046  1.271
neptun   59800  0.011  1.638
---------------------
pd.concat([df1,df2]
               P      e    i      psi    rho
merkur      88.0  0.205  7.0    0.034    NaN
venus      224.7  0.007  3.4  177.400    NaN
dunya      365.2  0.017  0.0   23.400    NaN
mars       687.0  0.094  1.9   25.200    NaN
jupiter   4331.0  0.049  NaN      NaN  1.326
saturn   10747.0  0.057  NaN      NaN  0.687
uranus   30589.0  0.046  NaN      NaN  1.271
neptun   59800.0  0.011  NaN      NaN  1.638

Görüldüğü üzere aksi söylenmediği takdirde yapılan işlem satırları altalta dizerken tüm sütunları kullanmak (outer join) ve bir satırın herhangi bir sütun için verisi yoksa onu NaN değerine atamaktır. Eğer ucuca ekleme sırasında sadece ortak olan sütunlar kullanılmak isteniyorsa bu davranış join = 'inner' ile aşılabilir.

In [33]:
print("pd.concat([df1,df2], join='inner')")
print(pd.concat([df1,df2], join='inner', sort=False))
pd.concat([df1,df2], join='inner')
               P      e
merkur      88.0  0.205
venus      224.7  0.007
dunya      365.2  0.017
mars       687.0  0.094
jupiter   4331.0  0.049
saturn   10747.0  0.057
uranus   30589.0  0.046
neptun   59800.0  0.011

"left join" ve "right join" yöntemleri pandas.concatenate() fonksiyonu için tanımlı değildir. İstenen indeksler üzerinden ucuca ekleme yapmak da aşağıdaki şekilde pd.Index fonksiyonunu kullanarak, join_axes parametresi üzerinden mümkündür.

In [34]:
print(pd.concat([df1,df2], join_axes=[pd.Index(['P'])], sort=False))
               P
merkur      88.0
venus      224.7
dunya      365.2
mars       687.0
jupiter   4331.0
saturn   10747.0
uranus   30589.0
neptun   59800.0

Append Metodu

Her ne kadar efektif bir yöntem olmadığı için çok sık kullanılmasa da veri birleştirmek için pandas veriçerçevesi ve serileri üzerinde tanımlı bir de append metodu bulunmaktadır. Bu metod da üzerine uygulandığı veri nesnesini değiştirmek yerine yeni bir veri nesnesi oluşturur. Dolayısıyla sonuç saklanmak isteniyorsa istenen isimde yeni bir veri nesnesine atanmalıdır.

In [35]:
df1 = pd.DataFrame(np.random.rand(9).reshape(3,3), index=[1,2,3], columns=['A','B','C'])
df2 = pd.DataFrame(np.random.rand(9).reshape(3,3), index=[4,5,6], columns=['A','B','C'])
df3 = df1.append(df2)
print(df3)
          A         B         C
1  0.520891  0.303596  0.074619
2  0.954380  0.467875  0.843252
3  0.868796  0.283862  0.329853
4  0.672498  0.713082  0.218514
5  0.257479  0.601321  0.045207
6  0.853710  0.160591  0.169852

Veri Çerçevelerini Birleştirme: Combining

Bir veriçerçevesini (ya da seriyi) diğerinin ucuna eklerken çakışan indeksleri bir kenara bırakıp çakışmayanları ikinciyi birincinin sonuna eklemek üzere birinci nesnenin üzerinde combine_first() fonksiyonu tanımlanmıştır. Örneklerle nasıl çalıştığını anlayalım.

In [36]:
import pandas as pd
import numpy as np
seri1 = pd.Series(np.random.rand(5),index=[1,2,3,4,5])
print("Seri 1:")
print(seri1)
seri2 = pd.Series(np.random.rand(4),index=[2,4,5,6])
print("Seri 2:")
print(seri2)
print("seri1.combine_first(seri2)")
print(seri1.combine_first(seri2))
Seri 1:
1    0.929831
2    0.430427
3    0.631260
4    0.518944
5    0.045025
dtype: float64
Seri 2:
2    0.012890
4    0.366385
5    0.667483
6    0.414238
dtype: float64
seri1.combine_first(seri2)
1    0.929831
2    0.430427
3    0.631260
4    0.518944
5    0.045025
6    0.414238
dtype: float64

Görüldüğü gibi $1, 2, 3, 4, 5$ indeksleri birinci seriden ($seri1$), $6$ indeksi ise ikinci seriden ($seri2$) alınarak seriler kombine edilmiştir. Bunun tersine bakalım.

In [37]:
print("seri2.combine_first(seri1)")
print(seri2.combine_first(seri1))
seri2.combine_first(seri1)
1    0.929831
2    0.012890
3    0.631260
4    0.366385
5    0.667483
6    0.414238
dtype: float64

Görüldüğü üzere $2, 4, 5, 6$ indeksleri ikinci seriden alınırken, onda bulunmayan $1$ ve $3$ indeksleri ise birinci seriden alınmıştır. Serilerin belirli bölümleri de dilimleme yoluyla birleştirilebilir. Aşağıdaki örnekte ilk serinin son üç elemanına kadar olan bölümünün ikinci serinin son üç elemanına kadar olan bölümünü "overlap" etmesi, sonrasında serinin geri kalanının $seri2$ elemanları tarafından doldurulması istenmiştir.

In [38]:
print(seri1[:3].combine_first(seri2[:3]))
1    0.929831
2    0.430427
3    0.631260
4    0.366385
5    0.667483
dtype: float64

Sütun ve Satırlarda Döndürme: Pivoting

Veriyi analize hazırlarken sıklıkla başvurulan bir grup başka işlem de sütunlarla satırların yerlerini değiştirme (pivoting) işlemleridir. Bu işlemlerde sütunlar satırlara dönüştürülebildiği (stacking), satırlar da sütunlara dönüştürülebilir (unstacking). Konuyu bir örnekle anlamaya çalışalım.

In [39]:
import pandas as pd
import numpy as np
df = pd.DataFrame(np.array([65,45,70,80,74,90,44,37,62]).reshape(3,3),
                  index=['ogr1','ogr2','ogr3'],
                  columns=['odev','vize','final'])
print(df)
      odev  vize  final
ogr1    65    45     70
ogr2    80    74     90
ogr3    44    37     62

Veriçerçeveleri (DataFrame) üzerinde tanımlıstack() metodunu kullanarak, sütunları satırlar haline dönüştürmek suretiyle birden fazla indeksi bulunan bir Seri üretilmesi mümkündür.

In [40]:
df.stack()
Out[40]:
ogr1  odev     65
      vize     45
      final    70
ogr2  odev     80
      vize     74
      final    90
ogr3  odev     44
      vize     37
      final    62
dtype: int64

Bunun tersi işlem de tahmin edilebileceği gibi unstack() fonksiyonu ile yapılır. Örneğimizde bu işlem satırları toplayıp sütuna dönüştüreceğinden veriçerçevesinin eski halinde görüntülenmesini sağlayacaktır. Bir not olarak veriçerçevesinin değiştirilemez (immutable) bir nesne olduğunu hatırlatmakta fayda vardır. Dolayısıyla yukarıda yaptığımız işlem sadece bir görüntüleme işlemidir ve veriçerçevemiz dönüşmüş değildir. Bu noktaya dikkat çekerek tersi işlem olan unstack() işlemini örnekleyebilmek üzere stack() edilmiş veriçerçevisini bir başka veri çerçevesine aktaralım ve unstack() işlemini bunun sonrasında yapalım.

In [41]:
df2 = df.stack()
print("Sutundan satira donusum (stack):")
print(df2)
print("Satirdan sutunaa donusum (unstack):")
df3 = df2.unstack()
print(df3)
Sutundan satira donusum (stack):
ogr1  odev     65
      vize     45
      final    70
ogr2  odev     80
      vize     74
      final    90
ogr3  odev     44
      vize     37
      final    62
dtype: int64
Satirdan sutunaa donusum (unstack):
      odev  vize  final
ogr1    65    45     70
ogr2    80    74     90
ogr3    44    37     62

İstendiği takdirde unstack() fonksiyonunu tersi yönde uygulamak suretiyle orjinal veriye dönmek yerine sütun isimlerini satırlara, satırları da sütunlara veriyi doğru şekilde hizalayarak almak da tercih edilebilir. Örneğimizde bu ödev, vize ve final notlarını satırlara, öğrenci isimlerini de sütunlara almaya karşılık gelecektir.

In [42]:
df4 = df2.unstack(0)
print(df4)
       ogr1  ogr2  ogr3
odev     65    80    44
vize     45    74    37
final    70    90    62

Görüldüğü üzere bu tür işlemler, bir öğrenci için ağırlıklı ortalama almak ya da sınıf için belirli bir sınavın (örneğin vizenin) ortalamasını almak gibi işlemleri yaparken esneklik sağlar. Karşılaşılan probleme göre bu tür esneklikler sağlayan fonksiyonların farkında olunarak döngüler yerine bu fonskiyonların kullanılmlası önerilir.

Uzun ve Geniş Tablolar: Longframe ve Wideframe

Satır ve sütunların yerdeğiştirme işlemlerinden bir başkası özellikle benzer ya da aynı elemanların bulunduğu veriçerçevelerinde kullanışlı hale gelir. Okuması zor olan bir tablo türü yerine okuması ve diğer tablolarla yukarıda anlatılan yöntemlerle etkileşimi daha kolay olan bir tablo türüne geçmek tercih edilebillir.

In [43]:
tablo1 = pd.DataFrame({ 'iyon':['FeI','FeI','FeI',
                                 'NaI','NaI','NaI',
                                 'CaII','CaII','CaII'],
                       'liste':['NIST','VALD','Custom',
                               'NIST','VALD','Custom',
                               'NIST','VALD','Custom'],
                       'dalgaboyu': [5292.512, 5292.509,5292.513,
                                5682.256, 5682.261, 5682.258,
                                5167.615, 5167.618, 5167.620]})
print(tablo1)
   dalgaboyu  iyon   liste
0   5292.512   FeI    NIST
1   5292.509   FeI    VALD
2   5292.513   FeI  Custom
3   5682.256   NaI    NIST
4   5682.261   NaI    VALD
5   5682.258   NaI  Custom
6   5167.615  CaII    NIST
7   5167.618  CaII    VALD
8   5167.620  CaII  Custom

Farklı iyonların farklı çizgi listelerindeki dalgaboyu değerlerini veren bu tabloyu oluşturulduğu haliyle okumak kolay olmayabilir. Ancak birden fazla indeks kullanarak bu tabloyu geniş formda gösterdiğimizde okuması çok daha kolay gelebilir. Bunun için hangi özelliğe göre döndürme işlemi yapılmak isteniyorsa pivot() foksiyonuna sağlanmak suretiyle istenen döndürme işlemi yapılabilir.

In [44]:
tablo2 = tablo1.pivot('iyon','liste')
print(tablo2)
      dalgaboyu                    
liste    Custom      NIST      VALD
iyon                               
CaII   5167.620  5167.615  5167.618
FeI    5292.513  5292.512  5292.509
NaI    5682.258  5682.256  5682.261

Bu şekilde her bir iyonun hangi listede hangi dalgaboyunda bulunduğunu görmek çok daha kolaylaştı.

Veri çıkarma: Removing

Veri hazırlamanın son aşaması sütunların ve satırların gerektiğinde kaldırılmasıdır (removing. Buna ilişkin örnekler Ders 2: Pandas'a Giriş bölümünde görmüştük. Bununla birlikte, veriyi analize hazırlamak için gerekli işlemleri tamamlamak adına burada yeni örnekler verilecektir.

Aşağıda daha önce de tanımaladığımız 3 öğrencinin ödev, vize ve final notlarını gösterir veriçerçevesini tekrar tanımlayarak satır ve sütun çıkarma işlemlerini tekrarlamaya yönelik örnekler bulunmaktadır.

In [45]:
import pandas as pd
import numpy as np
df = pd.DataFrame(np.array([65,45,70,80,74,90,44,37,62]).reshape(3,3),
                  index=['ogr1','ogr2','ogr3'],
                  columns=['odev','vize','final'])
print(df)
      odev  vize  final
ogr1    65    45     70
ogr2    80    74     90
ogr3    44    37     62

Tıpkı numpy dizilerinde olduğu gibi del komutu veriçerçevelerinden de sütun silmek için kullanılabilir. del sadece veriçerçeveleri üzerinde tanımlı bir metod ya da fonksiyon olmadığı için kullanılır kullanılmaz etkili olur ve başka bir veriçerçevesine ya da değişkene kopyalama gib bir önlem alınmadıysa, geri alınması mümkün değildir.

In [46]:
del df['odev']
print(df)
      vize  final
ogr1    45     70
ogr2    74     90
ogr3    37     62

İstenmeyen bir satırı kaldırmak içinse drop() metodu kullanılır. drop() veriçerçeveleri üzerinde tanım bir metod olduğu ve veriçerçevesi ($DataFrame$) nesnesi de değiştirilemez (immutable) olduğu için doğrudan etkili olmaz. Eğer satır silme işlemi korunmak isteniyorsa işlem sonrası oluşan veriçerçevesi bir değişkene (eskisini kaybetmek koşuluyla istenirse aynı isimli) alınmalıdır.

In [47]:
df2 = df.drop('ogr3')
print("ogr3 'un olmadıgi liste:")
print(df2)
print("orjinal liste:")
print(df)
ogr3 'un olmadıgi liste:
      vize  final
ogr1    45     70
ogr2    74     90
orjinal liste:
      vize  final
ogr1    45     70
ogr2    74     90
ogr3    37     62

Tekrarlayan Satırların Atılması

Bir pandas serisi ya da veriçerçevesinde tekrar eden satırları (ya da bir sütun içindeki değerleri) yakalamak için duplicated() metodu kullanılır. Metod, tekrarlayan değerlerin arandığı yerdeki bu tür değerleri True diğerlerini ise False olarak işaretlemek suretiyle bir maske oluşturur. Tıpkı belirli koşullara dayalı olarak o koşulu sağlayan ve sağlamayan satırların filtrelenmesinde olduğu gibi, bu maske ilgilenilen veri setinin filtrelenmesinde kullanılabilir.

Örnek olarak çeşitli tekrar eden satır ve sütunlar barındıran çizgi listesi örneğimize geri dönelim. Bu veriçerçevesinde kendini tekrar eden bir satır olmadığı için tüm satırlar $False$ olarak işaretlenecektir.

In [48]:
import pandas as pd
cizgi_listesi = pd.DataFrame({ 'iyon':['FeI','FeI','FeI',
                                 'NaI','NaI','NaI',
                                 'CaII','CaII','CaII'],
                       'liste':['NIST','VALD','Custom',
                               'NIST','VALD','Custom',
                               'NIST','VALD','Custom'],
                       'dalgaboyu': [5292.512, 5292.509,5292.513,
                                5682.256, 5682.261, 5682.258,
                                5167.615, 5167.618, 5167.620]})
cizgi_listesi.duplicated()
Out[48]:
0    False
1    False
2    False
3    False
4    False
5    False
6    False
7    False
8    False
dtype: bool

Ancak istersek herhangi bir sütunda tekrar eden değerleri de duplicated() fonksiyonuyla bulabiliriz.

In [49]:
cizgi_listesi['iyon'].duplicated()
Out[49]:
0    False
1     True
2     True
3    False
4     True
5     True
6    False
7     True
8     True
Name: iyon, dtype: bool

Bu şekilde oluşturduğumuz maskeyi daha sonra veriçerçevesine vererek tekrarlayan satırları alabiliriz. Örneğimizde $iyon$ sütununda her bir iyon için verilen ilk satır $False$ değeri ile maskelenmiş iken, daha sonra bu iyona ilişkin diğer çizgi listesindeki değerlerin bulunduğu satırlar $True$ olarak işaretlenmiştir. Dolayısıyla bu maske cizgi_listesi veriçerçevesine sağlandığında sadece tekrar eden satırlar filtrelenip görüntülenir.

In [50]:
cizgi_listesi[cizgi_listesi['iyon'].duplicated()]
Out[50]:
dalgaboyu iyon liste
1 5292.509 FeI VALD
2 5292.513 FeI Custom
4 5682.261 NaI VALD
5 5682.258 NaI Custom
7 5167.618 CaII VALD
8 5167.620 CaII Custom

İstendiği takdirde bu tekrar satırları veriçerçevesinden çıkarılabilir. drop_duplicates() metodu bu amaçla kullanılır.

In [51]:
cizgi_listesi.drop_duplicates('iyon')
Out[51]:
dalgaboyu iyon liste
0 5292.512 FeI NIST
3 5682.256 NaI NIST
6 5167.615 CaII NIST

Veriçerçevesi üzerinde yaptığımız bu tür filtre işlemlerinin veriçerçevesini değiştirmediğini, işlemin sonucunu saklanması istendiğinde yeni bir veriçerçevesine alınması gerektiğini unutmayınız. Filtre işleminin sonucunun saklanması istendiğinde inplace parametresinin $False$ olan varsayılan değeri True ile değiştirilebilir. Bu durumda yapılan değişiklik kalıcı hale getirilmiş olur. drop_duplicates() tekrarlanan satırların her seferinde sadece ilkinin ($'first'$) korunması yerine sonuncusunun korunmasını ($'last'$) ya da tamamının ($False$) filtrelenmesine de keep parametresi üzerinden olanak sağlar.

In [52]:
cizgi_listesi.drop_duplicates('iyon', keep='last')
Out[52]:
dalgaboyu iyon liste
2 5292.513 FeI Custom
5 5682.258 NaI Custom
8 5167.620 CaII Custom

Gördüğünüz gibi sadece kullanıcının oluşturduğu "Custom" isimli çizgi listesindeki benzersiz (unique) satırlar kalmıştır; zira bu çizgi listesi son sıradadır.

Eşleştirme

Veriçerçeveleri üzerinde çalışırken zaman zaman belirli bir değere karşılık gelen tüm değerleri değiştirmek (ing. replace), değerleri eşleştirerek yeni bir sütun oluşturmak (ing. map) ya da indeks değerlerini istenen değerlerle değiştirmek (ing. rename) istenebilir. pandas tümü özünde "eşleştirme" (ing. mapping) olan bu işlemler için çeşitli fonksiyonlar sunar.

Eşleşenleri Değiştirme

Bir veriçerçevesindeki değerlerden bazılarını istenen başka bir değerle değiştirmek için veri nesneleri üzerinde tanımlı replace() metodu kullanılır. Değiştirilmek istenen değeri anahtar (key) yerine koymak istenen değeri değer (value kabul eden bir sözlük kullanmak bu tür değişimler için ideal bir çözümdür.

Aşağıdaki örnekle bu tür işlemlerin nasıl yapıldığını görelim. cizgi_listesi veriçerçevemizde kullanıcı tanımlı çizgi listesinde yer alan tüm çizgiler için $Custom$ yerine $User$ değerini koymak istiyor olalım ve bu değişimi kalıcı hale getirmek için inplace parametresini de $True$ değerine ayarlayalım.

In [53]:
import pandas as pd
cizgi_listesi = pd.DataFrame({ 'iyon':['FeI','FeI','FeI',
                                 'NaI','NaI','NaI',
                                 'CaII','CaII','CaII'],
                       'liste':['NIST','VALD','Custom',
                               'NIST','VALD','Custom',
                               'NIST','VALD','Custom'],
                       'dalgaboyu': [5292.512, 5292.509,5292.513,
                                5682.256, 5682.261, 5682.258,
                                5167.615, 5167.618, 5167.620]})
cizgi_listesi
Out[53]:
dalgaboyu iyon liste
0 5292.512 FeI NIST
1 5292.509 FeI VALD
2 5292.513 FeI Custom
3 5682.256 NaI NIST
4 5682.261 NaI VALD
5 5682.258 NaI Custom
6 5167.615 CaII NIST
7 5167.618 CaII VALD
8 5167.620 CaII Custom
In [54]:
listeadi = {'Custom':'User'}
cizgi_listesi.replace(listeadi, inplace=True)
cizgi_listesi
Out[54]:
dalgaboyu iyon liste
0 5292.512 FeI NIST
1 5292.509 FeI VALD
2 5292.513 FeI User
3 5682.256 NaI NIST
4 5682.261 NaI VALD
5 5682.258 NaI User
6 5167.615 CaII NIST
7 5167.618 CaII VALD
8 5167.620 CaII User

replace() fonksiyonu NaN gibi değerleri 0'la değiştirmek için sıklıkla kullanılır.

In [55]:
import numpy as np
seri = pd.Series([10,2.3,np.nan,-4,0.6,np.nan,7.5])
print(seri)
seri.replace(np.nan,0, inplace=True)
print("Degisiklik sonrasi:")
print(seri)
0    10.0
1     2.3
2     NaN
3    -4.0
4     0.6
5     NaN
6     7.5
dtype: float64
Degisiklik sonrasi:
0    10.0
1     2.3
2     0.0
3    -4.0
4     0.6
5     0.0
6     7.5
dtype: float64

Eşleştirme Yaparak Yeni Bir Sütun Ekleme

Bir sütunda verilen değerleri kullanarak yeni bir sütun eklemek de sıklıkla ihtiyaç duyulan bir yöntemdir. pandas veri nesneleri üzerinde tanımlı map() metodu kullanılarak bu amaca erişilebilir.

In [56]:
liste_referanslari = {'VALD':'Ryabchikova (1997)', 'NIST':'NIST ASD Team (2019)', 'User':'this study'}
cizgi_listesi['referanslar'] = cizgi_listesi['liste'].map(liste_referanslari)
cizgi_listesi
Out[56]:
dalgaboyu iyon liste referanslar
0 5292.512 FeI NIST NIST ASD Team (2019)
1 5292.509 FeI VALD Ryabchikova (1997)
2 5292.513 FeI User this study
3 5682.256 NaI NIST NIST ASD Team (2019)
4 5682.261 NaI VALD Ryabchikova (1997)
5 5682.258 NaI User this study
6 5167.615 CaII NIST NIST ASD Team (2019)
7 5167.618 CaII VALD Ryabchikova (1997)
8 5167.620 CaII User this study

Eşleştirme Yaparak İndeks İsimlerini Değiştirme

İndeks isimlerini yenileriyle değiştirmek istendiğinde de aynı yönteme başvurulabilir. Bu kez kullanılması gereken fonksiyon yine veri nesneleri üzerinde tanımlı rename() metodudur.

Yine cizgi_listesi veriçerçevemiz üzerinde bir örnekle görelim. Yeni indekslerimizi $iyon$ sütunundaki iyon isimleriyle $liste$ sütunundaki liste isimlerini "_" ile birleştirerek oluşturalım.

In [57]:
yeni_indeksler = {}
for i in range(len(cizgi_listesi.index)):
    yeni_indeksler[i] = cizgi_listesi.at[i,'iyon']+"_"+cizgi_listesi.at[i,'liste']
print(yeni_indeksler)
cizgi_listesi.rename(yeni_indeksler)
{0: 'FeI_NIST', 1: 'FeI_VALD', 2: 'FeI_User', 3: 'NaI_NIST', 4: 'NaI_VALD', 5: 'NaI_User', 6: 'CaII_NIST', 7: 'CaII_VALD', 8: 'CaII_User'}
Out[57]:
dalgaboyu iyon liste referanslar
FeI_NIST 5292.512 FeI NIST NIST ASD Team (2019)
FeI_VALD 5292.509 FeI VALD Ryabchikova (1997)
FeI_User 5292.513 FeI User this study
NaI_NIST 5682.256 NaI NIST NIST ASD Team (2019)
NaI_VALD 5682.261 NaI VALD Ryabchikova (1997)
NaI_User 5682.258 NaI User this study
CaII_NIST 5167.615 CaII NIST NIST ASD Team (2019)
CaII_VALD 5167.618 CaII VALD Ryabchikova (1997)
CaII_User 5167.620 CaII User this study

Sütun isimleri de aynı şekilde değiştirilebilir. Bu kez columns parametresi değişiklik yapılmak istenen sütun isimlerinin bulunduğu sözlüğe ayarlanır.

In [58]:
sutunlar = {'dalgaboyu':'wavelength',
            'iyon':'ion',
            'liste':'linelist',
            'referanslar':'reference'}
cizgi_listesi.rename(columns=sutunlar)
Out[58]:
wavelength ion linelist reference
0 5292.512 FeI NIST NIST ASD Team (2019)
1 5292.509 FeI VALD Ryabchikova (1997)
2 5292.513 FeI User this study
3 5682.256 NaI NIST NIST ASD Team (2019)
4 5682.261 NaI VALD Ryabchikova (1997)
5 5682.258 NaI User this study
6 5167.615 CaII NIST NIST ASD Team (2019)
7 5167.618 CaII VALD Ryabchikova (1997)
8 5167.620 CaII User this study

Yine aynı şekilde bu değişikliklerin kalıcı hale getirilmek istendiği durumlarda inplace parametresine başvurulur.

Veri Gruplama

Veri işlemenenin son aşamasını veri gruplama (ing. data aggregation) teknikleri oluşturur. Veri gruplama kavramıyla amaçlanan bir dizi veriden tek bir gruba dönüşüm yapmaktır. Örneğin $sum()$, $mean()$, $count()$, $min()$, $max()$ gibi numpy fonksiyonlarıyla yapılan da bir çeşit gruplamadır. Tüm bu fonksiyonlar bir grup veriyi tek bir sayıyla ifade eder. Sayısal bu tür gruplamaların yanı sıra doğal olarak, aynı türden olduğu düşünülen verilerin, tek bir grupla ifade edildiği kategorik gruplamalar da düşünülebilir.

Öncelikle pandas 'ta bu tür sayısal gruplamaların nasıl yapıldığını ötegezegenler veritabanı üzerinden örnekleyelim. Yine NASA Exoplanet Archive 'dan indirebileceğiniz keşifleri onaylanmış (ing. confirmed) ötegezegenler veritabanı üzerinde çalışalım.

In [59]:
import pandas as pd
import numpy as np
og = pd.read_csv("veri/planets_2020.04.16_03.10.01.csv", comment="#", skipinitialspace=True,
                index_col="pl_name")
og.head()
Out[59]:
pl_hostname pl_letter pl_discmethod pl_controvflag pl_pnum pl_orbper pl_orbpererr1 pl_orbpererr2 pl_orbperlim pl_orbsmax ... st_mass st_masserr1 st_masserr2 st_masslim st_rad st_raderr1 st_raderr2 st_radlim rowupdate pl_facility
pl_name
11 Com b 11 Com b Radial Velocity 0 1 326.03000 0.32 -0.32 0.0 1.29 ... 2.70 0.30 -0.30 0.0 19.00 2.00 -2.00 0.0 2014-05-14 Xinglong Station
11 UMi b 11 UMi b Radial Velocity 0 1 516.21997 3.20 -3.20 0.0 1.53 ... 2.78 0.69 -0.69 0.0 29.79 2.84 -2.84 0.0 2018-09-06 Thueringer Landessternwarte Tautenburg
14 And b 14 And b Radial Velocity 0 1 185.84000 0.23 -0.23 0.0 0.83 ... 2.20 0.10 -0.20 0.0 11.00 1.00 -1.00 0.0 2014-05-14 Okayama Astrophysical Observatory
14 Her b 14 Her b Radial Velocity 0 1 1773.40002 2.50 -2.50 0.0 2.93 ... 0.90 0.04 -0.04 0.0 0.93 0.01 -0.01 0.0 2018-09-06 W. M. Keck Observatory
16 Cyg B b 16 Cyg B b Radial Velocity 0 1 798.50000 1.00 -1.00 0.0 1.66 ... 1.08 0.04 -0.04 0.0 1.13 0.01 -0.01 0.0 2018-09-06 Multiple Observatories

5 rows × 71 columns

Öncelikle geçiş yapan ötegezegenlerin yörüngelerinin dış merkezliliklerinin ortalamasını bilmek istiyor olalım.

In [60]:
print("Otegezegenlerin ortalama dis merkezliligi: {:.2f} (+{:.2f} , {:.2f})".
      format(og['pl_orbeccen'].mean(),og['pl_orbeccenerr1'].mean(),og['pl_orbeccenerr2'].mean()))      
Otegezegenlerin ortalama dis merkezliligi: 0.16 (+0.07 , -0.05)

Bir başka örnek olarak istenen sütunların genel istatistikleri için değeri NaN olan satırları da eledikten sonra describe() metodunu kullanalım.

In [61]:
og[['pl_bmassj','pl_radj']].dropna().describe()
Out[61]:
pl_bmassj pl_radj
count 746.000000 746.000000
mean 1.531967 0.870898
std 3.247176 0.539388
min 0.000210 0.030000
25% 0.050475 0.272000
50% 0.581000 1.020000
75% 1.370000 1.290000
max 30.000000 3.000000

GroupBy Fonksiyonuyla Veri Gruplama

Gruplama işleme özünde üç aşamalı bir işlemdir. Öncelikle veri istenen sütundaki eş değerlere göre gruplara bölünür (ing. split), daha sonra istenen gruplama işlemi (toplama, sayma vs.) her bir gruba uygulanır (ing. apply) ve daha sonra gruplar birleştirilir (ing. combine). Programcılıkta da veritabanı yönetiminde de bir amaca ulaşmanın birden çok yöntemi vardır. Burada tarif edilen bu işlemler dizisine ayrı ayrı fonksiyonlar (koşula göle maskeleme, fonksiyona (sum, mean gibi) maskelenmiş veri nesnelerini gönderme, sonra birleştirme (merge, join ya da concat gibi fonksiyonlarla) fonksiyonlar kullanılarak gerçekleştirilebilir. Bu fonksiyonların bir sıra dahilinde planlanmasıyla da amaçlanan sonuca erişilebilir. İyi programcılık, programlama dilinin sağladığı olanakların farkında olup bunları gerektiği zaman gereğince kullanmaya dayanır. pandas veri nesneleri üzerinde tanımlı GroupBy metodu bütun bu adımları sırayla gerçekleştirebilir.

Örneğin ötegezegenler ($og$) veriçerçevemizi keşif yöntemine göre gruplayalım. Bunun için öncelikle veriçerçevesinin sütunlarının adlarını görüntüleyip, keşif yönteminin hangi sütun isminde yer aldığını bulmalıyız.

In [62]:
og.columns
Out[62]:
Index(['pl_hostname', 'pl_letter', 'pl_discmethod', 'pl_controvflag',
       'pl_pnum', 'pl_orbper', 'pl_orbpererr1', 'pl_orbpererr2',
       'pl_orbperlim', 'pl_orbsmax', 'pl_orbsmaxerr1', 'pl_orbsmaxerr2',
       'pl_orbsmaxlim', 'pl_orbeccen', 'pl_orbeccenerr1', 'pl_orbeccenerr2',
       'pl_orbeccenlim', 'pl_orbincl', 'pl_orbinclerr1', 'pl_orbinclerr2',
       'pl_orbincllim', 'pl_bmassj', 'pl_bmassjerr1', 'pl_bmassjerr2',
       'pl_bmassjlim', 'pl_bmassprov', 'pl_radj', 'pl_radjerr1', 'pl_radjerr2',
       'pl_radjlim', 'pl_dens', 'pl_denserr1', 'pl_denserr2', 'pl_denslim',
       'pl_ttvflag', 'pl_kepflag', 'pl_k2flag', 'pl_nnotes', 'ra_str', 'ra',
       'dec_str', 'dec', 'st_dist', 'st_disterr1', 'st_disterr2', 'st_distlim',
       'gaia_dist', 'gaia_disterr1', 'gaia_disterr2', 'gaia_distlim',
       'st_optmag', 'st_optmagerr', 'st_optmaglim', 'st_optband', 'gaia_gmag',
       'gaia_gmagerr', 'gaia_gmaglim', 'st_teff', 'st_tefferr1', 'st_tefferr2',
       'st_tefflim', 'st_mass', 'st_masserr1', 'st_masserr2', 'st_masslim',
       'st_rad', 'st_raderr1', 'st_raderr2', 'st_radlim', 'rowupdate',
       'pl_facility'],
      dtype='object')

Görüldüğü gibi keşif yöntemi pl_discmethod başlıklı sütunda yer almaktadır.

In [63]:
og.groupby("pl_discmethod")
Out[63]:
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x7f56d6498b70>

GroupBy metodunun sonucu bir DataFrameGroupBy nesnesidir. Bu nesne ilgilenilen veriçerçevesinin özel bir görüntüsüdür. Bu nesnenin üzerine istenen işlem uygulanarak (ing. apply) gruplama işleminin ikinci aşaması da gerçekleştirilebliir.

In [64]:
og.groupby("pl_discmethod").count()
Out[64]:
pl_hostname pl_letter pl_controvflag pl_pnum pl_orbper pl_orbpererr1 pl_orbpererr2 pl_orbperlim pl_orbsmax pl_orbsmaxerr1 ... st_mass st_masserr1 st_masserr2 st_masslim st_rad st_raderr1 st_raderr2 st_radlim rowupdate pl_facility
pl_discmethod
Astrometry 1 1 1 1 1 1 1 1 1 1 ... 1 1 1 1 0 0 0 0 1 1
Disk Kinematics 1 1 1 1 0 0 0 1 1 0 ... 1 0 0 1 1 0 0 1 1 1
Eclipse Timing Variations 16 16 16 16 16 15 15 16 14 14 ... 13 3 3 16 2 1 1 10 16 16
Imaging 50 50 50 50 10 6 6 17 48 28 ... 40 27 27 44 9 7 7 18 50 50
Microlensing 89 89 89 89 8 7 7 53 89 85 ... 89 88 87 89 0 0 0 45 89 89
Orbital Brightness Modulation 6 6 6 6 6 3 3 6 3 1 ... 3 3 3 3 3 3 3 3 6 6
Pulsar Timing 7 7 7 7 6 6 6 6 7 1 ... 7 0 0 7 1 0 0 6 7 7
Pulsation Timing Variations 2 2 2 2 2 2 2 2 1 1 ... 2 2 2 2 1 1 1 1 2 2
Radial Velocity 796 796 796 796 796 792 792 796 760 701 ... 796 613 608 796 606 522 517 683 796 796
Transit 3155 3155 3155 3155 3154 3049 3049 3153 1534 819 ... 2408 2388 2368 2408 3131 3103 3083 3153 3155 3155
Transit Timing Variations 21 21 21 21 21 9 9 21 8 6 ... 18 8 8 18 21 11 11 21 21 21

11 rows × 70 columns

Görüldüğü gibi aslında bir DataFrameGroupBy nesnesi de bir veriçerçevesi gibi kullanılabilir. Veriçerçevelerinden sütun seçilebildiği gibi bu nesneden de istenen sütunlar seçilebilir ve üzerinde istenen işlemler düşünülebliir. Örneğin daha önce elde ettiğimiz ötegezegenlerin ortalama dış merkezliliğini keşif yöntemine göre ayrı ayrı elde edebilir, karşılaştırmalar yapabilir ve bunlardan istatistiki çıkarımlara yönebiliriz.

In [65]:
og.groupby("pl_discmethod")['pl_orbeccen'].mean()
Out[65]:
pl_discmethod
Astrometry                       0.345000
Disk Kinematics                       NaN
Eclipse Timing Variations        0.152879
Imaging                          0.362000
Microlensing                     0.075000
Orbital Brightness Modulation         NaN
Pulsar Timing                    0.063260
Pulsation Timing Variations      0.075000
Radial Velocity                  0.219733
Transit                          0.086254
Transit Timing Variations        0.169728
Name: pl_orbeccen, dtype: float64

Görüldüğü üzere geçiş ($e_{ort} \sim 0.09$), pulsar zamanlaması ($e_{ort} \sim 0.06$), pulsasyon frekansı değişimi ($e_{ort} \sim 0.08$), kütleçekimsel mercek yöntemi ($e_{ort} \sim 0.08$) gibi yöntemlerde yörünge dış merkezliliği küçük gezegenler keşfedilirken; astrometri ($e_{ort} \sim 0.34$), doğrudan görüntüleme ($e_{ort} \sim 0.36$), dikine hız ($e_{ort} \sim 0.22$) gibi yöntemlerde ise ortalam yörünge dış merkezliliği daha büyük olan ötegezegenler keşfedilebilmektedir. Benzer şekilde yörünge dönemlerini de görmek isteyebiliriz. Bu kez grupladıktan sonra medyan alalım.

In [66]:
og.groupby("pl_discmethod")['pl_orbper'].median()
Out[66]:
pl_discmethod
Astrometry                         246.360000
Disk Kinematics                           NaN
Eclipse Timing Variations         3661.550000
Imaging                          40250.000000
Microlensing                      2665.500000
Orbital Brightness Modulation        0.334083
Pulsar Timing                       45.901950
Pulsation Timing Variations       1005.000000
Radial Velocity                    353.400000
Transit                              8.679444
Transit Timing Variations           15.943000
Name: pl_orbper, dtype: float64

Farklı tekniklerin farklı yörünge karakteristiklerine sahip ötegezegenleri keşfetmeye daha duyarlı oldukları, bu anlamda birbirlerinin keşif yanlılıklarını dengeleme kapasiteleri görülebilmektedir. Örneğin geçiş yöntemi yörünge dönemi küçük ($P_{orb,medyan} \sim 8.68$ gün) gezegenleri keşfetmeye yanlı iken doğrudan görüntüleme tekniğinin yanlılığı tam ters yöndedir ($P_{orb,medyan} \sim 40250$ gün). Her ne kadar doğrudan görüntüleme yöntemiyle daha az gezegen keşfediliyor olsa da geçiş yönteminin üzerinden çıkarımlar yapılmak istenen ötegezegenler popülasyonunu dengelemesi açısından önemi açıktır.

DataFrameGroupBy nesnesi tıpkı liste (list), demet değişken (tuple), sözlük (dictionary) ya da numpy dizileri (numpy.array) gibi üzerinde iteratif işlemler uygulanabilen bir nesnedir.

In [67]:
for (teknik, grup) in og.groupby('pl_discmethod'):
    print("{0:30s} shape={1}".format(teknik, grup.shape))
Astrometry                     shape=(1, 71)
Disk Kinematics                shape=(1, 71)
Eclipse Timing Variations      shape=(16, 71)
Imaging                        shape=(50, 71)
Microlensing                   shape=(89, 71)
Orbital Brightness Modulation  shape=(6, 71)
Pulsar Timing                  shape=(7, 71)
Pulsation Timing Variations    shape=(2, 71)
Radial Velocity                shape=(796, 71)
Transit                        shape=(3155, 71)
Transit Timing Variations      shape=(21, 71)

Görüldüğü üzere her bir teknikten kaçar gezegen keşfedildiği ve her gruba karşılık gelen teknikle keşfedilen gezegenlerin kaç sütunda (71) parametrelerinin bulunduğu tek tek ekrana getirilebilmektedir. Her bir tekniğin en başarıyla uygulandığı gözlemevi ve teleskoplara ilişkin istatistiki bilgi edinmek için aşağıdaki gibi bir gruplama ifadesi kullanılabilir.

In [68]:
og.groupby('pl_discmethod')['pl_facility'].describe()
Out[68]:
count unique top freq
pl_discmethod
Astrometry 1 1 Paranal Observatory 1
Disk Kinematics 1 1 Atacama Large Millimeter Array (ALMA) 1
Eclipse Timing Variations 16 7 Multiple Observatories 7
Imaging 50 14 Paranal Observatory 12
Microlensing 89 5 OGLE 51
Orbital Brightness Modulation 6 1 Kepler 6
Pulsar Timing 7 4 Arecibo Observatory 3
Pulsation Timing Variations 2 2 Multiple Observatories 1
Radial Velocity 796 27 La Silla Observatory 239
Transit 3155 27 Kepler 2321
Transit Timing Variations 21 3 Kepler 18

Her bir yöntemle keşif yapan gözlemevi ya da teleskopların sayısı, en çok keşif yapan gözlemevi / teleskoplar ve kaçar keşif yaptıkları gibi bilgilere describe() metoduyla ulaşılır. Bu istatistikler için kullınal gözlemevi / teleskop bilgisi içeren pl_facility sütunu sayısal olmayan kategorik veri içerdiği gerekçesiyle elde edilen istatistiksel parametreler de ($count$, $unique$, $top$, $freq$) kategorik veriler için geçerli istatistiki parametrelerdir. Daha önceki örneklerden sayısal veri içeren sütunlar söz konusu olduğunda bu istatistiklerin de farklı olduğunu bilyorsunuz. Aşağıdaki örnekte maksimum yörünge büyüklüğü Astronomi Birimi'nde farklı keşif tekniği grupları için farklı istatistikler dahilinde sunulmaktadır. unstack metodu her bir istatistiği bir diğerinden ayırarak keşif gruplarına birer ikincil indeks haline getirmektedir.

In [69]:
og.groupby('pl_discmethod')['pl_orbsmax'].describe().unstack()
Out[69]:
       pl_discmethod                
count  Astrometry                          1.000000
       Disk Kinematics                     1.000000
       Eclipse Timing Variations          14.000000
       Imaging                            48.000000
       Microlensing                       89.000000
       Orbital Brightness Modulation       3.000000
       Pulsar Timing                       7.000000
       Pulsation Timing Variations         1.000000
       Radial Velocity                   760.000000
       Transit                          1534.000000
       Transit Timing Variations           8.000000
mean   Astrometry                          0.360000
       Disk Kinematics                   130.000000
       Eclipse Timing Variations           4.061643
       Imaging                           429.656250
       Microlensing                        2.616000
       Orbital Brightness Modulation       0.013667
       Pulsar Timing                       4.897800
       Pulsation Timing Variations         1.700000
       Radial Velocity                     1.565985
       Transit                             0.121915
       Transit Timing Variations           1.161956
std    Astrometry                               NaN
       Disk Kinematics                          NaN
       Eclipse Timing Variations           2.116737
       Imaging                           761.401387
       Microlensing                        2.475035
       Orbital Brightness Modulation       0.011920
       Pulsar Timing                       8.819731
       Pulsation Timing Variations              NaN
                                           ...     
50%    Imaging                           156.500000
       Microlensing                        1.900000
       Orbital Brightness Modulation       0.007600
       Pulsar Timing                       0.360000
       Pulsation Timing Variations         1.700000
       Radial Velocity                     1.032000
       Transit                             0.075000
       Transit Timing Variations           0.309700
75%    Astrometry                          0.360000
       Disk Kinematics                   130.000000
       Eclipse Timing Variations           5.387500
       Imaging                           368.750000
       Microlensing                        3.450000
       Orbital Brightness Modulation       0.017500
       Pulsar Timing                       5.360000
       Pulsation Timing Variations         1.700000
       Radial Velocity                     2.102500
       Transit                             0.130950
       Transit Timing Variations           1.865000
max    Astrometry                          0.360000
       Disk Kinematics                   130.000000
       Eclipse Timing Variations           8.190000
       Imaging                          3500.000000
       Microlensing                       18.000000
       Orbital Brightness Modulation       0.027400
       Pulsar Timing                      23.000000
       Pulsation Timing Variations         1.700000
       Radial Velocity                    20.250000
       Transit                             4.500000
       Transit Timing Variations           4.200000
Length: 88, dtype: float64

Gördüğünüz tüm bu gruplama işlemlerinde sırasıyla gruplara ayırma (ing. split), işlem yapma (ing. apply) ve birleştirme (ing. combine) işlemleri DataFrameGroupBy nesnneleri üzerinde tanımlı groupby(9 fonksiyonuyla sırasıyla gerçekeştirilmektedir. DataFrameGroupBy nesnneleri üzerinde birleştirme (combine) işleminin yanı sıra filtreleme (filter()), dönüştürme (transform()) ve fonksiyon uygulama (apply()) işlemleri de tanımlıdır.

aggregatge Metodu

DataFrameGroupBy nesneleri üzerinde tanımlı bu işlemlerin nasıl çalıştığını anlamaya aggregate() metoduyla başlayalım. Bu metod istenen liste, metin (fonksiyon adı) ya da sözlük gibi bir yapıda gönderilen tüm fonksiyonları ilgili gruplara uygular.

NASA Exoplanet Archive ötegezegenler veritabanındaki ötegezegenleri keşif yöntemlerine göre gruplandırıp bu kez bazı fiziksel özelliklerinin (kütle, yarıçap, yoğunluk) minimum, medyan ve maksimum değerlerine bakalım. Fonksiyonun gruplandırma dahilinde birden fazla fonksiyonu, birden fazla sütuna aynı anda uygulayabildiğine ilişkin bu örnek aşağıdaki ifadeyle verilebilir.

In [70]:
import numpy as np
og.groupby('pl_discmethod')[['pl_bmassj','pl_radj','pl_dens']].aggregate(['min', np.median, max])
Out[70]:
pl_bmassj pl_radj pl_dens
min median max min median max min median max
pl_discmethod
Astrometry 28.50000 28.500000 28.50 NaN NaN NaN NaN NaN NaN
Disk Kinematics 2.50000 2.500000 2.50 NaN NaN NaN NaN NaN NaN
Eclipse Timing Variations 1.90000 6.175000 23.70 NaN NaN NaN NaN NaN NaN
Imaging 4.00000 12.784500 30.00 0.920 1.210 6.900 NaN NaN NaN
Microlensing 0.00450 0.620000 18.00 NaN NaN NaN NaN NaN NaN
Orbital Brightness Modulation 0.00140 0.002100 2.01 0.068 0.077 1.360 1.10 1.1000 1.10
Pulsar Timing 0.00006 0.013530 2.50 NaN NaN NaN 1.84 12.4200 23.00
Pulsation Timing Variations 3.20000 7.500000 11.80 NaN NaN NaN NaN NaN NaN
Radial Velocity 0.00236 1.256435 55.59 0.117 0.372 1.390 0.80 6.3400 6.95
Transit 0.00021 0.570000 27.23 0.030 0.208 2.085 0.03 0.9915 77.70
Transit Timing Variations 0.01100 0.173680 22.00 0.108 0.156 0.269 NaN NaN NaN

filter Metodu

DataFrameGroupBy nesneleri üzerinde tanımlı filter() metoduyla yapılan filtreleme işlemi, grup özelliklerine göre veri atmanıza olanak sağlar.

Aşağıdaki örneği inceleyelerek filter() metodunun nasıl çalıştığını anlamaya çalışalım.

In [71]:
import numpy as np
rng = np.random.RandomState(0)
df = pd.DataFrame({'kategori': ['A', 'B', 'C', 'A', 'B', 'C'],
                   'veri1': range(6),
                   'veri2': rng.randint(0, 10, 6)},
                  columns = ['kategori', 'veri1', 'veri2'])
print(df)
  kategori  veri1  veri2
0        A      0      5
1        B      1      0
2        C      2      3
3        A      3      3
4        B      4      7
5        C      5      9

Örnek olarak bu veri çerçevesinde olup ikinci veri setinde ($veri2$) standart sapması 4'ten büyük olan ölçümleri filtreleyebiliriz. Bunun için öncelikle bir filtre fonksiyonu tanımlayalım.

In [72]:
filtre_fonksiyonu = lambda x: x['veri2'].std() < 4
print(df.groupby('kategori').filter(filtre_fonksiyonu))
  kategori  veri1  veri2
0        A      0      5
3        A      3      3

Görüldüğü gibi standart sapması 4'ten küçük olan tek grup A kategorisindeki ölçümlerdir. Tüm standart sapma değerlerine bakarak bunu doğrulayabiliriz. Filtre fonksiyonu (filtering function) bir grubun (burada $A$, $B$ ve $C$ kategorileri) sağlaması beklenen şartı tanımladığı için mutlaka Boolean ($True$ ya da $False$) döndüren bir fonksiyon olmaldıır. filter fonksiyonu bu şartı sağlayan grupları alır, sağlamayanları eler.

In [73]:
print(df.groupby('kategori').std())
            veri1     veri2
kategori                   
A         2.12132  1.414214
B         2.12132  4.949747
C         2.12132  4.242641

Şimdi bu örnekle öğrendiklerimizi yine ötegezegenler ($og$) veriçerçevemize uygulayarak pekiştirelim. Veriçerçevimizi gruplama için yine pl_discmethod sütununda verilen keşif yöntemini kullanalım. Sonrasında filtrelemeyi keşfettiği gezegenlerin yörüngelerinin ortalama dış merkezliliği 0.25'ten büyük olan tekniklerle ($e_{ort} > 0.25$) keşfedilen gezegenleri göstermek üzere yapalım. Bu gezegenlerin de tüm sütunlardaki değerlerini değil sadece keşif yöntemi (pl_discmethod), yörünge dış merkezliliği (pl_orbeccen), yörünge dönemi (pl_orbper) ve yörünge büyüklüğünü (pl_orbsmax) veren sütunları gösterlim.

In [74]:
filtre_fonksiyonu = lambda x: x['pl_orbeccen'].mean() > 0.25
og.groupby('pl_discmethod').filter(filtre_fonksiyonu)[['pl_discmethod','pl_orbeccen','pl_orbper','pl_orbsmax']]
Out[74]:
pl_discmethod pl_orbeccen pl_orbper pl_orbsmax
pl_name
1RXS J160929.1-210524 b Imaging NaN NaN 330.00
2MASS J01225093-2439505 b Imaging NaN NaN 52.00
2MASS J02192210-3925225 b Imaging NaN NaN 156.00
2MASS J04414489+2301513 b Imaging NaN NaN 15.00
2MASS J12073346-3932539 b Imaging NaN NaN 46.00
2MASS J21402931+1625183 A b Imaging 0.260 7336.50 NaN
2MASS J22362452+4751425 b Imaging NaN NaN 230.00
51 Eri b Imaging 0.450 11688.00 12.00
AB Pic b Imaging NaN NaN 260.00
CFBDSIR J145829+101343 b Imaging NaN 10037.50 2.60
CHXR 73 b Imaging NaN NaN 210.00
CT Cha b Imaging NaN NaN 440.00
DENIS-P J082303.1-491201 b Astrometry 0.345 246.36 0.36
DH Tau b Imaging NaN NaN 330.00
FU Tau b Imaging NaN NaN 800.00
Fomalhaut b Imaging 0.870 555530.00 160.00
GJ 504 b Imaging NaN NaN 43.50
GQ Lup b Imaging NaN NaN 100.00
GSC 06214-00210 b Imaging NaN NaN 320.00
GU Psc b Imaging NaN NaN 2000.00
HD 100546 b Imaging NaN NaN 53.00
HD 106906 b Imaging NaN NaN 650.00
HD 203030 b Imaging NaN NaN 487.10
HD 95086 b Imaging NaN NaN 55.70
HIP 65426 b Imaging NaN NaN 92.00
HIP 78530 b Imaging NaN NaN 740.00
HIP 79098 AB b Imaging NaN NaN 345.00
HN Peg b Imaging NaN NaN 773.00
HR 2562 b Imaging NaN NaN 20.30
HR 8799 b Imaging NaN 170000.00 68.00
HR 8799 c Imaging NaN 69000.00 38.00
HR 8799 d Imaging NaN 37000.00 24.00
HR 8799 e Imaging 0.150 NaN 16.40
LkCa 15 b Imaging NaN NaN 14.70
LkCa 15 c Imaging NaN NaN 18.60
Oph 11 b Imaging NaN 7300000.00 243.00
PDS 70 b Imaging NaN 43500.00 22.00
PDS 70 c Imaging NaN NaN 34.50
ROXs 12 b Imaging NaN NaN 210.00
ROXs 42 B b Imaging NaN NaN 157.00
Ross 458 c Imaging NaN NaN 1168.00
SR 12 AB c Imaging NaN NaN NaN
TYC 8998-760-1 b Imaging NaN NaN 162.00
USco CTIO 108 b Imaging NaN NaN 670.00
USco1556 b Imaging NaN NaN 3500.00
USco1621 b Imaging NaN NaN 2880.00
VHS J125601.92-125723.9 b Imaging NaN NaN 102.00
WD 0806-661 b Imaging NaN NaN 2500.00
WISEP J121756.91+162640.2 A b Imaging NaN NaN 8.00
bet Pic b Imaging 0.080 7665.00 9.10
kap And b Imaging NaN NaN 55.00

Görüldüğü gibi $e_{ort} > 0.25$ koşulunu sağlayan iki yöntem doğrudan görüntüleme (ing. Imaging) ve astrometri yöntemleridir. Ekrana bu yöntemlerle keşfedilen gezegenlerin istenen parametreleri, DataFrameGroupBy nesnesi üzerinde tanımlı filter() fonksiyonunun sonucu bir veriçerçevesi türünde nesne olduğu için getirilebilmiştir.

Sonuç olarak filter() fonksiyonu uygulandığı veriçerçevesinin bir şekilde sınırlandırılmış (kısaltılmıış) bir versiyonunu döndürür.

trasformation Metodu

Filtreleme verilen veri gruplarını bir filtre fonksiyonuna tabi tutup, bu filtre fonksiyonuyla belirlenen şartı sağlayanlarını alır ve gerisini filtreleyip elerken, transformation() metodu grubu ilgili fonksiyon çerçevesinde dönüştürür.

Örneğin bir veri setindeki her bir veriden o verinin dahil olduğu grubun (örneğin $A$ kategorisinin) ortalamasını çıkararak ilgili sütun ve satıra yazarak veriçerçevesini dönüştürmek (transform etmek) için aşağıdaki gibi bir ifade kullanılabilir. Yine bu işlemin sonucunun yeni bir veriçerçevesi tanımladığını ve saklanmak isteniyorsa bu veriçerçevesine bir isim verilmesi gerektiğini unutmayınız.

In [75]:
import numpy as np
rng = np.random.RandomState(0)
df = pd.DataFrame({'kategori': ['A', 'B', 'C', 'A', 'B', 'C'],
                   'veri1': range(6),
                   'veri2': rng.randint(0, 10, 6)},
                  columns = ['kategori', 'veri1', 'veri2'])
print(df)
  kategori  veri1  veri2
0        A      0      5
1        B      1      0
2        C      2      3
3        A      3      3
4        B      4      7
5        C      5      9
In [76]:
donusum_fonksiyonu = lambda x: x - x.mean()
df.groupby('kategori').transform(donusum_fonksiyonu)
Out[76]:
veri1 veri2
0 -1.5 1.0
1 -1.5 -3.5
2 -1.5 -3.0
3 1.5 -1.0
4 1.5 3.5
5 1.5 3.0

Yöntemi öntegezegen veritabanı üzerinde, her bir yöntemin keşfettiği gezegenlerin parametrelerini o yöntemle bu parametre için keşfedilen gezegenlerin ortalama değerine normalize ederek (bölerek) vermek için kullanalım ve sonucu yörünge dönemi (pl_orbper) için görüntüleyelim.

In [77]:
def donusum_fonksiyonu(x):
    return x / x.mean()
og.groupby('pl_discmethod').transform(donusum_fonksiyonu)['pl_orbper']
Out[77]:
pl_name
11 Com b                        0.325144
11 UMi b                        0.514818
14 And b                        0.185335
14 Her b                        1.768582
16 Cyg B b                      0.796331
18 Del b                        0.990602
1RXS J160929.1-210524 b              NaN
24 Boo b                        0.030268
24 Sex b                        0.451570
24 Sex c                        0.880601
2MASS J01225093-2439505 b            NaN
2MASS J02192210-3925225 b            NaN
2MASS J04414489+2301513 b            NaN
2MASS J12073346-3932539 b            NaN
2MASS J19383260+4603591 b       0.105868
2MASS J21402931+1625183 A b     0.008934
2MASS J22362452+4751425 b            NaN
30 Ari B b                      0.334190
4 UMa b                         0.268568
42 Dra b                        0.477798
47 UMa b                        1.075072
47 UMa c                        2.384505
47 UMa d                       13.963962
51 Eri b                        0.014233
51 Peg b                        0.004219
55 Cnc b                        0.014612
55 Cnc c                        0.044297
55 Cnc d                        4.811892
55 Cnc e                        0.000735
55 Cnc f                        0.261288
                                 ...    
eps Eri b                       2.495203
eps Ind A b                    16.465149
eps Tau b                       0.593284
gam 1 Leo b                     0.427336
gam Cep b                       0.900846
gam Lib b                       0.414072
gam Lib c                       0.961980
iot Dra b                       0.509710
kap And b                            NaN
kap CrB b                       1.281509
mu Leo b                        0.356828
nu Oph b                        0.528770
nu Oph c                        3.176178
ome Ser b                       0.276267
omi CrB b                       0.187320
omi UMa b                       1.625572
pi Men c                        0.236802
psi 1 Dra B b                   3.108532
rho CrB b                       0.039738
rho CrB c                       0.102261
tau Boo b                       0.003303
tau Cet e                       0.162428
tau Cet f                       0.634402
tau Cet g                       0.019946
tau Cet h                       0.049276
tau Gem b                       0.304670
ups And b                       0.004604
ups And c                       0.240603
ups And d                       1.272992
xi Aql b                        0.136379
Name: pl_orbper, Length: 4144, dtype: float64

apply Metodu

apply() metodu herhangi bir fonksiyonun bir DataFrameGroupBy nesnesine uygulanmasını sağlar. Her bir grubun birinci veri setindeki ölçümlerini ($veri1$) ikinci veri setindeki ölçümlerin toplamına ($veri2$) normalize etmek istiyor olalım. Aşağıdaki $normalizasyon$ fonksiyonunun df.groupby('kategori') ifadesi ile elde edilen DataFrameGroupBy nesnesine uygulanması sonucu $veri1$ sütunundaki veri seti her bir grup için o grubun $veri2$ veri setindeki ölçümlerin toplamına bölünmesi (normalize edilmesi) sağlanmıştır.

In [78]:
def normalizasyon(x):
    x['veri1'] /= x['veri2'].sum()
    return(x)
print(df.groupby('kategori').apply(normalizasyon))
  kategori     veri1  veri2
0        A  0.000000      5
1        B  0.142857      0
2        C  0.166667      3
3        A  0.375000      3
4        B  0.571429      7
5        C  0.416667      9

apply() fonksiyonu oldukça kullanışlı bir fonksiyon olup, herhangi bir fonksiyonun sadece DataFrameGroupBy nesnelerine değil, istenen tüm veriçerçevelerine uygulanmasını sağlar. Sonuç istenirse bir pandas veri nesnesi istenirse de skaler bir değer olabilir.

Bir önceki bölümde transformation() metoduyla bütun sütunlara uyguladığımız normalizasyonu, sadece yörünge dönemleri bilinen tüm gezegenlerin yörünge dönemlerinin, keşfedildikleri yöntemle keşfedilen tüm gezegenlerin yörünge dönemi ortalamasına oranını hesaplamak üzere kullanabiliriz.

In [79]:
def normalizedonem(x):
    return x['pl_orbper'] / x['pl_orbper'].mean()
og.groupby('pl_discmethod').apply(normalizedonem)
Out[79]:
pl_discmethod              pl_name                    
Astrometry                 DENIS-P J082303.1-491201 b      1.000000
Disk Kinematics            HD 97048 b                           NaN
Eclipse Timing Variations  2MASS J19383260+4603591 b       0.105868
                           DE CVn b                        1.042930
                           DP Leo b                        2.600898
                           HU Aqr AB b                     0.608234
                           HU Aqr AB c                     1.111617
                           HW Vir b                        1.180838
                           KIC 5095269 b                   0.060490
                           MXB 1658-298 b                  0.193413
                           NN Ser c                        1.418418
                           NN Ser d                        0.733825
                           NSVS 14256825 b                 0.820734
                           NY Vir b                        0.804192
                           NY Vir c                        2.239266
                           RR Cae b                        1.105382
                           UZ For b                        1.486228
                           UZ For c                        0.487668
Imaging                    1RXS J160929.1-210524 b              NaN
                           2MASS J01225093-2439505 b            NaN
                           2MASS J02192210-3925225 b            NaN
                           2MASS J04414489+2301513 b            NaN
                           2MASS J12073346-3932539 b            NaN
                           2MASS J21402931+1625183 A b     0.008934
                           2MASS J22362452+4751425 b            NaN
                           51 Eri b                        0.014233
                           AB Pic b                             NaN
                           CFBDSIR J145829+101343 b        0.012223
                           CHXR 73 b                            NaN
                           CT Cha b                             NaN
                                                            ...    
Transit                    Wolf 503 b                      0.226725
                           XO-1 b                          0.148911
                           XO-2 N b                        0.098827
                           XO-3 b                          0.120577
                           XO-4 b                          0.155846
                           XO-5 b                          0.158214
                           XO-6 b                          0.142242
                           XO-7 b                          0.108207
                           pi Men c                        0.236802
Transit Timing Variations  KOI-142 c                       0.102230
                           Kepler-122 f                    0.257495
                           Kepler-19 c                     0.131479
                           Kepler-338 e                    0.042746
                           Kepler-37 e                     0.234284
                           Kepler-411 e                    0.144195
                           Kepler-414 b                    0.021508
                           Kepler-414 c                    0.032816
                           Kepler-415 b                    0.019110
                           Kepler-415 c                    0.039850
                           Kepler-416 b                    0.028917
                           Kepler-416 c                    0.055871
                           Kepler-417 b                    0.056429
                           Kepler-417 c                    0.072959
                           Kepler-419 c                    3.091099
                           Kepler-448 c                   11.440548
                           Kepler-46 c                     0.260895
                           Kepler-539 c                    4.576219
                           Kepler-82 f                     0.346566
                           WASP-126 c                      0.034917
                           WASP-18 c                       0.009865
Name: pl_orbper, Length: 4144, dtype: float64

Kaynaklar