Python ile Örnekleme ve Nokta Tahminleri

Enes Eren
11 min readApr 1, 2023

Bir ülkenin nüfusunu sayma problemini ele alalım. Bu problem genellikle nüfus sayımı ile çözülmektedir. Yani ülkedeki her bir haneye bir görevli girer ve hane nüfusunun kaydını tutar. Bu oldukça maliyetli ve uzun bir süreçtir. Üstelik günümüz dünyasında bile.

1786'da Pierre Simon Laplace adındaki bir biliminsanı bu büyük nüfus sayımı maliyetinden kurtulmak için bir popülasyon tahmininin yapılmasının çok daha hızlı ve ucuz olabileceğini düşündü. Yani her bir hanenin kaydını tutmak yerine belirli sayıda bir hanenin kaydını tutup istatistik yardımıyla bütün popülasyonu tahmin etmeyi öne sürdü.

Bir altküme (örneklem) ile çalışarak bütün popülasyonu tahmin etmeye örnekleme denir.

Elimizde bir Spotify veri seti bulunmaktadır. Bu veri seti yaklaşık 40.000 kadar şarkı içermektedir. Bu şarkıların isimleri, sanatçısı ve çıkış yılı gibi bilgiler bulunmaktadır. Elimizdeki bu veri seti (örneklem) ile bütün spotify kullanıcılar ile ilgili tahminlerde bulunacağız.

Paketleri ve Veriyi İçe Aktaralım

import pandas as pd
import numpy as np

spotify_population = pd.read_csv('spotify_population.csv')
attrition_pop = pd.read_csv('attrition_pop.csv')

Örneklem

Pandas paketinin sample metodu ile bir veri setinden örneklem oluşturabiliriz.

spotify_sample = spotify_population.sample(n=1000)

print(spotify_sample)
           acousticness                           artists  danceability  duration_ms  duration_minutes  ...  release_date  speechiness    tempo  valence    year
4132 3.590e-02 ['Natanael Cano'] 0.607 115793.0 1.930 ... 2020-06-12 0.047 127.619 0.434 2020.0
15898 3.800e-03 ['Imagine Dragons'] 0.685 206707.0 3.445 ... 2012-09-04 0.042 99.983 0.570 2012.0
31344 6.910e-04 ['*NSYNC'] 0.665 228907.0 3.815 ... 2000-03-21 0.058 111.045 0.629 2000.0
9211 6.850e-01 ['Hammock'] 0.114 308907.0 5.148 ... 2008-08-06 0.046 77.945 0.040 2008.0
9611 2.260e-03 ['Motionless In White'] 0.245 236973.0 3.950 ... 2012-11-13 0.191 135.023 0.171 2012.0
... ... ... ... ... ... ... ... ... ... ... ...
6206 5.410e-01 ['Turbo', 'Gunna', 'Young Thug'] 0.787 217728.0 3.629 ... 2020-04-02 0.268 91.344 0.327 2020.0
38218 4.510e-02 ['Mayday Parade'] 0.261 276173.0 4.603 ... 2007-07-10 0.032 139.242 0.329 2007.0
27788 2.490e-01 ['The Dramatics'] 0.641 214973.0 3.583 ... 2007-01-01 0.118 152.939 0.914 2007.0
30031 1.700e-02 ['Lil Wayne', 'Babyface'] 0.596 265240.0 4.421 ... 2008-06-10 0.075 94.197 0.693 2008.0
18515 8.720e-01 ['$NOT', 'SUS Valentino'] 0.566 114547.0 1.909 ... 2018-03-25 0.290 87.020 0.552 2018.0

[1000 rows x 20 columns]

Burada spotify_population veri setinden 1000 elemanlı bir örneklem oluşturduk. Asıl veri setimiz 40.000 satır veri içermekteydi. Yani bu 40.000 satır veri içerisinden rastgele 1000 satır veriyi seçtik.

Örneğin bu örneklem ve asıl veri setimizdeki şarkıların ortalama dinlenme süresine bakalım.

mean_dur_pop = spotify_population['duration_minutes'].mean()

mean_dur_samp = spotify_sample['duration_minutes'].mean()

print(mean_dur_pop)
print(mean_dur_samp)
    3.8521519140900073
3.8277472833333333

Gördüldüğü üzere oluşturduğumuz örneklem asıl veri setimiz ile oldukça benzerlik gösteriyor. Ama tabii ki de asıl veri seti ile hiçbir zaman aynı olamaz.

Veri setinde acousticness (akustiklik) adında bir sütun bulunmaktadır. Bu değerler şarkının ne kadar akustik olduğu ile ilgili bize bilgi vermektedir.

Bu değerlerin dağılımına göz atarsak bütün şarkıların arasında ne kadar akustik şarkı var görebiliriz.

spotify_population['acousticness'].hist(bins=np.arange(0, 1.01, 0.01))
plt.show()

Histogram aralıklarını 0 ve 1 arasında belirliyoruz. 1 tam akustik şarkılara denk gelmektedir.

Görüldüğü üzere bütün şarkılar arasında akustik olmayan şarkıların oranı oldukça fazla.

Peki bu veri setinden 1000 elemanlı yeni bir örneklem oluşturalım.

spotify_mysterious_sample = spotify_population.sample(n=1000)

Bu örneklemin akustiklik dağılımına bakalım.

spotify_mysterious_sample['acousticness'].hist(bins=np.arange(0, 1.01, 0.01))
plt.show()

Eğer örneklemden bir genelleme yapacak olursak Spotify’daki bütün şarkılar akustiktir dememiz gerekir. Ancak bu oldukça yanlış bir bulgu olurdu. Çünkü veri setinden oluşturduğumuz 1000 elemanlı örneklem, 40.000 elemanlı veri setindeki bütün akustik şarkılara denk gelmiş. Burada örneklemin güvenilirliği oldukça önemli hale gelmektedir.

Sözde Rassal Sayı Üretici (Pseudo-random number generation)

Elemanları arasında kolay kolay ilişki kurulamayacak bir sayı dizisi üreten algoritma türlerine verilen genel isimdir. Kullanışı oldukça ucuz maliyetli ve hızlıdır. Bir sonraki rassal sayıyı bir önceki rassal sayıdan oluşturur. İlk rassal sayı bir seed’den oluşur.

Örneğin Numpy paketini kullanarak bir rassal sayı dizisi oluşturalım.

uniforms = np.random.uniform(low=-3, high=3, size=5000)

normals = np.random.normal(loc=5, scale=2, size=5000)

print(uniforms)
print(normals)

Burada ilk önce bir sürekli dağılım üzerinden daha sonra normal dağılım üzerinden iki farklı rassal sayı dizisi oluşturduk.

[-1.36665743 -1.48457608 -0.41216497 ... -1.85940745  2.8888604 0.29751209]
[3.44069307 7.74024633 6.09466135 ... 7.20893084 7.47265844 4.65574985]

Bu dizilerin dağılımlarına bakalım.

Bu histogram bir sürekli dağılım üzerinden oluşturulmuş bir dizidir.

Bu histogram ise bir normal dağılım üzerinden oluşturulmuş bir dizidir. Burada farketmemiz gereken şey her ikisi dizi de rastgele sayılar içermektedir. Ancak dağılımları belirlediğimiz dağılıma göre gerçekleşmektedir.

Rassal Örnekleme

Rassal örnekleme pandas paketinin sample metodu ile yapılabilir. Ayrıca rassallıklarda aynı sonucu tekrar elde etmek için seed adında bir metod kullanılırz. Bu metod kendisine verilen anahtara göre farklı örneklemler oluşturur. Aynı seed birçok kez rassal örneklem oluşturduğunuzda aynı sonucu alabilirisiniz.

attrition_samp = attrition_pop.sample(n=70, random_state=18900217)

print(attrition_samp)

Yukarıdaki kodu ne kadar çalıştırırsak çalıştıralım random_state’i yani seedi değiştirmediğimiz sürece aynı sonucu alacağız.

Age  Attrition     BusinessTravel  DailyRate            Department  ...  WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
274 26 0.0 Travel_Frequently 921 Research_Development ... Better 5 3 1 3
524 32 0.0 Travel_Frequently 1005 Research_Development ... Good 7 7 3 6
59 22 1.0 Travel_Frequently 1256 Research_Development ... Better 0 0 0 0
1247 41 0.0 Travel_Rarely 263 Research_Development ... Better 18 13 2 17
799 29 0.0 Travel_Rarely 1252 Research_Development ... Better 10 7 0 7
... ... ... ... ... ... ... ... ... ... ... ...
661 54 0.0 Travel_Rarely 376 Research_Development ... Better 5 3 1 4
1322 51 0.0 Travel_Rarely 684 Research_Development ... Better 20 18 15 15
308 34 1.0 Non-Travel 967 Research_Development ... Better 5 2 3 0
710 34 0.0 Travel_Rarely 1480 Sales ... Better 5 3 1 0
1288 40 0.0 Travel_Rarely 898 Human_Resources ... Better 21 7 7 7

[70 rows x 31 columns]

Sistematik Örnekleme

Sistematik örnekleme rassal olmayan örneklemedir. Sistematik şekilde aynı elemanları seçer.

sample_size = 70

pop_size = len(attrition_pop)

interval = pop_size // sample_size

Örneğin burada 1470 elemanlı bir veri setinden 70 eleman seçmek istiyoruz. Bunu 1470 / 70 = 21'den yani her 21 satırda bir satır seçerek yapabiliriz.

attrition_sys_samp = attrition_pop.iloc[::interval]

print(attrition_sys_samp)
      Age  Attrition BusinessTravel  DailyRate            Department  ...  WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
0 21 0.0 Travel_Rarely 391 Research_Development ... Better 0 0 0 0
21 19 0.0 Travel_Rarely 1181 Research_Development ... Better 1 0 0 0
42 45 0.0 Travel_Rarely 252 Research_Development ... Better 1 0 0 0
63 23 0.0 Travel_Rarely 373 Research_Development ... Better 1 0 0 1
84 30 1.0 Travel_Rarely 945 Sales ... Good 1 0 0 0
... ... ... ... ... ... ... ... ... ... ... ...
1365 48 0.0 Travel_Rarely 715 Research_Development ... Best 1 0 0 0
1386 48 0.0 Travel_Rarely 1355 Research_Development ... Better 15 11 4 8
1407 50 0.0 Travel_Rarely 989 Research_Development ... Good 27 3 13 8
1428 50 0.0 Non-Travel 881 Research_Development ... Better 31 6 14 7
1449 52 0.0 Travel_Rarely 699 Research_Development ... Better 33 18 11 9

[70 rows x 31 columns]

Burada örneklemi rassal olarak değil düzenli aralıklar ile seçmiş olduk.

Ancak sistematik örneklemede eğer veri sıralanmışsa dağılımında belirli bir düzen görmemiz mümkün. Bu da seçilen örneklemin tüm veri setini değil belirli bir kısmını yansıttığını gösterir.

attrition_pop_id = attrition_pop.reset_index()

attrition_pop_id.plot(x="index", y="YearsAtCompany", kind="scatter")
plt.show()

Bu yüzden sistematik örnekleme yaparken verinin sıralanmamış olduğundan emin olun.

Tabakalı Örnekleme

Tabakalı örnekleme yöntemini diğer olasılık örnekleme yöntemlerden ayıran özelliği anakütlenin içindeki bütün elamanlar belli özelliklere göre kendi içlerinde birbirlerine benzeyen birkaç gruptan, tabakadan oluştuklarıdır.

Popülasyonu alt gruplara bölüp her bir alt gruba rassal örnekleme uygulanır.

Veri setindeki tabakaların (grupların) oranlarına (büyüklüğüne) bakalım.

education_counts_pop = attrition_pop['Education'].value_counts(normalize=True)
print(education_counts_pop)
Bachelor         0.389
Master 0.271
College 0.192
Below_College 0.116
Doctor 0.033
Name: Education, dtype: float64

Her bir tabakanın %40'ı için örnekleme yaparsak;

attrition_strat = attrition_pop.groupby('Education')\
.sample(frac=0.4, random_state=2022)

education_counts_strat = attrition_strat['Education'].value_counts(normalize=True)

print(education_counts_strat)
    Bachelor         0.389
Master 0.270
College 0.192
Below_College 0.116
Doctor 0.032
Name: Education, dtype: float64

Ağırlıklı Örnekleme

attrition_pop['YearsAtCompany'].hist(bins=np.arange(0, 41, 1))
plt.show()

Histogram ile veri setindeki değişkenin dağılımına bakalım.

attrition_weight = attrition_pop.sample(n=400, weights="YearsAtCompany")

400 elemanlı bir örneklem oluşturalım ve ağırlıklarını belirleyelim.

Örneklemin dağılımına bakacak olursak;

attrition_weight['YearsAtCompany'].hist(bins=np.arange(0, 41, 1))
plt.show()

Küme Örneklemesi

Alt grupları seçmek için rassal örnekleme kullanılır ve bu alt gruplar içerisinde rassal örnekleme yapılır.

Veri setindeki JonRole değişkeninden özel değerleri rassal olarak seçelim.

job_roles_pop = list(attrition_pop['JobRole'].unique())

job_roles_samp = random.sample(job_roles_pop, k=4)

print(job_roles_samp)
['Research_Director', 'Research_Scientist', 'Human_Resources', 'Manager'

Burada bütün veri setindeki özel iş unvanlarını bulduk ve aralarından 4 tanesini rassal olarak seçtik.

Veri setini bu özel değerlere göre filtreleyelim.

jobrole_condition = attrition_pop['JobRole'].isin(job_roles_samp)
attrition_filtered = attrition_pop[jobrole_condition]

print(attrition_filtered)
      Age  Attrition BusinessTravel  DailyRate            Department  ...  WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
0 21 0.0 Travel_Rarely 391 Research_Development ... Better 0 0 0 0
5 27 0.0 Non-Travel 443 Research_Development ... Good 0 0 0 0
6 18 0.0 Non-Travel 287 Research_Development ... Better 0 0 0 0
10 18 0.0 Non-Travel 1431 Research_Development ... Bad 0 0 0 0
17 31 0.0 Travel_Rarely 1082 Research_Development ... Better 1 1 1 0
... ... ... ... ... ... ... ... ... ... ... ...
1462 54 0.0 Travel_Rarely 584 Research_Development ... Better 10 8 4 7
1464 55 0.0 Travel_Rarely 452 Research_Development ... Better 36 10 4 13
1465 55 0.0 Travel_Rarely 1117 Sales ... Better 10 9 7 7
1466 58 0.0 Non-Travel 350 Sales ... Good 16 9 14 14
1469 58 1.0 Travel_Rarely 286 Research_Development ... Better 31 15 13 8

[526 rows x 31 columns]

Burada veri setimizi sadece bu seçtiğimiz değerleri içerecek şekilde seçtik.

Kullanılmayan diğer kategorileri kaldıralım ve bu yeni oluşturuduğumuz popülasyondan rassal örnekleme yapalım.

attrition_filtered['JobRole'] = attrition_filtered['JobRole'].cat.remove_unused_categories()

attrition_clust = attrition_filtered.groupby("JobRole")\
.sample(n=10, random_state=2022)

print(attrition_clust)
          Age  Attrition     BusinessTravel  DailyRate            Department  ...  WorkLifeBalance YearsAtCompany YearsInCurrentRole YearsSinceLastPromotion YearsWithCurrManager
1348 44 1.0 Travel_Rarely 1376 Human_Resources ... Better 20 6 3 6
886 41 0.0 Non-Travel 552 Human_Resources ... Better 3 2 1 2
983 39 0.0 Travel_Rarely 141 Human_Resources ... Bad 8 3 3 6
88 27 1.0 Travel_Frequently 1337 Human_Resources ... Better 1 0 0 0
189 34 0.0 Travel_Rarely 829 Human_Resources ... Bad 3 2 0 2
160 24 0.0 Travel_Frequently 897 Human_Resources ... Better 2 2 2 1
839 46 0.0 Travel_Rarely 991 Human_Resources ... Best 7 6 5 7
966 30 0.0 Travel_Rarely 1240 Human_Resources ... Bad 11 9 4 7
162 28 0.0 Non-Travel 280 Human_Resources ... Better 3 2 2 2
1231 37 0.0 Travel_Rarely 1239 Human_Resources ... Good 10 0 4 7
1375 44 0.0 Travel_Rarely 1315 Research_Development ... Best 2 2 0 1
1462 54 0.0 Travel_Rarely 584 Research_Development ... Better 10 8 4 7
1316 45 0.0 Travel_Frequently 364 Research_Development ... Better 0 0 0 0
1356 48 0.0 Travel_Frequently 117 Research_Development ... Better 22 17 4 7
1387 48 0.0 Non-Travel 1262 Research_Development ... Good 5 4 2 1
1321 54 0.0 Non-Travel 142 Human_Resources ... Better 5 3 4 4
1266 50 0.0 Travel_Rarely 1452 Research_Development ... Better 5 4 4 4
1330 46 0.0 Travel_Rarely 406 Sales ... Better 12 9 4 9
1052 59 0.0 Travel_Rarely 1089 Sales ... Bad 6 4 0 4
1449 52 0.0 Travel_Rarely 699 Research_Development ... Better 33 18 11 9
1439 58 0.0 Travel_Rarely 1055 Research_Development ... Better 9 8 1 5
1339 58 0.0 Travel_Frequently 1216 Research_Development ... Better 2 2 2 2
1426 49 0.0 Travel_Rarely 1245 Research_Development ... Better 31 9 0 9
1415 48 0.0 Travel_Rarely 1224 Research_Development ... Better 22 10 12 9
1322 51 0.0 Travel_Rarely 684 Research_Development ... Better 20 18 15 15
1284 40 0.0 Travel_Rarely 1308 Research_Development ... Best 20 7 4 9
1149 37 0.0 Travel_Rarely 161 Research_Development ... Better 16 11 6 8
1126 42 0.0 Travel_Rarely 810 Research_Development ... Better 1 0 0 0
1374 46 0.0 Travel_Rarely 1009 Research_Development ... Bad 3 2 0 1
1050 33 0.0 Travel_Rarely 213 Research_Development ... Best 13 9 3 7
86 26 0.0 Travel_Rarely 482 Research_Development ... Good 1 0 1 0
930 52 1.0 Travel_Rarely 723 Research_Development ... Good 8 2 7 7
860 37 0.0 Travel_Rarely 674 Research_Development ... Better 10 8 3 7
36 20 1.0 Travel_Rarely 1362 Research_Development ... Better 1 0 1 1
997 32 0.0 Travel_Rarely 824 Research_Development ... Better 7 1 2 5
1358 45 0.0 Travel_Rarely 1339 Research_Development ... Better 1 0 0 0
993 41 0.0 Travel_Frequently 1200 Research_Development ... Good 6 2 3 3
421 34 0.0 Travel_Rarely 181 Research_Development ... Better 5 0 1 2
789 28 1.0 Travel_Rarely 654 Research_Development ... Better 7 7 3 7
94 36 1.0 Travel_Rarely 318 Research_Development ... Good 1 0 0 0

[40 rows x 31 columns]

Bağıl hata

Aldığınız örneklemin boyutu, nokta tahminlerinin karşılık gelen popülasyon parametresini ne kadar doğru yansıttığını etkiler. Örneğin, bir örneklem ortalaması hesaplarken, bunun popülasyon ortalamasına yakın olmasını istersiniz.

attrition_srs50 = attrition_pop.sample(n=50, random_state=2022)

mean_attrition_srs50 = attrition_srs50['Attrition'].mean()

rel_error_pct50 = 100 * abs(mean_attrition_pop - mean_attrition_srs50) / mean_attrition_pop

print(rel_error_pct50)
62.78481012658227

Burada 50 elemanlı bir örneklemin ortalamasının popülasyon ortalamasına göre ne kadar hatalı olduğunu görüyoruz.

attrition_srs100 = attrition_pop.sample(n=100, random_state=2022)

mean_attrition_srs100 = attrition_srs100['Attrition'].mean()

rel_error_pct100 = 100 * abs(mean_attrition_pop - mean_attrition_srs100) / mean_attrition_pop

print(rel_error_pct100)
6.962025316455695

Burada ise 100 elemanlı bir örneklemin popülasyon ortalamasına göre ne kadar hatalı olduğunu görüyoruz

Örneklemin eleman sayısı arttıkça örneklemin ortalaması popülasyon ortalamasın yaklaşır ve bağıl hata oranı düşer.

Örneklem Dağılımı

Ortalama gibi bir nokta tahminini hesapladığınızda, hesapladığınız değer, örnekleme dahil edilen satırlara bağlıdır. Yani bir popülasyondan rassal olarak her farklı örneklem oluşturduğunuzda bunlar dağılımı birbirinden farklılık gösterir.

mean_attritions = []

for i in range(500):
mean_attritions.append(
attrition_pop.sample(n=60)['Attrition'].mean()
)

plt.hist(mean_attritions, bins=16)
plt.show()

Örneğin burada attrition_pop veri setinden 500 kez 60 elemanlı bir örneklem oluşturuyoruz ve bu 60 elemanlı 500 örneklemden elde ettiğimiz 500 örneklem ortalamasının dağılımına bakıyoruz.

Kesin Örneklem Dağılımı

İlgilendiğiniz nokta tahmininin (örneklem istatistiğinin) nasıl değiştiğini ölçmek için, alabileceği tüm olası değerleri sıklığıyla birlikte bilmeniz gerekir.

Örneğin 6 kenarlı 5 tane zarımız olsun.

dice = expand_grid(
{'die1': [1, 2, 3, 4, 5, 6],
'die2': [1, 2, 3, 4, 5, 6],
'die3': [1, 2, 3, 4, 5, 6],
'die4': [1, 2, 3, 4, 5, 6],
'die5': [1, 2, 3, 4, 5, 6]
})

expand_grid fonksiyonu bize bu 5 zar ile olabilecek tüm sonuçları bize getirir.

Bu zarların ortalamasını alalım.

dice['mean_roll'] = (dice['die1'] + dice['die2'] + 
dice['die3'] + dice['die4'] +
dice['die5']) / 5
dice['mean_roll'] = dice['mean_roll'].astype('category')

Dağılımına bakalım.

dice['mean_roll'].value_counts(sort=False).plot(kind="bar")
plt.show()

Kesin örneklem dağılımı, ilgilendiğiniz nokta tahmininin olası tüm varyasyonlarını gösterir.

Kesin örneklem dağılımı, yalnızca popülasyonun ne olduğunu biliyorsanız ve problemler hesaplanacak kadar küçük ve basitse hesaplanabilir. Aksi takdirde, yaklaşık örnekleme dağılımı kullanılmalıdır.

Yeniden Örnekleme

Popülasyon hakkında çıkarımlar yapabilmek için bir veri setinden yerine koyarak tekrar tekrar aynı büyüklükte örneklemler oluşturmaya yeniden örnekleme (resampling) denir.

Örneğin önceden oluşturduğumuz spotify_sample örnekleminden bir tekrar yerleştirme ile bir yeniden örnekleme oluşturalım. Daha sonra bu örneklemin danceability değişkeninin ortalamasına bakalım.

spotify_1_resample = spotify_sample.sample(frac=1, replace=True)

mean_danceability_1 = np.mean(spotify_1_resample['danceability'])

print(mean_danceability_1)
0.5910226305934319

danceability değişkeni bize şarkıların ortalama olarak dans edilebilirlik oranını vermektedir.

Bunu 1000 kez tekrarlayalım ve dağılımına bakalım.

mean_danceability_1000 = []
for i in range(1000):
mean_danceability_1000.append(
np.mean(spotify_sample.sample(frac=1, replace=True)['danceability'])
)

plt.hist(mean_danceability_1000)
plt.show()

Spotify şarkılarının daha küçük bir örnekleminden, popülasyondaki ortalama dans edilebilirlik istatistiğini tahmin edebiliriz. Bir istatistik dağılımımız olduğundan, tahminimizin ne kadar doğru olduğunu bile ölçebiliriz.

Son

Beni Linkedin ve Github üzerinden takip edebilirsiniz.

--

--