Think Stats kitabının üçüncü baskısını Bookshop.org ve Amazon üzerinden edinebilirsiniz (bunlar satış ortaklığı bağlantılarıdır). Ücretsiz çevrimiçi sürümü beğeniyorsanız bana bir kahve ısmarlamayı düşünebilirsiniz.
4. Kümülatif dağılım fonksiyonları#
Frekans tabloları ve PMF’ler dağılımları temsil etmenin en bilinen yollarıdır; ancak bu bölümde göreceğimiz gibi bazı sınırlamaları vardır. Bir alternatif, yüzdelikleri hesaplamaya ve özellikle dağılımları karşılaştırmaya yarayan kümülatif dağılım fonksiyonudur (CDF).
Bu bölümde ayrıca dağılımın konumunu, yayılımını ve çarpıklığını nicelleştirmek için yüzdeliklere dayalı istatistikler hesaplayacağız.
Bu notebook’u Colab’da çalıştırmak için buraya tıklayın.
4.1. Yüzdelikler ve yüzdelik sıralar#
Standartlaştırılmış bir sınava girdiyseniz sonuçlarınız muhtemelen ham puan ve yüzdelik sıra biçiminde verilmiştir. Bu bağlamda yüzdelik sıra, sizinle aynı veya sizden daha düşük puan alan kişilerin yüzdesidir. Dolayısıyla “90. yüzdelikteyseniz” sınava girenlerin %90’ıyla aynı veya onlardan daha iyi sonuç almışsınız demektir.
Yüzdelikleri ve yüzdelik sıraları anlamak için koşu hızlarına dayalı bir örneği ele alalım. Birkaç yıl önce Massachusetts’te düzenlenen 10 kilometrelik James Joyce Ramble yol yarışına katıldım. Yarıştan sonra süremi diğer koşucularla karşılaştırmak için sonuçları indirdim.
Verileri indirme talimatları bu bölümün notebook’unda yer alıyor.
download("https://github.com/TerekliTahaBerk/thinkstatstr/raw/v3/nb/relay.py")
download(
"https://github.com/TerekliTahaBerk/thinkstatstr/raw/v3/data/Apr25_27thAn_set1.shtml"
)
relay.py modülü sonuçları okuyup bir Pandas DataFramei döndüren bir fonksiyon sağlar.
from relay import read_results
results = read_results()
results.head()
| Place | Div/Tot | Division | Guntime | Nettime | Min/Mile | MPH | |
|---|---|---|---|---|---|---|---|
| 0 | 1 | 1/362 | M2039 | 30:43 | 30:42 | 4:57 | 12.121212 |
| 1 | 2 | 2/362 | M2039 | 31:36 | 31:36 | 5:06 | 11.764706 |
| 2 | 3 | 3/362 | M2039 | 31:42 | 31:42 | 5:07 | 11.726384 |
| 3 | 4 | 4/362 | M2039 | 32:28 | 32:27 | 5:14 | 11.464968 |
| 4 | 5 | 5/362 | M2039 | 32:52 | 32:52 | 5:18 | 11.320755 |
results, yarışı tamamlayan 1.633 koşucunun her biri için bir satır içerir.
Performansı nicelleştirmek için kullanacağımız MPH sütunu, her koşucunun saat başına mil cinsinden ortalama hızını içerir.
Bu sütunu seçecek ve hızları NumPy dizisi olarak çıkarmak için values niteliğini kullanacağız.
speeds = results["MPH"].values
Yarışı 42:44’te bitirdim; dolayısıyla satırımı şu şekilde bulabiliriz.
my_result = results.query("Nettime == '42:44'")
my_result
| Place | Div/Tot | Division | Guntime | Nettime | Min/Mile | MPH | |
|---|---|---|---|---|---|---|---|
| 96 | 97 | 26/256 | M4049 | 42:48 | 42:44 | 6:53 | 8.716707 |
Satırımın indeksi 96 olduğuna göre hızımı şöyle çıkarabiliriz.
my_speed = speeds[96]
Benim hızımda veya daha yavaş koşanların sayısını bulmak için sum kullanabiliriz.
(speeds <= my_speed).sum()
np.int64(1537)
Benim hızımda veya daha yavaş koşanların yüzdesini hesaplamak için mean kullanabiliriz.
(speeds <= my_speed).mean() * 100
np.float64(94.12124923453766)
Sonuç, bütün koşucular arasındaki yüzdelik sıramdır ve yaklaşık %94’tür.
Daha genel olarak aşağıdaki fonksiyon, bir değer dizisindeki belirli bir değerin yüzdelik sırasını hesaplar.
def percentile_rank(x, seq):
"""x değerinin yüzdelik sırasını hesaplar.
x: değer
seq: değer dizisi
döndürür: 0-100 arasında yüzdelik sıra
"""
return (seq <= x).mean() * 100
results içindeki Division sütunu, her koşucunun cinsiyet ve yaş aralığına göre belirlenen kategorisini gösterir. Örneğin ben, 40-49 yaşındaki erkek koşucuları içeren M4049 kategorisindeydim.
Kategorimdeki kişilerin satırlarını seçmek ve hızlarını çıkarmak için query yöntemini kullanabiliriz.
my_division = results.query("Division == 'M4049'")
my_division_speeds = my_division["MPH"].values
Artık kategorimdeki yüzdelik sıramı hesaplamak için percentile_rank fonksiyonunu kullanabiliriz.
percentile_rank(my_speed, my_division_speeds)
np.float64(90.234375)
Ters yönde gidersek, yüzdelik sıra verildiğinde aşağıdaki fonksiyon bir dizide buna karşılık gelen değeri bulur.
def percentile(p, seq):
n = len(seq)
i = (1 - p / 100) * (n + 1)
return seq[round(i)]
n dizideki öğelerin sayısı, i ise verilen yüzdelik sıraya sahip öğenin indeksidir.
Bir yüzdelik sırayı aradığımızda karşılık gelen değere yüzdelik denir.
percentile(90, my_division_speeds)
np.float64(8.591885441527447)
Kategorimde 90. yüzdelik yaklaşık saatte 8,6 mildi.
Bu yarışa katılmamın üzerinden birkaç yıl geçti ve artık M5059 kategorisindeyim.
Yeni kategorimde aynı yüzdelik sıraya ulaşmak için ne kadar hızlı koşmam gerektiğine bakalım.
Yaklaşık %90,2 olan M4049 kategorisindeki yüzdelik sıramı M5059 kategorisindeki bir hıza dönüştürerek bu soruyu yanıtlayabiliriz.
next_division = results.query("Division == 'M5059'")
next_division_speeds = next_division["MPH"].values
percentile(90.2, next_division_speeds)
np.float64(8.017817371937639)
M5059 kategorisinde benimle aynı yüzdelik sıraya sahip kişi saatte 8 milin biraz üzerinde koşmuş.
Bu kişiyi bulmak için query kullanabiliriz.
next_division.query("MPH > 8.01").tail(1)
| Place | Div/Tot | Division | Guntime | Nettime | Min/Mile | MPH | |
|---|---|---|---|---|---|---|---|
| 222 | 223 | 18/171 | M5059 | 46:30 | 46:25 | 7:29 | 8.017817 |
Yarışı 46:25’te bitirmiş ve kategorisindeki 171 kişi arasında 18. olmuş.
Yüzdelik sıraları ve yüzdelikleri tanıdığımıza göre artık kümülatif dağılım fonksiyonlarına geçebiliriz.
4.2. CDF’ler#
Kümülatif dağılım fonksiyonu veya CDF, frekans tablosu ve PMF gibi bir değer kümesinin dağılımını betimlemenin başka bir yoludur.
Bir x değeri verildiğinde CDF, xten küçük veya xe eşit değerlerin oranını hesaplar.
Örnek olarak kısa bir diziyle başlayacağız.
t = [1, 2, 2, 3, 5]
CDF hesaplamanın yollarından biri PMF ile başlamaktır.
Aşağıdaki Pmf nesnesi t içindeki değerlerin dağılımını temsil eder.
from empiricaldist import Pmf
pmf = Pmf.from_seq(t)
pmf
| probs | |
|---|---|
| 1 | 0.2 |
| 2 | 0.4 |
| 3 | 0.2 |
| 5 | 0.2 |
Önceki bölümde gördüğümüz gibi bir Pmf içindeki değeri aramak için köşeli ayraç işlecini kullanabiliriz.
pmf[2]
np.float64(0.4)
Sonuç, dizide verilen değere eşit olan değerlerin oranıdır.
Bu örnekte beş değerden ikisi 2ye eşit olduğu için sonuç 0,4’tür.
Bu oranı, diziden rastgele seçilen bir değerin 2ye eşit olma olasılığı olarak da düşünebiliriz.
Pmf, içindeki olasılıkların kümülatif toplamını hesaplayan make_cdf yöntemini sunar.
cdf = pmf.make_cdf()
cdf
| probs | |
|---|---|
| 1 | 0.2 |
| 2 | 0.6 |
| 3 | 0.8 |
| 5 | 1.0 |
Sonuç, bir tür Pandas Series nesnesi olan Cdf nesnesidir.
Bir değeri aramak için köşeli ayraç işlecini kullanabiliriz.
cdf[2]
np.float64(0.6000000000000001)
Sonuç, dizide verilen değerden küçük veya ona eşit olan değerlerin oranıdır. Bu örnekte beş değerden üçü 2den küçük veya 2ye eşit olduğu için sonuç 0,6’dır.
Bu oranı, diziden rastgele seçilen bir değerin 2den küçük veya 2ye eşit olma olasılığı olarak da düşünebiliriz.
Cdf nesnesini fonksiyon gibi çağırmak için parantez kullanabiliriz.
cdf(3)
array(0.8)
Kümülatif dağılım fonksiyonu yalnızca dizide görünen değerler için değil, bütün sayılar için tanımlıdır.
cdf(4)
array(0.8)
Cdfyi görselleştirmek için onu basamak fonksiyonu olarak çizen step yöntemini kullanabiliriz.
cdf.step()
decorate(xlabel="x", ylabel="CDF")
İkinci örnek olarak önceki kısımdaki koşu hızlarının dağılımını temsil eden bir Cdf oluşturalım.
Cdf sınıfı, bir diziden Cdf nesnesi oluşturmak için kullanabileceğimiz from_seq fonksiyonunu sunar.
from empiricaldist import Cdf
cdf_speeds = Cdf.from_seq(speeds)
Grafik şu şekilde görünür; dikey çizgi benim hızımı gösteriyor.
cdf_speeds.step()
plt.axvline(my_speed, ls=":", color="gray")
decorate(xlabel="Hız (mil/saat)", ylabel="CDF")
Hızımı aradığımızda sonuç, benim hızımda veya daha yavaş koşanların oranıdır. 100 ile çarptığımızda yüzdelik sıramı elde ederiz.
cdf_speeds(my_speed) * 100
np.float64(94.12124923453766)
Dolayısıyla Cdfyi şöyle düşünebiliriz: Bir değer verildiğinde yüzdelik sıraya benzer bir sonuç hesaplar; ancak sonuç 0 ile 100 arasında bir yüzde değil, 0 ile 1 arasında bir orandır.
Cdf, kümülatif dağılım fonksiyonunun tersini hesaplayan inverse yöntemini sunar. 0 ile 1 arasında bir oran verildiğinde karşılık gelen değeri bulur.
Örneğin bir kişi bütün koşucuların %50’si kadar veya onlardan daha hızlı koştuğunu söylüyorsa hızını şöyle bulabiliriz.
cdf_speeds.inverse(0.5)
array(6.70391061)
Bir oran verilip karşılık gelen değer ters CDF ile bulunduğunda sonuca kantil denir; bu nedenle ters CDF’ye bazen kantil fonksiyonu adı verilir.
Bir kantil verip karşılık gelen oranı CDF ile bulduğunuzda sonucun garip biçimde özel bir adı yoktur. Yüzdelik ve yüzdelik sırayla tutarlı olması için buna “kantil sırası” denebilirdi; ancak bildiğim kadarıyla kimse bu adı kullanmıyor. Çoğunlukla yalnızca “kümülatif olasılık” denir.
4.3. CDF’lerin karşılaştırılması#
CDF’ler özellikle dağılımları karşılaştırmak için kullanışlıdır.
Örnek olarak ilk bebeklerle diğerlerinin doğum ağırlığı dağılımlarını karşılaştıralım.
NSFG veri kümesini yeniden yükleyip üç DataFramee ayıracağız: bütün canlı doğumlar, ilk bebekler ve diğerleri.
Aşağıdaki hücreler veri dosyalarını indirir ve verileri okumak için ihtiyaç duyduğumuz statadict paketini kurar.
download("https://github.com/TerekliTahaBerk/thinkstatstr/raw/v3/nb/nsfg.py")
download("https://github.com/TerekliTahaBerk/thinkstatstr/raw/v3/data/2002FemPreg.dct")
download("https://github.com/TerekliTahaBerk/thinkstatstr/raw/v3/data/2002FemPreg.dat.gz")
try:
import statadict
except ImportError:
%pip install statadict
from nsfg import get_nsfg_groups
live, firsts, others = get_nsfg_groups()
firsts ve others içinden libre cinsinden toplam doğum ağırlıklarını seçecek, nan değerlerini kaldırmak için dropna kullanacağız.
first_weights = firsts["totalwgt_lb"].dropna()
first_weights.mean()
np.float64(7.201094430437772)
other_weights = others["totalwgt_lb"].dropna()
other_weights.mean()
np.float64(7.325855614973262)
İlk bebekler ortalama olarak biraz daha hafif görünüyor. Ancak böyle bir fark birkaç şekilde ortaya çıkabilir. Örneğin özellikle hafif az sayıda ilk bebek veya özellikle ağır az sayıda diğer bebek bulunabilir. Bu durumlarda dağılımların biçimleri farklı olur. Başka bir olasılık, dağılımların biçimlerinin aynı fakat konumlarının farklı olmasıdır.
Dağılımları karşılaştırmak için PMF’leri çizmeyi deneyebiliriz.
from empiricaldist import Pmf
first_pmf = Pmf.from_seq(first_weights, name="ilkler")
other_pmf = Pmf.from_seq(other_weights, name="diğerleri")
Ancak aşağıdaki şekilde görüldüğü gibi bu yöntem pek iyi sonuç vermiyor.
from thinkstats import two_bar_plots
two_bar_plots(first_pmf, other_pmf, width=0.06)
decorate(xlabel="Ağırlık (libre)", ylabel="PMF")
Dağılımları olabildiğince açık göstermek için çubukların genişliğini ve saydamlığını ayarladım; buna rağmen dağılımları karşılaştırmak zor. Çok sayıda tepe ve çukurdan oluşan bazı farklar görülüyor; ancak bunlardan hangilerinin anlamlı olduğunu söylemek güç. Genel örüntüleri görmek de zor; örneğin hangi dağılımın ortalamasının daha yüksek olduğu görsel olarak anlaşılmıyor.
Bu sorunlar, verileri kutulara ayırarak; yani nicelik aralığını örtüşmeyen aralıklara bölüp her kutudaki nicelikleri sayarak azaltılabilir. Kutulama yararlı olabilir; ancak kutu büyüklüklerini doğru seçmek zordur. Kutular gürültüyü yumuşatacak kadar büyükse yararlı bilgileri de yumuşatabilir.
İyi bir alternatif CDF’leri çizmektir.
first_cdf = first_pmf.make_cdf()
other_cdf = other_pmf.make_cdf()
Grafikler şöyledir.
first_cdf.plot(ls="--")
other_cdf.plot(alpha=0.5)
decorate(xlabel="Ağırlık (libre)", ylabel="CDF")
Bu şekil dağılımların biçimini ve aralarındaki farkları çok daha açık gösteriyor. İlk bebeklerin eğrisi sürekli olarak diğerlerinin eğrisinin solundadır. Bu, ilk bebeklerin dağılımın tamamında biraz daha hafif olduğunu; orta noktanın üzerindeyse farkın büyüdüğünü gösterir.
4.4. Yüzdeliklere dayalı istatistikler#
3. Bölümde dağılımın merkezî noktasını belirleyen aritmetik ortalamayı ve dağılımın yayılımını nicelleştiren standart sapmayı hesapladık. Önceki bir alıştırmada da dağılımın sola mı sağa mı çarpık olduğunu gösteren çarpıklığı hesapladık. Bu istatistiklerin ortak sakıncası, aykırı değerlere duyarlı olmalarıdır. Veri kümesindeki tek bir aşırı değer ortalama, standart sapma ve çarpıklık üzerinde büyük etki yaratabilir.
Bir alternatif, dağılımın yüzdeliklerine dayanan ve aykırı değerlerden daha az etkilendiği için daha dayanıklı olan istatistikleri kullanmaktır. Bunu göstermek için NSFG verilerini herhangi bir veri temizliği yapmadan yeniden yükleyelim.
from nsfg import read_stata
dct_file = "2002FemPreg.dct"
dat_file = "2002FemPreg.dat.gz"
preg = read_stata(dct_file, dat_file)
Doğum ağırlığının biri libre, diğeri ons için olmak üzere iki sütunda kaydedildiğini hatırlayın.
birthwgt_lb = preg["birthwgt_lb"]
birthwgt_oz = preg["birthwgt_oz"]
birthwgt_oz değerleriyle bir Hist nesnesi oluşturursak eksik verileri gösteren 97, 98 ve 99 özel değerlerinin bulunduğunu görebiliriz.
from empiricaldist import Hist
Hist.from_seq(birthwgt_oz).tail(5)
| freqs | |
|---|---|
| birthwgt_oz | |
| 14.0 | 475 |
| 15.0 | 378 |
| 97.0 | 1 |
| 98.0 | 1 |
| 99.0 | 46 |
birthwgt_lb sütunu aynı özel değerleri ve açıkça hatalı olan 51 değerini içerir.
Hist.from_seq(birthwgt_lb).tail(5)
| freqs | |
|---|---|
| birthwgt_lb | |
| 15.0 | 1 |
| 51.0 | 1 |
| 97.0 | 1 |
| 98.0 | 1 |
| 99.0 | 57 |
Şimdi iki senaryo düşünelim.
Birinci senaryoda eksik ve geçersiz değerleri nan ile değiştirerek bu değişkenleri temizler, ardından libre cinsinden toplam ağırlığı hesaplarız.
birthwgt_oz_clean değişkenini 16’ya bölmek, onsu ondalık libreye dönüştürür.
birthwgt_lb_clean = birthwgt_lb.replace([51, 97, 98, 99], np.nan)
birthwgt_oz_clean = birthwgt_oz.replace([97, 98, 99], np.nan)
total_weight_clean = birthwgt_lb_clean + birthwgt_oz_clean / 16
Diğer senaryoda verileri temizlemeyi unutur ve toplam ağırlığı yanlışlıkla bu sahte değerlerle hesaplarız.
total_weight_bogus = birthwgt_lb + birthwgt_oz / 16
Hatalı veri kümesinde yalnızca 49 sahte değer vardır; bu da verilerin yaklaşık %0,5’idir.
count1, count2 = total_weight_bogus.count(), total_weight_clean.count()
diff = count1 - count2
diff, diff / count2 * 100
(np.int64(49), np.float64(0.5421553441026776))
Şimdi iki senaryodaki verilerin ortalamasını hesaplayalım.
mean1, mean2 = total_weight_bogus.mean(), total_weight_clean.mean()
mean1, mean2
(np.float64(7.319680587652691), np.float64(7.265628457623368))
Sahte değerlerin ortalama üzerinde orta düzeyde bir etkisi vardır. Temizlenmiş verilerin ortalamasını doğru kabul edersek hatalı verilerin ortalaması %1’den az sapmıştır.
(mean1 - mean2) / mean2 * 100
np.float64(0.74394294099376)
Böyle bir hata fark edilmeyebilir; şimdi standart sapmalara ne olduğuna bakalım.
std1, std2 = total_weight_bogus.std(), total_weight_clean.std()
std1, std2
(np.float64(2.096001779161835), np.float64(1.4082934455690173))
(std1 - std2) / std2 * 100
np.float64(48.83274403900607)
Hatalı verilerin standart sapması neredeyse %50 sapmıştır; bu daha belirgin bir farktır. Son olarak iki veri kümesinin çarpıklığı şöyledir.
def skewness(seq):
"""Bir dizinin çarpıklığını hesaplar.
seq: sayı dizisi
döndürür: kayan noktalı çarpıklık değeri
"""
deviations = seq - seq.mean()
return np.mean(deviations**3) / seq.std(ddof=0) ** 3
skew1, skew2 = skewness(total_weight_bogus), skewness(total_weight_clean)
skew1, skew2
(np.float64(22.251846195422484), np.float64(-0.5895062687577698))
# skew1 ne kadar sapmış?
(skew1 - skew2) / skew2
np.float64(-38.74658112171127)
Hatalı veri kümesinin çarpıklığı yaklaşık 40 kat sapmış, üstel işareti de yanlıştır! Verilere aykırı değerler eklendiğinde dağılım, büyük pozitif çarpıklığın gösterdiği gibi güçlü biçimde sağa çarpıktır. Geçerli verilerin dağılımıysa küçük negatif çarpıklığın gösterdiği gibi hafifçe sola çarpıktır.
Bu sonuçlar az sayıdaki aykırı değerin ortalama üzerinde orta, standart sapma üzerinde güçlü, çarpıklık üzerindeyse yıkıcı bir etkisi olduğunu gösteriyor.
Bir alternatif yüzdeliklere dayalı istatistikleri kullanmaktır. Özellikle:
yüzdelik olan medyan, ortalama gibi dağılımın merkezî noktasını belirler.
ve 25. yüzdelikler arasındaki fark olan çeyrekler arası açıklık, standart sapma gibi dağılımın yayılımını nicelleştirir.
Çeyreklik çarpıklığı, çarpıklığı nicelleştirmek için dağılımın çeyrekliklerini (25., 50. ve 75. yüzdelikleri) kullanır.
Cdf nesnesi yüzdeliklere dayalı bu istatistikleri hesaplamanın verimli bir yolunu sunar.
Göstermek için hatalı ve temiz veri kümelerinden birer Cdf nesnesi oluşturalım.
cdf_total_weight_bogus = Cdf.from_seq(total_weight_bogus)
cdf_total_weight_clean = Cdf.from_seq(total_weight_clean)
Aşağıdaki fonksiyon bir Cdf alıp inverse yöntemiyle medyan olan 50. yüzdeliği hesaplar (en azından bu, bir veri kümesinin medyanını tanımlamanın yollarından biridir).
def median(cdf):
m = cdf.inverse(0.5)
return m
Artık iki veri kümesinin medyanını hesaplayabiliriz.
median(cdf_total_weight_bogus), median(cdf_total_weight_clean)
(array(7.375), array(7.375))
Sonuçlar aynıdır; dolayısıyla bu örnekte aykırı değerlerin medyan üzerinde hiçbir etkisi yoktur. Genel olarak aykırı değerler medyanı ortalamadan daha az etkiler.
Çeyrekler arası açıklık (IQR), 75. ve 25. yüzdelikler arasındaki farktır.
Aşağıdaki fonksiyon bir Cdf alıp IQR’yi döndürür.
def iqr(cdf):
low, high = cdf.inverse([0.25, 0.75])
return high - low
İki veri kümesinin çeyrekler arası açıklıkları şöyledir.
iqr(cdf_total_weight_bogus), iqr(cdf_total_weight_clean)
(np.float64(1.625), np.float64(1.625))
Genel olarak aykırı değerler IQR’yi standart sapmadan daha az etkiler; bu örnekte hiçbir etkileri yoktur.
Son olarak aşağıdaki fonksiyon üç istatistiğe dayanan çeyreklik çarpıklığını hesaplar:
Medyan,
ve 75. yüzdeliklerin orta noktası,
IQR’nin yarısı olan yarı IQR.
def quartile_skewness(cdf):
low, median, high = cdf.inverse([0.25, 0.5, 0.75])
midpoint = (high + low) / 2
semi_iqr = (high - low) / 2
return (midpoint - median) / semi_iqr
İki veri kümesinin çeyreklik çarpıklığı şöyledir.
qskew1 = quartile_skewness(cdf_total_weight_bogus)
qskew2 = quartile_skewness(cdf_total_weight_clean)
qskew1, qskew2
(np.float64(-0.07692307692307693), np.float64(-0.07692307692307693))
Bu örneklerdeki az sayıdaki aykırı değerin çeyreklik çarpıklığı üzerinde hiçbir etkisi yoktur. Bu örnekler, yüzdeliklere dayalı istatistiklerin aykırı değerlere ve veri hatalarına daha az duyarlı olduğunu gösterir.
4.5. Rastgele sayılar#
Cdf nesneleri bir dağılımdan rastgele sayılar üretmenin verimli bir yolunu sunar.
Önce 0 ile 1 arasındaki tekdüze dağılımdan rastgele sayılar üretiriz.
Ardından ters CDF’yi bu noktalarda değerlendiririz.
Aşağıdaki fonksiyon bu algoritmayı uygular.
def sample_from_cdf(cdf, n):
ps = np.random.random(size=n)
return cdf.inverse(ps)
Göstermek için koşu hızlarından rastgele bir örneklem üretelim.
sample = sample_from_cdf(cdf_speeds, 1001)
İşlemin doğru çalıştığını doğrulamak için örneklemle asıl veri kümesinin CDF’lerini karşılaştırabiliriz.
cdf_sample = Cdf.from_seq(sample)
cdf_speeds.plot(label="orijinal", ls="--")
cdf_sample.plot(label="örneklem", alpha=0.5)
decorate(xlabel="Hız (mil/saat)", ylabel="CDF")
Örneklem, asıl verilerin dağılımını izler. Algoritmanın nasıl çalıştığını anlamak için şu soruyu ele alalım: Koşu hızları evreninden rastgele bir örneklem seçtiğimizi ve örneklemdeki hızların yüzdelik sıralarını bulduğumuzu varsayalım. Şimdi bu yüzdelik sıraların CDF’sini hesapladığımızı düşünelim. Sizce nasıl görünür?
Bakalım. Ürettiğimiz örneklemin yüzdelik sıraları şunlardır.
percentile_ranks = cdf_speeds(sample) * 100
Yüzdelik sıraların CDF’si şöyledir.
cdf_percentile_rank = Cdf.from_seq(percentile_ranks)
cdf_percentile_rank.plot()
decorate(xlabel="Yüzdelik sıra", ylabel="CDF")
Yüzdelik sıraların CDF’si 0 ile 1 arasında düz bir çizgiye yakındır. Bu sonuç mantıklıdır; çünkü herhangi bir dağılımda yüzdelik sırası %50’den küçük olanların oranı 0,5, %90’dan küçük olanların oranı 0,9’dur ve bu şekilde devam eder.
Cdf bu algoritmayı kullanan bir sample yöntemi sunar; dolayısıyla bir örneklemi şöyle de üretebiliriz.
sample = cdf_speeds.sample(1001)
4.6. Terimler#
yüzdelik sıra: Bir dağılımda belirli bir nicelikten küçük veya ona eşit değerlerin yüzdesi.
yüzdelik: Bir dağılımda belirli bir yüzdelik sırayla ilişkili değer.
kümülatif dağılım fonksiyonu (CDF): Bir değeri, dağılımda o değerden küçük veya ona eşit değerlerin oranıyla eşleyen fonksiyon.
kantil: Bir dağılımda belirli bir kümülatif olasılığa karşılık gelen değer.
dayanıklı: Bir istatistik aşırı değerlerden veya aykırı değerlerden daha az etkileniyorsa dayanıklıdır.
çeyrekler arası açıklık (IQR): Dağılımın yayılımını ölçmek için kullanılan, 75. ve 25. yüzdelikler arasındaki fark.
4.7. Alıştırmalar#
4.7.1. Alıştırma 4.1#
Doğduğunuzda kaç kiloydunuz? Bilmiyorsanız annenizi veya bilen başka birini arayın. Kimse bilmiyorsa bu alıştırmada benim doğum ağırlığım olan 8,5 libreyi kullanabilirsiniz.
NSFG verilerini (bütün canlı doğumları) kullanarak doğum ağırlıklarının dağılımını hesaplayın ve yüzdelik sıranızı bulun. İlk çocuk olarak doğduysanız ilk bebeklerin dağılımındaki, aksi hâlde diğerlerinin dağılımındaki yüzdelik sıranızı bulun. 90. yüzdelik veya üzerindeyseniz annenizi yeniden arayıp özür dileyin.
from nsfg import get_nsfg_groups
live, firsts, others = get_nsfg_groups()
4.7.2. Alıştırma 4.2#
NSFG veri kümesindeki canlı doğumlar için babysex sütunu bebeğin erkek mi kız mı olduğunu gösterir.
Erkek ve kız bebeklerin satırlarını seçmek için query kullanabiliriz.
male = live.query("babysex == 1")
female = live.query("babysex == 2")
len(male), len(female)
(4641, 4500)
Erkek ve kız bebeklerin doğum ağırlığı dağılımlarını temsil eden Cdf nesneleri oluşturun.
İki CDF’yi çizin.
Dağılımların biçimleri ve konumları arasında ne fark var?
Bir erkek bebek 8,5 libre ağırlığındaysa yüzdelik sırası nedir? Aynı yüzdelik sıradaki bir kız bebeğin ağırlığı nedir?
4.7.3. Alıştırma 4.3#
NSFG gebelik verilerinden agepreg sütununu seçin ve her gebelikte gebe kalma yaşının dağılımını temsil eden bir Cdf oluşturun.
20’den küçük veya 20’ye eşit yaşların yüzdesiyle 30’dan küçük veya 30’a eşit yaşların yüzdesini CDF kullanarak hesaplayın.
Bu sonuçlarla 20 ile 30 yaş arasındaki yüzdeyi hesaplayın.
from nsfg import read_fem_preg
preg = read_fem_preg()
4.7.4. Alıştırma 4.4#
Aşağıda bu bölümde daha önce anlatılan James Joyce Ramble yarışını tamamlayan kişilerin koşu hızları yer alıyor.
speeds = results["MPH"].values
Bu hızların dağılımını temsil eden bir Cdf oluşturup medyanı, IQR’yi ve çeyreklik çarpıklığını hesaplayın.
Dağılım sola mı, sağa mı çarpıktır?
4.7.5. Alıştırma 4.5#
np.random.random tarafından üretilen sayıların 0 ile 1 arasında tekdüze olması beklenir; bu da bir örneklemin CDF’sinin düz çizgi olması gerektiği anlamına gelir.
Bunun doğru olup olmadığına bakalım.
Aşağıda 1.001 sayıdan oluşan bir örneklem var. Bu örneklemin CDF’sini çizin. Düz çizgiye benziyor mu?
t = np.random.random(1001)
Orijinal eser: Think Stats: Exploratory Data Analysis in Python, 3rd Edition
Telif hakkı 2024 Allen B. Downey
Türkçe çeviri: ThinkStatsTr
Kod lisansı: MIT License
Metin lisansı: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International