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.
import pandas as pd
nasaexo = pd.read_csv('PSCompPars_2022.03.22_01.51.21.csv',
comment="#", skipinitialspace=True)
exoeu = pd.read_csv('exoplanet.eu_catalog_20200421.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)
NASA Exooplanet Archive veritabani sutunlari --------------------------------------------- Index(['pl_name', 'hostname', 'sy_snum', 'sy_pnum', 'discoverymethod', 'disc_year', 'disc_facility', 'pl_controv_flag', 'pl_orbper', 'pl_orbpererr1', 'pl_orbpererr2', 'pl_orbperlim', 'pl_orbsmax', 'pl_orbsmaxerr1', 'pl_orbsmaxerr2', 'pl_orbsmaxlim', 'pl_rade', 'pl_radeerr1', 'pl_radeerr2', 'pl_radelim', 'pl_radj', 'pl_radjerr1', 'pl_radjerr2', 'pl_radjlim', 'pl_bmasse', 'pl_bmasseerr1', 'pl_bmasseerr2', 'pl_bmasselim', 'pl_bmassj', 'pl_bmassjerr1', 'pl_bmassjerr2', 'pl_bmassjlim', 'pl_bmassprov', 'pl_orbeccen', 'pl_orbeccenerr1', 'pl_orbeccenerr2', 'pl_orbeccenlim', 'pl_insol', 'pl_insolerr1', 'pl_insolerr2', 'pl_insollim', 'pl_eqt', 'pl_eqterr1', 'pl_eqterr2', 'pl_eqtlim', 'ttv_flag', 'st_spectype', 'st_teff', 'st_tefferr1', 'st_tefferr2', 'st_tefflim', 'st_rad', 'st_raderr1', 'st_raderr2', 'st_radlim', 'st_mass', 'st_masserr1', 'st_masserr2', 'st_masslim', 'st_met', 'st_meterr1', 'st_meterr2', 'st_metlim', 'st_metratio', 'st_logg', 'st_loggerr1', 'st_loggerr2', 'st_logglim', 'rastr', 'ra', 'decstr', 'dec', 'sy_dist', 'sy_disterr1', 'sy_disterr2', 'sy_vmag', 'sy_vmagerr1', 'sy_vmagerr2', 'sy_kmag', 'sy_kmagerr1', 'sy_kmagerr2', 'sy_gaiamag', 'sy_gaiamagerr1', 'sy_gaiamagerr2'], dtype='object') xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx exoplanet.eu veritabani sutunlari --------------------------------------------- Index(['# name', 'planet_status', 'mass', 'mass_error_min', 'mass_error_max', 'mass_sini', 'mass_sini_error_min', 'mass_sini_error_max', 'radius', 'radius_error_min', 'radius_error_max', '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', 'angular_distance', 'discovered', 'updated', 'omega', 'omega_error_min', 'omega_error_max', 'tperi', 'tperi_error_min', 'tperi_error_max', 'tconj', 'tconj_error_min', 'tconj_error_max', 'tzero_tr', 'tzero_tr_error_min', 'tzero_tr_error_max', 'tzero_tr_sec', 'tzero_tr_sec_error_min', 'tzero_tr_sec_error_max', 'lambda_angle', 'lambda_angle_error_min', 'lambda_angle_error_max', 'impact_parameter', 'impact_parameter_error_min', 'impact_parameter_error_max', 'tzero_vr', 'tzero_vr_error_min', 'tzero_vr_error_max', 'k', 'k_error_min', 'k_error_max', 'temp_calculated', 'temp_calculated_error_min', 'temp_calculated_error_max', 'temp_measured', 'hot_point_lon', 'geometric_albedo', 'geometric_albedo_error_min', 'geometric_albedo_error_max', 'log_g', 'publication', 'detection_type', 'mass_detection_type', 'radius_detection_type', 'alternate_names', 'molecules', 'star_name', 'ra', 'dec', 'mag_v', 'mag_i', 'mag_j', 'mag_h', 'mag_k', 'star_distance', 'star_distance_error_min', 'star_distance_error_max', 'star_metallicity', 'star_metallicity_error_min', 'star_metallicity_error_max', 'star_mass', 'star_mass_error_min', 'star_mass_error_max', 'star_radius', 'star_radius_error_min', 'star_radius_error_max', 'star_sp_type', 'star_age', 'star_age_error_min', 'star_age_error_max', 'star_teff', 'star_teff_error_min', 'star_teff_error_max', 'star_detected_disc', 'star_magnetic_field', 'star_alternate_names'], dtype='object')
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şlenini 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)
NASA Exoplanet Archive veritabani buyuklugu: (5005, 84) exoplanet.eu veritabani buyuklugu: (4249, 98) İki veritabaninin kesisiminin buyuklugu: (3602, 181)
Görüldüğü üzere her iki veritabanında sırasıylsa 4144 ve 4249 ötegezegen olmasına karşın, kesişimlerinde toplam 3557 ö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) 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ı gerekir; öncesinde üzerinde çalışacağı veritabanlarını iyice incelemesi gerekir.
Daha önemlisi birbirine bağlanan veritabanlarında sırasıyla 72 ve 98 sütun bulunduğu için bağlama işlemi sonunda oluşan $og$ veritabanında 169 sütunun bulunmasıdır. Bu durumda her iki veritabanında birden 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
Index(['hostname', 'sy_snum', 'sy_pnum', 'discoverymethod', 'disc_year', 'disc_facility', 'pl_controv_flag', 'pl_orbper', 'pl_orbpererr1', 'pl_orbpererr2', ... 'star_sp_type', 'star_age', 'star_age_error_min', 'star_age_error_max', 'star_teff', 'star_teff_error_min', 'star_teff_error_max', 'star_detected_disc', 'star_magnetic_field', 'star_alternate_names'], dtype='object', length=159)
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 147'ye 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()
ra_x | dec_x | |
---|---|---|
pl_name | ||
11 Com b | 185.178779 | 17.793252 |
11 UMi b | 229.274595 | 71.823943 |
14 And b | 352.824150 | 39.235837 |
14 Her b | 242.602101 | 43.816362 |
16 Cyg B b | 295.465642 | 50.516824 |
og.rename(columns={'ra_x':'ra','dec_x':'dec'},inplace=True)
og[['ra','dec']].head()
ra | dec | |
---|---|---|
pl_name | ||
11 Com b | 185.178779 | 17.793252 |
11 UMi b | 229.274595 | 71.823943 |
14 And b | 352.824150 | 39.235837 |
14 Her b | 242.602101 | 43.816362 |
16 Cyg B b | 295.465642 | 50.516824 |
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 pl_discmethod sütununa bakmalı ve bu sütundaki tüm teknikleri unique()
metodunu kullanarak birer kez geçecek listelemeliyiz.
print(og['discoverymethod'].unique())
['Radial Velocity' 'Imaging' 'Transit' 'Eclipse Timing Variations' 'Orbital Brightness Modulation' 'Pulsation Timing Variations' 'Microlensing' 'Transit Timing Variations' 'Pulsar Timing']
Geçiş yöntemiyle keşfedilen gezegenlerin pl_discmethod 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
(2800, 157)
Gördüğünüz gibi her iki veritabanında (NASA ve exoplanet.eu) ortak olan 3557 ötegezegenden 2772'si geçişle keşfedilmiş. 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']
pl_name Kepler-302 c NaN Kepler-468 b NaN Kepler-487 b NaN Kepler-490 b NaN Kepler-548 b NaN Kepler-553 c NaN Kepler-670 b NaN Kepler-686 b NaN Kepler-699 b NaN Kepler-706 b NaN Kepler-723 b NaN Kepler-730 b NaN Kepler-731 b NaN Kepler-762 b NaN Kepler-785 b NaN Name: pl_bmassj, dtype: float64
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']
Series([], Name: pl_radj, dtype: float64)
İş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.
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'])
Series([], Name: pl_radj, dtype: float64) 1.24
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.
import seaborn as sns
%matplotlib inline
sns.relplot(x="pl_bmassj", y="pl_radj", data=gecis_og)
<seaborn.axisgrid.FacetGrid at 0x7fe4e573ddf0>
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]
sns.relplot(x="pl_bmassj", y="pl_radj", data=saturnler)
<seaborn.axisgrid.FacetGrid at 0x7fe4e5465e80>