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
Ötegezegenler ve onların barınak yıldızlarına ilişkin pek çok parametrenin bulunduğu ötegezegen veritabanları arasında öne çıkan iki tanesi NASA Exoplanet Archive tarafından sağlanan veritabanı ile Cenevre Üniversitesi'nde tutulan exoplanet.eu veritabanıdır. İki veritabanında da benzer veriler yer aldığı gibi bir veritabanında olup diğerinde olmayan (barınak yıldız metal bolluğu gibi) ya da farklı kaynaklardan alınan veriler de bulunmaktadır. Bu iki veritabanını pandas
paketinin sağladığı olanaklarla çeşitli şekillerde birleştirerek sorgulayabiliriz.
Öncelikle her iki tabloyu astroquery
fonksiyonlarıyla sorgulayarak birer pandas
veriçerçevesine alalım. NASA Exoplanet Archive ötegezegenler ve gözlemleriyle ilgili pek çok tablo ve veri sunmaktadır. Bu veri tablolarından ikisi tüm ötegezegen, sistem ve barınak yıldız parametrelerinin farklı literatür kaynaklarından alınarak listelendiği Planetary Systems, diğeri bu parametrelerin farklı kaynaklardan derlenerek her bir gezegen için tek bir satır halinde sunulduğu Planetary Systems Composite Data tablosudur. Bu tablolara astroquery
modüllerinden NasaExoplanetArchive
NASA Exoplanet Archive veritabanını kritere göre tarayan fonksiyonu query_criteria
ile erişilebilir. Tüm literatür kaynaklarından alınan verilerin sunulduğu tablo ps
, parametrelerin derlenerek tek bir satıra dönüştürüldüğü tablo pscommpars
adıyla table
anahtarına sağlanmalı; tüm tablo çekilmek isteniyorsa, SQL sorgu nesnesinin sağlandığı select
parametresi " * " değerine atanmalıdır.
#from astroquery.ipac.nexsci.nasa_exoplanet_archive import NasaExoplanetArchive
import pandas as pd
#nasatablo = NasaExoplanetArchive.query_criteria(table="pscomppars", select="*")
#nasatablo.columns
#nasaexo = nasatablo.to_pandas()
exoplanet.eu veritabanına bağlanmak için bir astroquery
servisi tanımlanmadığından bu veritabanını sorgulayabilmek ya da çevrimiçi çekip kullanabilmek için ya requests
modülü fonksiyonlarını kullanmak ya da sitenilen formatta (Virtual Observatory --VO-- tablosu, csv, dat) indirip uygun pandas
fonksiyonuyla açmak gerekecektir. DACE platformunun bir parçası olan katalog, Sanal Gözlemevi standardı Tablo Erişim Protokolü (Table Access Protocol, TAP) fonksiyonları ile sorgulamaya açıktır ve pyvo modülü fonksiyonlarıyla sorgulanabilir ve tıpkı NASA Exoplanet Archive veritabanı gibi kullanılabilir.
nasaexo = pd.read_csv('veri/PSCompPars_2024.04.02_02.08.30.csv',
comment="#", skipinitialspace=True)
exoeu = pd.read_csv('veri/exoplanet.eu_catalog_20240402.csv',
skipinitialspace=True)
print("NASA Exooplanet Archive veritabani sutunlari")
print("-"*45)
print(nasaexo.columns)
print("x"*80)
print("exoplanet.eu veritabani sutunlari")
print("-"*45)
print(exoeu.columns)
Görüldüğü üzere farklı veritabanlarında aynı sütunlar farklı isimlerle bulunabilmektedir. Örneğin NASA Exoplanet Archive veritabanında pl_name sütununda yer alan gezegen isimleri # name sütununda yer almaktadır.
NASA Exoplanet Archive'dan bu uygulama için indirilen veritabanı gezegen doğaları başka gözlemlerle (örneğin hem geçiş, hem dikine hız) kesinleştirilmiş ve bu nedenle "onaylanmış" (ing. confirmed) ötegezegenleri içermektedir. exoplanet.eu veritabanında ise bu şekilde kesinleştirilmemiş gezegenler de bulunmaktadır. Her iki veritabanını bağlamak üzere gezegen isimlerini kullanınız ve bu iki veritabanında birden bulunan gezegenleri alınız. Gezegen ismini bu bağlanmış veritabanının indeksi haline getiriniz.
pandas
paketinin iki veriçerçevesindeki verileri bağlamak için kullandığı fonksiyon pd.merge()
fonksiyonudur. Fonksiyon varsayılan olarak bizim de amaçladığımız kesişim işlemini how = "inner"
parametresi ile sağlar. Ancak her iki verçerçevesinde gezegen isimlerinin bulunduğu sütunlar farklıdır. Bu sütunların fonksiyona veritabanlarının verildiği sırayla hangi isimlerde olduğu left_on
ve right_on
parametrelerine sağlanmalıdır. Sonrasında oluşacak yeni verçerçevesinin indeksini gezegen ismi yapmak üzere veriçerçeveleri üzerine tanımlı set_index
metoduna pl_name
sütun ismi sağlanarak istenen hedefe ulaşılabilir.
og = pd.merge(nasaexo, exoeu, how="inner",\
left_on="pl_name", right_on="name")
og.set_index("pl_name", inplace=True)
print("NASA Exoplanet Archive veritabani buyuklugu: ", nasaexo.shape)
print("exoplanet.eu veritabani buyuklugu: ", exoeu.shape)
print("İki veritabaninin kesisiminin buyuklugu: ", og.shape)
nasaexo[nasaexo['pl_name'] == 'Kepler-16 b']
exoeu[exoeu['name'] == 'Kepler-16 b']
exoeu[exoeu['name'] == 'Kepler-16 (AB) b']
Görüldüğü üzere her iki veritabanında sırasıylsa 5602 ve 5653 ötegezegen olmasına karşın, kesişimlerinde toplam 4630 ötegezegen bulunmaktadır. Aslında aynı isimle olmasa dahi her iki veritabanında yer alan bazı ötegezegenler maalesef bulunmaktadır. Bunun nedeni zaman zaman ortaya çıkan isim karışıklığıdır. Örneğin NASA Exoplanet Archive veritabanında Kepler-16 b ismiyle yer alan ötegezegen, exoplanet.eu veritabanında bir çift yıldızın etrafında dolanan bir gezegen olduğu (ing. circumbinary planet) için Kepler 16 (AB) b ismiyle yer almaktadır. Yukarıdaki gibi bir birleştirmeyle bu tür ötegezegenleri veritabanında kaybetme tehlikesi vardır. Maalesef bu özel durumdan kaçınmanın kolay bir yolu olmayabilir. Özelde çift yıldız gezegenlerinin isimlerini kontrol edip eşleştirebilecek $string$ fonksiyonlarından faydalanılabilir. Ancak amacımız bu olmadığı için bu hataları bu uygulamada görmezden geliyoruz. Çalışma alanında deneyimli ve bu veritabanları üzerinden bir bilimsel araştırma yürütecek bir araştırıcının bu tür durumları da dikkate alması ve bunlar için de fonksiyonlar yazması ve öncesinde üzerinde çalışacağı veritabanlarını iyice incelemesi gerekir.
Daha önemlisi birbirine bağlanan veritabanlarında sırasıyla 84 ve 98 sütun bulunduğu için bağlama işlemi sonunda oluşan $og$ veritabanında 181 sütunun bulunmasıdır. Bu durumda her iki veritabanında birden çok kez bulunan sütunların hangilerinin nihai veritabanında bulunup hangilerinin bulunmayacağına karar vermek gerek. Bu bilgiler, farklı veritabanlarında farklı kaynaklardan (literatür referanslarından) geliyor olabilir. Üzerinde çalışılacak birleştirilmiş veritabanının sağlıklı veriler içermesi için yapılması gereken bu seçimde öncelikler araştırmacıdan araştırmacıya, ya da yapılacak araştırmanın niteliğine göre değişebilir. Biz bu uygulamada her iki veritabanında da bulunan bilgiler için NASA Exoplanet Archive'da bulunanları kullanmayı tercih edeceğiz.
Her iki veritabanında da bulunan sütunları belirleyerek bunlardan exoplanet.eu veritabanında bulunanları bağlanmış veriçerçevenizden atınız.
Öncelikle her iki veritabanında aynı bilgiyi barındıran (aynı referanstan alınmayabildiği için bazıları tam olarak aynı olmayabilir ancak biz NASA Explanet Archive veritabanında bulunan bilgileri kullanmayı tercih ettik), ancak farklı isimle bulunan sütunların exoplanet.eu veritabanındaki isimlerini bir listeye toplayalım. Sonra bu listeyi pandas
veriçerçevelerine uygulanan drop()
fonksiyonuna sütun silecek şekilde axis
parametresini $1$ değerine ayarlayarak atalım ve yaptığımız değişikliği kalıcı hale getirmek için inplace
parametresini de $True$ değerine ayarlayalım.
atilacak_sutunlar = ['star_name','name','detection_type',
'orbital_period','orbital_period_error_min','orbital_period_error_max',
'semi_major_axis','semi_major_axis_error_min','semi_major_axis_error_max',
'eccentricity','eccentricity_error_min','eccentricity_error_max',
'inclination','inclination_error_min','inclination_error_max',
'mass','mass_error_min','mass_error_max','mass_detection_type',
'radius','radius_error_min','radius_error_max']
og.drop(atilacak_sutunlar,axis=1,inplace=True)
og.columns
Görüldüğü gibi her iki veriçerçevesinde de "aynı" bilgiyi içeren, ancak farklı isimle bulunan toplamda 22 sütunu attık ve sütun sayımız 159'a indi.
Her iki veritabanında da aynı isimle bulunan ve barınak yıldızın ekvatoryal koordinat sistemindeki koordinatlarını içeren $ra$ ve $dec$ sütunlarından exoplanet.eu veritabanı sağlananları atacak ve birer $ra$,$dec$ sütunu bırakacak düzenlemeyi yapınız.
pandas.merge()
işlemi sırasında her iki taraftan aynıı isimle gelecek sütunlardan fonksiyona ilk sağlanan veriçerçevesindekinin sonuna "_x", ikinci sağlanacak veriçerçevesindekinin sonuna ise "_y" eki gelecektir. Bu nedenle sonu "_y" ile biten $ra$ ve $dec$ sütunlarını yine drop()
fonksiyonunu uygun şekilde kullanarak atabiliriz.
og.drop(['ra_y','dec_y'], axis=1,inplace=True)
Daha sonra da ra_x ve dec_x isimli sütunları yeniden isimlendirerek amacımıza ulaşabiliriz. Bunun için veriçerçeveleri üzerinde tanımlı rename()
fonksiyonunu aşağıdaki şekilde istediğimiz değişiklikleri bir sözlük değişkenine yazıp, bu değişkeni columns
parametresine sağlayarak kullanmalı ve yine yaptığımız değişikliği kalıcı hale getirmek için fonksiyonun inplace
parametresini $True$ değerine ayarlamalıyız.
og[['ra_x','dec_x']].head()
og.rename(columns={'ra_x':'ra','dec_x':'dec'},inplace=True)
og[['ra','dec']].head()
Gördüğünüz gibi istediğmiz değişiklikleri yaptık ve bağlanmış veritabanımızı her iki veritabanında ortak olan ötegezegenler için her iki veritabanında ortak olmayan bilgilerini de içerecek şekilde her türlü analiz için hazır hale getirmiş olduk. Herhangi bir veri için tekrar orjinal veritabanlarına dönmemiz gerekse de bu veritabanlarını sırasıyla $nasaexo$ ve $exoeu$ veriçerçevelerinde sakladığımız için bir kaybımız olmayacak.
Sadece geçiş yöntemiyle keşfedilmiş gezegenlerden oluşan bir veriçerçevesi oluşturunuz.
Bu amaçla yapmamız gereken daha önce de yaptığımız gibi bize sadece geçiş yapan gezegenleri verecek bir koşul üretip bu koşulu mevcut veritabanında uygulayarak bir maske oluşturmak ve uyanları yeni bir veritabanına toplamaktan ibaret. Ancak önce keşif yöntemlerinin hangileri olduğunu görelim. Bunun için discoverymethod sütununa bakmalı ve bu sütundaki tüm teknikleri unique()
metodunu kullanarak birer kez geçecek listelemeliyiz.
print(og['discoverymethod'].unique())
print(nasaexo['discoverymethod'].unique())
print(exoeu['detection_type'].unique())
Geçiş yöntemiyle keşfedilen gezegenlerin discoverymethod sütununda $Transit$ adıyla listelendiğini görmüş olduk. Koşulu buna uygun olarak yazabiliriz.
kosul = (og['discoverymethod'] == 'Transit')
gecis_og = og[kosul]
gecis_og.shape
Gördüğünüz gibi her iki veritabanında (NASA ve exoplanet.eu) ortak olan 4443 ötegezegenden 3464'ü geçişle keşfedilmiş (4 Nisan 2023 itibarı ile güncel). Bu önemli bir yüzde. Elimizdeki bu veriçerçevesinde NASA Exoplanet Arcihve'da bulunan onaylanmış tüm geçiş yapan ötegezegenler olduğuna göre bu ötegezegenlerin kütle ve yarıçapları biliniyor olmalı.
gecis_og[gecis_og['pl_bmassj'].isnull()]['pl_bmassj']
Gördüğünüz gibi durum hiç de öyle değil. Bildiğiniz gibi geçiş yöntemi gezegen yarıçapının yıldız yarıçapına oranının bulunmasını sağlar, yıldız modellerinden elde edilen yıldız yarıçapları kullanılarak gezegen yarıçapları elde edilebilirken kütlelerini elde etmek mümkün değildir. Burada dikine hız (ya da bir başka yöntemle) kütleleri onaylanmamış gezegenler (adaylar) de bulunuyor; hatta çoğunluktalar (2125 / 2772). Bunun için yapabileceğimiz pek fazla bir şey yok; zira bu gezegenlerin büyük çoğunluğu, ki bunların da büyük bölümü de Kepler uzay teleskobuyla keşfedilmiş gezegenlerdir; dikine hızlarını elde etmek üzere yüksek çözünürlüklü tayfları alınamayacak kadar sönük yıldızların etrafında bulunuyorlar. O vakit sadece kütlesi bulunanlara odaklanalım. Ancak önce yarıçapların da bulunup bulunmadığını bir test edelim. isnull()
fonksiyonu kullanabileceğimiz gibi isna()
fonksiyonunu da kullanabiliriz çünkü veriçerçevemizde değer bulunmayan bütün sütunlar NaN
olarak işaretmenmiş durumda.
gecis_og[gecis_og['pl_radj'].isna()]['pl_radj']
İşte bu şaşırtıcı. Zira geçiş yöntemiyle keşfedilmiş 16 ötegezegenin veriçerçevemizde yarıçapları bulunmuyor. Bunun nedeni basit olarak bu değerlerin veritabanına girilmemiş olması olabilir. Astronomide (ya da veri bilimi içeren herhangi başka bir alanda) kullanılan veritabanlarında bu durumla sıklıkla karşılaşılır. Bu tür durumlarda bu bilgiler başka veritabanlarında ya da literatürden alınabilir. Ya da sadece bu durumu yönetmekle yetinilir. Bir başka deyişle, iş eldeki veriyle yapılıp bu durum sonuçların paylaşıldığı yerde belirtilir. 4 Nisan 2023 tarihi itibarı ile ortak tabloda geçiş yöntemiyle keşfedilip yarıçapı veritabanına girilmemiş gezegen bulunmamaktadır. Ancak tekrar oluşabilecek böyle bir durum için aşağıdakine benzer bir çözüm takip edilebilir:
Biz örneğimizde yarıçap değerlerini barındıran pl_radj sütununu NASA Exoplanet Archive'dan almıştık. Bu gezegenler exoplanet.eu veritabanında da bulundukları için orada yarıçapları bulunuyor olabilir. Dolayısıyla yukarıdaki koşulun sağlandığı gezegenlerin yarıçap değerlerini exoplanet.eu ($exoeu$) veritabanından alıp, veriçerçevemizdeki pl_radj sütununa kopyalayabiliriz. Öncelikle exoplanet.eu veritabanında bu gezegenlerden hangilerinin yarıçaplarının olduğuna bakalım. Bunun için $exoeu$ şeklinde adlandırdığımız bu veritabanının indeks sütununu gezegen adının bulunduğu # name sütununa ayarlayalım ve gecis_og veriçerçevemizde yarıçapı bulunmayan (NaN
olan) gezegenlerin bu veritabanında olup olmadığını sorgulayalım. Yarıçap değerleri $exoeu$ veriçerçevesinde $radius$ sütununda bulunmaktadır.
exoeu.set_index('name', inplace=True)
for planet in gecis_og[gecis_og['pl_radj'].isna()]['pl_radj'].index:
print(planet,exoeu.loc[planet,'radius'])
Gördüğünüz gibi bu değerler exoplanet.eu veritabanında bulunuyor. Bulunmuyor da olabilirdi. Bu durumda da gidip başka bir veritabanına bakabilir ya da literatürden toplayıp manuel olarak kendimiz girebilirdik. Ama buna gerek kalmadı. Yukarıdaki gibi bir döngü yapısıyla ilgili satırlara gereken bilgileri ekleyebiliriz.
for planet in gecis_og[gecis_og['pl_radj'].isna()]['pl_radj'].index:
gecis_og.at[planet,'pl_radj'] = exoeu.at[planet,'radius']
print(gecis_og[gecis_og['pl_radj'].isna()]['pl_radj'])
print(gecis_og.at['WASP-18 b','pl_radj'])
Görüldüğü üzere artık yarıçap bulunmayan sütun yok. Geçiş yöntemiyle keşfedilen tüm gezegenler için bu değerin belirlenmiş olması gerektiğinden bu bilgiyi veriçerçevemizde bulundurmak istedik. Ancak bu gezegenlerin tümü için kütle değerinin veriçerçevemizde olmadığını gördük. Ancak amacımız olan kütle-yarıçap grafiğini seaborn
paketi fonksiyonları kullanarak çizdirirken bu durum bir problem teşkil etmeyecek. Çünkü kütlesi veriçerçevesinde bulunmayan gezegenler dikkate alınmayacak. Söz konusu parametreleri numpy
dizilerine alarak matplotlib.pyplot
fonksiyonları ile grafik elde etmek isterseniz bu durumu dikkat almanız gerekecektir.
from matplotlib import pyplot as plt
%matplotlib inline
plt.plot(gecis_og["pl_bmassj"], gecis_og["pl_radj"],'b+')
plt.xlabel("Kutle (M$_{jup}$)")
plt.ylabel("Yaricap (R$_{jup}$)")
plt.show()
Görüldüğü üzere bu veritabanlarından birinde (NASA Exoplanet Archive) bazı düşük kütleli yıldızlar da bulunmaktadır. Bunları seçerek veritabanından çıkarmakta fayda var.
gecis_og = gecis_og[gecis_og['pl_bmassj'] < 100]
plt.plot(gecis_og["pl_bmassj"], gecis_og["pl_radj"],'b+')
plt.xlabel("Kutle (M$_{jup}$)")
plt.ylabel("Yaricap (R$_{jup}$)")
plt.show()
Bu grafik genellikle farklı gezegen türleri için çizdirildiğinde anlam kazanan bir grafiktir. Bu nedenle yine daha önce yaptığımız gibi kütle limitleri koyarak kütle-yarıçap grafiğini farklı gezegen grupları için elde edebiliriz. Örneğin $0.1 - 0.4~M_{jup}$ kütle aralığındaki gezegenler için böyle bir uygulama yapalım.
kosul = (gecis_og['pl_bmassj'] >= 0.1) & (gecis_og['pl_bmassj'] <= 0.4)
saturnler = gecis_og[kosul]
plt.plot(saturnler["pl_bmassj"], saturnler["pl_radj"],'b+')
plt.xlabel("Kutle (M$_{jup}$)")
plt.ylabel("Yaricap (R$_{jup}$)")
plt.title("Gecis Yapan Saturn Kutlesindeki Gezegenler Icin Kutle-Yaricap Grafigi")
plt.show()
Bu grafikte bir doğru üzerine dizilen gezegenler için kütle değeri kütle-yarıçap ilişkilerinden türetilmiş olmalıdır. Bu gezegenler için barınak yıldızlarının sönük olması nedeniyle dikine hız alınmamış olabilir, ayrıca gezegen kütlesini belirlemeye yardımcı olabilecek, gözlenebilecek düzeyde bir geçiş zamanlaması değişimi yaratabilecek bir ilave cisim bulunmayabilir. Grafikte daha ilgi çekici olan, genel olarak Satürn kütlesi civarındaki gezegenler için saçılması yüksek de olsa kütleyle yarıçap arasında bir pozitif korelasyonun gözlendiği, ancak yarıçapı $0.25 R_{jup}$''ten küçük gezegenler için bu ilişkinin bozulduğudur. Bu ilginç bir araştırma sorusu olabilir; ancak öncelikle bu verilerin kaynağına bakmak ve grafiği bir de belirsizlik değerleriyle birlikte çizdirmeyi denemekte fayda vardır.
kosul = (gecis_og['pl_bmassj'] < 0.04)
karasal = gecis_og[kosul]
plt.plot(karasal["pl_bmassj"], karasal["pl_radj"],'b+')
plt.xscale("log")
plt.yscale("log")
plt.xlabel("Kutle (M$_{jup}$)")
plt.ylabel("Yaricap (R$_{jup}$)")
plt.title("Gecis Yapan Karasal Gezegenler Icin Kutle-Yaricap Grafigi")
plt.show()
kosul = (gecis_og['pl_bmassj'] > 0.5)
devgaz = gecis_og[kosul]
plt.plot(devgaz["pl_bmassj"], devgaz["pl_radj"],'b+')
plt.xlabel("Kutle (M$_{jup}$)")
plt.ylabel("Yaricap (R$_{jup}$)")
plt.title("Gecis Yapan Dev Gaz Gezegenler Icin Kutle-Yaricap Grafigi")
plt.show()