Verileri KMeans kümeleme modeli ve doğrusal regresyon modellerine uydurarak sezon başına MLB galibiyetlerini tahmin etmeye yönelik bir scikit-learn eğitimi.
Python programlama dili, birden fazla paketiyle veri bilimi ve öngörüsel analitik için harika bir seçenektir; veri analiz ihtiyaçlarınızın çoğunu karşılar. Python'da makine öğrenimi için Scikit-learn (sklearn) mükemmel bir seçenektir ve NumPy, SciPy ve Matplotlib (sırasıyla N-boyutlu diziler, bilimsel hesaplama ve veri görselleştirme) üzerine kuruludur.
Bu eğitimde, sqlite3 ile bir veritabanından verileri nasıl kolayca içe aktarabileceğinizi, pandas ve matplotlib ile verinizi nasıl keşfedip veri kalitesini iyileştirebileceğinizi ve ardından Scikit-Learn paketini kullanarak verinizden nasıl geçerli içgörüler çıkarabileceğinizi göreceksiniz.
Bölüm 1: MLB Takımlarının Sezon Başına Galibiyetlerini Tahmin Etme
Bu projede, sklearn içindeki çeşitli makine öğrenimi modellerini, bir Major League Baseball takımının, o sezonki takım istatistiklerine ve diğer değişkenlere dayanarak kaç maç kazandığını tahmin etmek için deneyeceksiniz. Eğer bahis oynayan biri olsaydım (ve kesinlikle öyleyim), geçmiş sezonların tarihsel verilerini kullanarak yaklaşan sezonu öngören bir model kurabilirdim. Verilerin zaman serisi doğası göz önüne alındığında, önceki beş yıldaki ortalama galibiyet gibi göstergeler ve benzeri etkenler üreterek yüksek doğrulukta bir model oluşturabilirsiniz. Ancak bu, bu eğitimin kapsamı dışındadır ve her satırı bağımsız olarak ele alacaksınız. Verilerimizin her satırı belirli bir yıl için tek bir takımdan oluşacaktır.
Sean Lahman bu verileri web sitesinde derlemiş ve burada bir sqlite veritabanına dönüştürülmüştür.
Veri İçe Aktarma
Verileri, sqlite3 paketini kullanarak bir sqlite veritabanını sorgulayıp sonuçları pandas ile bir DataFrame'e çevirerek okuyacaksınız. Verileriniz, yalnızca hâlen aktif olan modern takımları ve takımın 150 veya daha fazla maç oynadığı yılları içerecek şekilde filtrelenecektir.
Önce “lahman2016.sqlite” dosyasını indirin (buradan). Ardından, Pandas'ı yükleyin ve verimlilik için pd olarak yeniden adlandırın. pd'nin Pandas için yaygın bir takma ad olduğunu hatırlıyor olabilirsiniz. Son olarak, sqlite3'ü yükleyin ve veritabanına şu şekilde bağlanın:
# import`pandas` and `sqlite3`import pandas as pdimport sqlite3# Connecting to SQLite Databaseconn = sqlite3.connect('lahman2016.sqlite')Altyapı:
Sonraki adımda bir sorgu yazacak, çalıştıracak ve sonuçları çekeceksiniz.
# Querying Database for all seasons where a team played 150 or more games and is still active today. query ='''select * from Teams inner join TeamsFranchiseson Teams.franchID == TeamsFranchises.franchIDwhere Teams.G >= 150 and TeamsFranchises.active == 'Y';'''# Creating dataframe from query.Teams = conn.execute(query).fetchall()Altyapı:
pandas kullanarak sonuçları bir DataFrame'e dönüştürür ve head() yöntemiyle ilk 5 satırı yazdırırsınız:
# Convert `Teams` to DataFrame
teams_df = pd.DataFrame(_____)
# Print out first 5 rows
print(_______________)
Sütunların her biri, belirli bir takım ve yıla ilişkin veriler içerir. Daha önemli değişkenlerden bazıları aşağıda listelenmiştir. Değişkenlerin tam listesine buradan ulaşabilirsiniz.
SHO - Rakibe sayı vermeden bitirilen maçlar (shutout)
SV - Kurtarışlar
IPOuts - Atılan out sayısı (atıcının oynadığı inning x 3)
HA - İzin verilen isabetler
HRA - İzin verilen home run'lar
BBA - İzin verilen yürüyüşler
SOA - Atıcıların strikeout'ları
E - Hatalar
DP - Çifte oyunlar
FP - Alan savunma yüzdesi
name - Takımın tam adı
Beyzbola çok aşina olmayanlar için, oyunun nasıl işlediğine ve bazı değişkenlere değinen kısa bir açıklama:
Beyzbol, her biri dokuz oyuncudan oluşan iki takım (name veya teamID ile veride bulacaksınız) arasında oynanır. Bu iki takım sırayla hücum (batting) ve savunma yapar. Hücum yapan takım, savunmadaki takımın atıcısının attığı topa vurarak ve ardından saat yönünün tersine dört bazı (birinci, ikinci, üçüncü ve ev plağı) dolaşarak sayı (run) elde etmeye çalışır. Savunma yapan takım ise çeşitli şekillerde vurucuyu veya koşucuyu out ederek sayıyı engellemeye çalışır ve bir oyuncu bazları dolaşıp ev plakasına döndüğünde bir sayı (R) kaydedilir. Hücum takımındaki bir oyuncu güvenle baza ulaştığında, takım arkadaşlarının vuruş sırası sırasında isabet (H), çalıntı baz (SB) ya da diğer yollarla sonraki bazlara ilerlemeye çalışır.
Takımlar, savunma yapan takım üç out kaydettiğinde hücum ve savunma rollerini değiştirir. Konuk takımla başlayan, her iki takımın da birer hücum hakkı kullandığı bölüm bir inning oluşturur. Oyun dokuz inning'den oluşur ve oyun sonunda daha fazla sayısı olan takım kazanır. Beyzbolda oyun saati yoktur ve çoğu maç dokuzuncu inning'de bitse de, maç dokuz inning sonunda berabere ise uzatmalara gider ve bir takım uzatma inning'inin sonunda öne geçene kadar süresiz olarak devam eder.
# Adding column names to dataframe
cols = ['yearID','lgID','teamID','franchID','divID','Rank','G','Ghome','W','L','DivWin','WCWin','LgWin','WSWin','R','AB','H','2B','3B','HR','BB','SO','SB','CS','HBP','SF','RA','ER','ERA','CG','SHO','SV','IPouts','HA','HRA','BBA','SOA','E','DP','FP','name','park','attendance','BPF','PPF','teamIDBR','teamIDlahman45','teamIDretro','franchID','franchName','active','NAassoc']
teams_df.columns = ____
# Print the first rows of `teams_df`
print(______________)
# Print the length of `teams_df`
print(len(________))
len() işlevi, kaç satırla uğraştığınızı bildirir: 2.287, çalışmak için çok büyük bir veri noktası sayısı değildir; umarız çok fazla null değer yoktur.
Veri kalitesini değerlendirmeden önce, gerekli olmayan veya hedef sütundan (Wins) türetilen sütunları eleyelim. Bu noktada, üzerinde çalıştığınız veriye dair bilgi sahibi olmak çok değerli hale gelir. Üzerinde çalıştığınız veriyi tanımıyorsanız, kodlama ya da istatistik bilgisi ne kadar iyi olursa olsun fark etmez. Ömür boyu bir beyzbol hayranı olmak bu projede bana kesinlikle yardımcı oldu.
# Dropping your unnecesary column variables.
drop_cols = ['lgID','franchID','divID','Rank','Ghome','L','DivWin','WCWin','LgWin','WSWin','SF','name','park','attendance','BPF','PPF','teamIDBR','teamIDlahman45','teamIDretro','franchID','franchName','active','NAassoc']
df = teams_df.drop(drop_cols, axis=1)
# Print out first rows of `df`
print(_________)
Yukarıda okuduğunuz gibi, null değerler veri kalitesini etkiler ve bu da makine öğrenimi algoritmalarında sorunlara yol açabilir.
Bu yüzden şimdi bunları kaldıracaksınız. Null değerleri ortadan kaldırmanın birkaç yolu vardır, ancak önce her sütun için null değer sayısını görüntülemek ve onlarla nasıl başa çıkılacağına karar vermek daha iyi bir fikir olabilir.
# Print out null values of all columns of `df`
print(_________.sum(axis=0).tolist())
Burada bir ödünleşim göreceksiniz: Temiz veriye ihtiyacınız var, ancak elinizde gözden çıkaracak çok veri de yok. İki sütunda nispeten az sayıda null değer var. SO (Strike Out) sütununda 110, DP (Double Play) sütununda 22 null değer bulunuyor. İki sütunda ise nispeten çok sayıda null değer var. CS (Çalarken Yakalanma) sütununda 419, HBP (Saha içi atışla vurulma) sütununda 1777 null değer var.
Az sayıda null değeri olan sütunlardaki satırları elimine ederseniz, verinin yüzde beşinden biraz fazlasını kaybedersiniz. Galibiyetleri tahmin etmeye çalıştığınız için, atılan ve yenilen sayılar hedefle yüksek korelasyona sahiptir. Bu sütunlardaki verilerin oldukça doğru olmasını istersiniz.
Strike out (SO) ve çifte oyun (DP) o kadar kritik değildir.
Satırları tutup null değerleri her sütunun medyan değeriyle fillna() yöntemiyle doldurmanın daha iyi olacağını düşünüyorum. Çalarken yakalanma (CS) ve saha içi atışla vurulma (HBP) da çok önemli değişkenler değil. Bu sütunlarda çok fazla null değer olduğundan, bu sütunları tamamen kaldırmak en iyisi.
# Eliminating columns with null values
df = df.drop(['CS','HBP'], axis=1)
# Filling null values
df['SO'] = df['SO'].fillna(df['SO'].median())
df['DP'] = df['DP'].fillna(df['DP'].median())
# Print out null values of all columns of `df`
print(df.isnull().sum(axis=0).tolist())
Veriyi Keşfetme ve Görselleştirme
Artık verinizi temizlediğinize göre, biraz keşif yapabilirsiniz. Birkaç basit görselleştirme ile veri kümesi hakkında daha iyi bir fikir edinebilirsiniz. matplotlib, veri görselleştirme için mükemmel bir kütüphanedir.
matplotlib.pyplot'ı içe aktarır ve verimlilik için plt olarak yeniden adlandırırsınız. Bir Jupyter defteri ile çalışıyorsanız, %matplotlib inline sihrini kullanmanız gerekir.
Galibiyetlerin dağılımını görebilmek için hedef sütunun histogramını çizerek başlayacaksınız.
# import the pyplot module from matplotlibimport matplotlib.pyplot as plt# matplotlib plots inline %matplotlib inline# Plotting distribution of winsplt.hist(df['W'])plt.xlabel('Wins')plt.title('Distribution of Wins')plt.show()Altyapı:
Jupyter defteri kullanmıyorsanız, grafikleri göstermek için plt.show() kullanmanız gerektiğini unutmayın.
Yıl başına ortalama galibiyetleri (W) yazdırın. Bunun için mean() yöntemini kullanabilirsiniz.
print(df['_'].______)
Verinizi keşfederken hedef sütun için kutucuklar (bins) oluşturmak yararlı olabilir, ancak modeli eğitirken hedef sütundan türettiğiniz hiçbir özelliği dahil etmemeye dikkat etmelisiniz. Hedef sütundan türetilen etiketler içeren bir sütunu eğitim kümesine dahil etmek, modele sınavın cevaplarını vermek gibi olur.
Galibiyet etiketlerini oluşturmak için, bir tamsayı değerini (galibiyet) alan ve girdiye bağlı olarak 1-5 arasında tamsayı döndüren assign_win_bins adlı bir işlev oluşturacaksınız.
Sonra, apply() yöntemini galibiyet sütununda kullanıp assign_win_bins() işlevini geçirerek win_bins adlı yeni bir sütun oluşturacaksınız.
# Creating bins for the win column
def assign_win_bins(_):
if W < 50:
return 1
if W >= 50 and W <= 69:
return 2
if W >= 70 and W <= 89:
return 3
if W >= 90 and W <= 109:
return 4
if W >= 110:
return 5
# Apply `assign_win_bins` to `df['W']`
df['win_bins'] = df['_'].apply(______________)
Şimdi x ekseninde yıl, y ekseninde galibiyet ve win_bins sütununu renklerle vurgulayarak bir saçılım grafiği yapalım.
# Plotting scatter graph of Year vs. Winsplt.scatter(df['yearID'], df['W'], c=df['win_bins'])plt.title('Wins Scatter Plot')plt.xlabel('Year')plt.ylabel('Wins')plt.show()Altyapı:
Yukarıdaki saçılım grafiğinde görüldüğü gibi, 1900 öncesine ait çok az sezon var ve o zamanlar oyun oldukça farklıydı. Bu nedenle, bu satırları veri setinden çıkarmak mantıklıdır.
# Filter for rows where 'yearID' is greater than 1900
df = df[___________________]
Sürekli verilerle çalışırken ve doğrusal modeller oluştururken, yıl gibi tamsayı değerleri sorunlara yol açabilir. Modelin çıkarımında, 1950 sayısının verinin geri kalanıyla aynı ilişkiye sahip olması olası değildir.
Bu sorunlardan kaçınmak için, yearID değerine dayalı olarak veriyi etiketleyen yeni değişkenler oluşturabilirsiniz.
Beyzbolu takip eden herkes bilir ki MLB ilerledikçe, maç başına atılan sayıların önemli ölçüde arttığı veya azaldığı farklı dönemler ortaya çıkmıştır. 1900'lerin başındaki “dead ball” dönemi düşük skorlu bir döneme, 21. yüzyılın başındaki steroid dönemi ise yüksek skorlu bir döneme örnektir.
Aşağıda, her yıl ne kadar skor üretildiğini gösteren bir grafik yapalım.
runs_per_year ve games_per_year sözlüklerini oluşturarak başlayacaksınız. iterrows() yöntemiyle dataframe üzerinde döngü kurun. runs_per_year sözlüğünü, anahtar olarak yılları ve değer olarak o yıl atılan toplam sayıları içerecek şekilde doldurun. games_per_year sözlüğünü ise anahtar olarak yılları ve değer olarak o yıl oynanan toplam maç sayısını içerecek şekilde doldurun.
# Create runs per year and games per year dictionaries
runs_per_year = {}
games_per_year = {}
for i, row in df.iterrows():
year = row['yearID']
runs = row['R']
games = row['G']
if year in runs_per_year:
runs_per_year[year] = runs_per_year[year] + runs
games_per_year[year] = games_per_year[year] + games
else:
runs_per_year[year] = runs
games_per_year[year] = games
print(runs_per_year)
print(games_per_year)
Sonra mlb_runs_per_game adlı bir sözlük oluşturun. items() yöntemiyle games_per_year sözlüğünde gezin. mlb_runs_per_game sözlüğünü, anahtar olarak yılları ve lig genelinde maç başına atılan sayı sayısını değer olarak içerecek şekilde doldurun.
# Create MLB runs per game (per year) dictionary
mlb_runs_per_game = {}
for k, v in games_per_year.items():
year = k
games = v
runs = runs_per_year[year]
mlb_runs_per_game[year] = runs / games
print(mlb_runs_per_game)
Son olarak, yılları x eksenine ve maç başına atılan sayıları y eksenine koyarak mlb_runs_per_game sözlüğünden grafiğinizi oluşturun.
# Create lists from mlb_runs_per_game dictionarylists =sorted(mlb_runs_per_game.items())x, y =zip(*lists)# Create line plot of Year vs.MLB runs per Gameplt.plot(x, y)plt.title('MLB Yearly Runs per Game')plt.xlabel('Year')plt.ylabel('MLB Runs per Game')plt.show()Altyapı:
Yeni Özellikler Ekleme
Artık skor eğilimleri hakkında daha iyi bir fikriniz olduğuna göre, her veri satırının yearID'ye göre hangi döneme denk geldiğini gösteren yeni değişkenler oluşturabilirsiniz. win_bins sütununu oluştururken izlediğiniz sürecin aynısını takip edeceksiniz.
Bu kez, kukla (dummy) sütunlar oluşturacaksınız; her dönem için yeni bir sütun. Bunun için get_dummies() yöntemini kullanabilirsiniz.
# Creating "year_label" column, which will give your algorithm information about how certain years are related
# (Dead ball eras, Live ball/Steroid Eras)
def assign_label(____):
if year < 1920:
return 1
elif year >= 1920 and year <= 1941:
return 2
elif year >= 1942 and year <= 1945:
return 3
elif year >= 1946 and year <= 1962:
return 4
elif year >= 1963 and year <= 1976:
return 5
elif year >= 1977 and year <= 1992:
return 6
elif year >= 1993 and year <= 2009:
return 7
elif year >= 2010:
return 8
# Add `year_label` column to `df`
df['year_label'] = df['yearID'].apply(___________)
dummy_df = pd.get_dummies(df['year_label'], prefix='era')
# Concatenate `df` and `dummy_df`
df = pd.concat([df, dummy_df], axis=1)
print(df.head())
Yıllara göre MLB maç başına sayı miktarını zaten belirlediğinize göre, bu veriyi veri setine ekleyin.
# Create column for MLB runs per game from the mlb_runs_per_game dictionary
def assign_mlb_rpg(year):
return mlb_runs_per_game[year]
df['mlb_rpg'] = df['yearID'].apply(assign_mlb_rpg)
Şimdi yılları on yıllara dönüştürerek her on yıl için kukla sütunlar oluşturacaksınız. Ardından, artık ihtiyacınız olmayan sütunları kaldırabilirsiniz.
# Convert years into decade bins and creating dummy variables
def assign_decade(year):
if year < 1920:
return 1910
elif year >= 1920 and year <= 1929:
return 1920
elif year >= 1930 and year <= 1939:
return 1930
elif year >= 1940 and year <= 1949:
return 1940
elif year >= 1950 and year <= 1959:
return 1950
elif year >= 1960 and year <= 1969:
return 1960
elif year >= 1970 and year <= 1979:
return 1970
elif year >= 1980 and year <= 1989:
return 1980
elif year >= 1990 and year <= 1999:
return 1990
elif year >= 2000 and year <= 2009:
return 2000
elif year >= 2010:
return 2010
df['decade_label'] = df['yearID'].apply(assign_decade)
decade_df = pd.get_dummies(df['decade_label'], prefix='decade')
df = pd.concat([df, decade_df], axis=1)
# Drop unnecessary columns
df = df.drop(['yearID','year_label','decade_label'], axis=1)
Beyzbol oyununda en temel konu, kaç sayı attığınız ve kaç sayı yediğinizdir. Verinizdeki diğer sütunların oranlarından oluşan sütunlar yaratarak modelinizin doğruluğunu önemli ölçüde artırabilirsiniz. Maç başına atılan sayılar ve maç başına yenilen sayılar, veri setimize eklemek için harika özellikler olacaktır.
Pandas bunu çok basit hale getirir; R sütununu G sütununa bölerek R_per_game sütununu oluşturacak yeni bir sütun yaratırsınız.
# Create new features for Runs per Game and Runs Allowed per Game
df['R_per_game'] = df['R'] / df['G']
df['RA_per_game'] = df['RA'] / df['G']
Şimdi, iki yeni değişkenin hedef galibiyet sütunu ile nasıl ilişkili olduğunu görmek için birkaç saçılım grafiği yapın. Bir grafikte x eksenine maç başına atılan sayıları, diğerinde x eksenine maç başına yenilen sayıları koyun. Her birinin y eksenine W sütununu yerleştirin.
# Create scatter plots for runs per game vs. wins and runs allowed per game vs. winsfig = plt.figure(figsize=(12,6))ax1 = fig.add_subplot(1,2,1)ax2 = fig.add_subplot(1,2,2)ax1.scatter(df['R_per_game'], df['W'], c='blue')ax1.set_title('Runs per Game vs. Wins')ax1.set_ylabel('Wins')ax1.set_xlabel('Runs per Game')ax2.scatter(df['RA_per_game'], df['W'], c='red')ax2.set_title('Runs Allowed per Game vs. Wins')ax2.set_xlabel('Runs Allowed per Game')plt.show()Altyapı:
Herhangi bir makine öğrenimi modeline geçmeden önce, değişkenlerin hedef değişkenle ne kadar ilişkili olduğunu görmek faydalı olabilir. Pandas, corr() yöntemiyle bunu kolaylaştırır.
df.corr()['W']
Veri setine ekleyebileceğiniz bir diğer özellik de sklearn tarafından sağlanan bir K-means kümeleme algoritmasından türetilen etiketlerdir. K-means, veriyi belirttiğiniz k merkez sayısına göre parçalayan basit bir kümeleme algoritmasıdır. Her veri noktası, kendisine en düşük Öklid uzaklığına sahip merkeze göre bir kümeye atanır.
K-means kümeleme hakkında daha fazla bilgiyi burada bulabilirsiniz.
Önce, hedef değişkeni dışarıda bırakan bir DataFrame oluşturun:
attributes = ['G','R','AB','H','2B','3B','HR','BB','SO','SB','RA','ER','ERA','CG',
'SHO','SV','IPouts','HA','HRA','BBA','SOA','E','DP','FP','era_1','era_2','era_3','era_4','era_5','era_6','era_7','era_8','decade_1910','decade_1920','decade_1930','decade_1940','decade_1950','decade_1960','decade_1970','decade_1980','decade_1990','decade_2000','decade_2010','R_per_game','RA_per_game','mlb_rpg']
data_attributes = df[attributes]
# Print the first rows of `df`
print(df.head())
K-means kümelemede, modeli kullanmadan önce belirlemeniz gereken bir konu, kaç küme istediğinizdir. sklearn’in silhouette_score() işlevini kullanarak ideal küme sayınız hakkında daha iyi bir fikir edinebilirsiniz. Bu işlev, tüm örnekler için ortalama silüet katsayısını döndürür. Daha yüksek bir silüet skoru istersiniz ve kümeler arttıkça skor düşer.
Şimdi modeli başlatabilirsiniz. Küme sayınızı 6 ve rastgele durumu 1 olarak ayarlayın. fit_transform() yöntemiyle her veri noktası için Öklid uzaklıklarını belirleyin ve ardından kümeleri bir saçılım grafiğiyle görselleştirin.
# Create K-means model and determine euclidian distances for each data pointkmeans_model =KMeans(n_clusters=6, random_state=1)distances = kmeans_model.fit_transform(data_attributes)# Create scatter plot using labels fromK-means model as colorlabels = kmeans_model.labels_plt.scatter(distances[:,0], distances[:,1], c=labels)plt.title('Kmeans Clusters')plt.show()Altyapı:
Şimdi kümelerinizden gelen etiketleri veri setine yeni bir sütun olarak ekleyin. Ayrıca daha sonra kullanmak üzere attributes listesine “labels” dizesini ekleyin.
Modelinizi kurmadan önce, verinizi eğitim ve test kümelerine bölmeniz gerekir. Bunun nedeni, modeli test ettiğiniz verilerle aynı veriler üzerinde eğitmeye karar verirseniz, modelinizin veriye kolayca aşırı uyum sağlayabilmesidir: model, veriden öğrenmek yerine veriyi ezberler, bu da veriniz için gereğinden karmaşık modellere yol açar. Bu aynı zamanda aşırı uyumlu bir modelin, yeni verilerle tahmin yapmaya çalıştığınızda neden çok kötü performans göstereceğini de açıklar.
Ancak hemen endişelenmeyin, modelinizi çapraz doğrulamanın çeşitli yolları vardır.
Bu kez, verinizin rastgele yüzde 75'ini train veri kümesi olarak alacak ve kalan yüzde 25'i test veri kümesi olarak kullanacaksınız. Modelinizde kullanacağınız tüm sütunları içeren bir numeric_cols listesi oluşturun. Ardından, df DataFrame'inden numeric_cols listesindeki sütunlarla data adlı yeni bir DataFrame oluşturun. Daha sonra data DataFrame'ini örnekleyerek train ve test veri kümelerinizi de oluşturun.
# Create new DataFrame using only variables to be included in models
numeric_cols = ['G','R','AB','H','2B','3B','HR','BB','SO','SB','RA','ER','ERA','CG','SHO','SV','IPouts','HA','HRA','BBA','SOA','E','DP','FP','era_1','era_2','era_3','era_4','era_5','era_6','era_7','era_8','decade_1910','decade_1920','decade_1930','decade_1940','decade_1950','decade_1960','decade_1970','decade_1980','decade_1990','decade_2000','decade_2010','R_per_game','RA_per_game','mlb_rpg','labels','W']
data = df[numeric_cols]
print(data.head())
# Split data DataFrame into train and test sets
train = data.sample(frac=0.75, random_state=1)
test = data.loc[~data.index.isin(train.index)]
x_train = train[attributes]
y_train = train['W']
x_test = test[attributes]
y_test = test['W']
Hata Metrisini ve Modeli Seçme
Ortalama Mutlak Hata (MAE), modelinizin ne kadar doğru olduğunu belirlemek için kullanacağınız metriktir. Tahminlerin gerçek sonuçlara ne kadar yakın olduğunu ölçer. Özellikle bu veri için, bu hata metriği, tahmininizin hedefinden ortalama mutlak sapmayı size sağlar.
Bu, tahminleriniz hedef değerden ortalama 5 galibiyet sapıyorsa, hata metriğinizin 5 olacağı anlamına gelir.
Eğiteceğiniz ilk model doğrusal regresyon modeli olacaktır. LinearRegression ve mean_absolute_error'ı sırasıyla sklearn.linear_model ve sklearn.metrics'ten içe aktarabilir ve lr modelini oluşturabilirsiniz. Sonra modeli fit edip, tahminler yapar ve modelin ortalama mutlak hatasını belirlersiniz.
# Import `LinearRegression` from `sklearn.linear_model`
from sklearn.linear_model import ___________________
# Import `mean_absolute_error` from `sklearn.metrics`
from sklearn.metrics import mean_absolute_error
# Create Linear Regression model, fit model, and make predictions
lr = LinearRegression(normalize=True)
lr.fit(x_train, y_train)
predictions = lr.predict(x_test)
# Determine mean absolute error
mae = mean_absolute_error(y_test, predictions)
# Print `mae`
print(___)
Yukarıda hatırlarsanız, ortalama galibiyet sayısı yaklaşık 79'dur. Model, ortalama olarak yalnızca 2,687 galibiyet farkıyla yanılmaktadır.
Şimdi bir Ridge regresyon modeli deneyin. sklearn.linear_model'dan RidgeCV'yi içe aktarın ve rrm modelini oluşturun. RidgeCV modeli, küçültme miktarını kontrol eden bir karmaşıklık parametresi olan alpha parametresini ayarlamanıza olanak tanır (daha fazlasını burada okuyun). Model, sağladığınız alpha parametrelerinden hangisinin ideal olduğunu belirlemek için çapraz doğrulamayı kullanacaktır.
Yine, modelinizi fit edin, tahminler yapın ve ortalama mutlak hatayı belirleyin.
# Import `RidgeCV` from `sklearn.linear_model`
from sklearn.linear_model import _______
# Create Ridge Linear Regression model, fit model, and make predictions
rrm = RidgeCV(alphas=(0.01, 0.1, 1.0, 10.0), normalize=True)
rrm.fit(x_train, y_train)
predictions_rrm = rrm.predict(x_test)
# Determine mean absolute error
mae_rrm = mean_absolute_error(y_test, predictions_rrm)
print(________)
Bu model biraz daha iyi performans gösterdi ve ortalama olarak 2,673 galibiyet farkıyla yanıldı.
Spor Analitiği & Scikit-Learn
Bu eğitim serisinin ilk bölümü burada sona eriyor; scikit-Learn'ü spor verilerini analiz etmek için nasıl kullanabileceğinizi gördünüz. Verileri bir SQLite veritabanından içe aktardınız, temizlediniz, bazı yönlerini görsel olarak incelediniz ve birkaç yeni özellik tasarladınız. Bir K-means kümeleme modeli, birkaç farklı Doğrusal Regresyon modeli oluşturmayı ve tahminlerinizi ortalama mutlak hata metriği ile nasıl test edeceğinizi öğrendiniz.
İkinci bölümde, MLB Şöhretler Müzesi'ne hangi oyuncuların gireceğini sınıflandırma modelleriyle nasıl tahmin edeceğinizi göreceksiniz.
Algoritmalar, sistem tasarımı ve davranışsal senaryoları kapsayan bu temel sorularla teknik mülakat sürecine hakim olun. Uzman cevapları, kod örnekleri ve kanıtlanmış hazırlık stratejileri edinin.
Git deponuzu temiz tutmak için .gitignore’u nasıl kullanacağınızı öğrenin. Bu eğitim; temelleri, yaygın kullanım durumlarını ve başlamanıza yardımcı olacak pratik örnekleri kapsar!
Python programlama dili, birden fazla paketiyle veri bilimi ve öngörüsel analitik için harika bir seçenektir; veri analiz ihtiyaçlarınızın çoğunu karşılar. Python'da makine öğrenimi için Scikit-learn (
sklearn) mükemmel bir seçenektir ve NumPy, SciPy ve Matplotlib (sırasıyla N-boyutlu diziler, bilimsel hesaplama ve veri görselleştirme) üzerine kuruludur.Bu eğitimde,
sqlite3ile bir veritabanından verileri nasıl kolayca içe aktarabileceğinizi,pandasvematplotlibile verinizi nasıl keşfedip veri kalitesini iyileştirebileceğinizi ve ardından Scikit-Learn paketini kullanarak verinizden nasıl geçerli içgörüler çıkarabileceğinizi göreceksiniz.Bir makine öğrenimi kursu almak isterseniz, DataCamp’in scikit-learn ile Denetimli Öğrenme kursuna göz atın.
Bölüm 1: MLB Takımlarının Sezon Başına Galibiyetlerini Tahmin Etme
Bu projede,
sklearniçindeki çeşitli makine öğrenimi modellerini, bir Major League Baseball takımının, o sezonki takım istatistiklerine ve diğer değişkenlere dayanarak kaç maç kazandığını tahmin etmek için deneyeceksiniz. Eğer bahis oynayan biri olsaydım (ve kesinlikle öyleyim), geçmiş sezonların tarihsel verilerini kullanarak yaklaşan sezonu öngören bir model kurabilirdim. Verilerin zaman serisi doğası göz önüne alındığında, önceki beş yıldaki ortalama galibiyet gibi göstergeler ve benzeri etkenler üreterek yüksek doğrulukta bir model oluşturabilirsiniz. Ancak bu, bu eğitimin kapsamı dışındadır ve her satırı bağımsız olarak ele alacaksınız. Verilerimizin her satırı belirli bir yıl için tek bir takımdan oluşacaktır.Sean Lahman bu verileri web sitesinde derlemiş ve burada bir sqlite veritabanına dönüştürülmüştür.
Veri İçe Aktarma
Verileri,
sqlite3paketini kullanarak bir sqlite veritabanını sorgulayıp sonuçlarıpandasile bir DataFrame'e çevirerek okuyacaksınız. Verileriniz, yalnızca hâlen aktif olan modern takımları ve takımın 150 veya daha fazla maç oynadığı yılları içerecek şekilde filtrelenecektir.Önce “lahman2016.sqlite” dosyasını indirin (buradan). Ardından,
Pandas'ı yükleyin ve verimlilik içinpdolarak yeniden adlandırın.pd'nin Pandas için yaygın bir takma ad olduğunu hatırlıyor olabilirsiniz. Son olarak,sqlite3'ü yükleyin ve veritabanına şu şekilde bağlanın:Sonraki adımda bir sorgu yazacak, çalıştıracak ve sonuçları çekeceksiniz.
İpucu: Python ile SQL kullanımı hakkında daha fazla bilgi edinmek isterseniz, DataCamp’in Python’da İlişkisel Veritabanlarına Giriş kursunu değerlendirin.
pandaskullanarak sonuçları bir DataFrame'e dönüştürür vehead()yöntemiyle ilk 5 satırı yazdırırsınız:Sütunların her biri, belirli bir takım ve yıla ilişkin veriler içerir. Daha önemli değişkenlerden bazıları aşağıda listelenmiştir. Değişkenlerin tam listesine buradan ulaşabilirsiniz.
yearID- YılteamID- TakımfranchID- Franchise (TeamsFranchise tablosuna bağlanır)G- Oynanan maçlarW- GalibiyetlerLgWin- Lig Şampiyonu (Y veya N)WSWin- World Series Şampiyonu (Y veya N)R- Atılan sayı (runs)AB- Vuruş (at bat)H- Vurucuların isabetleriHR- Vurucuların home run'larıBB- Vurucuların base on balls (yürüyüş) sayısıSO- Vurucuların strikeout'larıSB- Çalınan bazlarCS- Çalarken yakalanmaHBP- Saha içi atışla vurulan vurucularSF- Fedakârlık uçuşlarıRA- Rakiplerin attığı sayılarER- İzin verilen earned runERA- Earned run ortalamasıCG- Tamamlanan maçlarSHO- Rakibe sayı vermeden bitirilen maçlar (shutout)SV- KurtarışlarIPOuts- Atılan out sayısı (atıcının oynadığı inning x 3)HA- İzin verilen isabetlerHRA- İzin verilen home run'larBBA- İzin verilen yürüyüşlerSOA- Atıcıların strikeout'larıE- HatalarDP- Çifte oyunlarFP- Alan savunma yüzdesiname- Takımın tam adıBeyzbola çok aşina olmayanlar için, oyunun nasıl işlediğine ve bazı değişkenlere değinen kısa bir açıklama:
Beyzbol, her biri dokuz oyuncudan oluşan iki takım (
nameveyateamIDile veride bulacaksınız) arasında oynanır. Bu iki takım sırayla hücum (batting) ve savunma yapar. Hücum yapan takım, savunmadaki takımın atıcısının attığı topa vurarak ve ardından saat yönünün tersine dört bazı (birinci, ikinci, üçüncü ve ev plağı) dolaşarak sayı (run) elde etmeye çalışır. Savunma yapan takım ise çeşitli şekillerde vurucuyu veya koşucuyu out ederek sayıyı engellemeye çalışır ve bir oyuncu bazları dolaşıp ev plakasına döndüğünde bir sayı (R) kaydedilir. Hücum takımındaki bir oyuncu güvenle baza ulaştığında, takım arkadaşlarının vuruş sırası sırasında isabet (H), çalıntı baz (SB) ya da diğer yollarla sonraki bazlara ilerlemeye çalışır.Takımlar, savunma yapan takım üç out kaydettiğinde hücum ve savunma rollerini değiştirir. Konuk takımla başlayan, her iki takımın da birer hücum hakkı kullandığı bölüm bir inning oluşturur. Oyun dokuz inning'den oluşur ve oyun sonunda daha fazla sayısı olan takım kazanır. Beyzbolda oyun saati yoktur ve çoğu maç dokuzuncu inning'de bitse de, maç dokuz inning sonunda berabere ise uzatmalara gider ve bir takım uzatma inning'inin sonunda öne geçene kadar süresiz olarak devam eder.
Beyzbol oyununun ayrıntılı açıklaması için Major League Baseball resmi kurallarına göz atın.
Veriyi Temizleme ve Hazırlama
Yukarıda gördüğünüz gibi, DataFrame'in sütun başlıkları yok.
pandas'ıncolumnsözelliğine başlık listenizi geçirerek başlıkları ekleyebilirsiniz.len()işlevi, kaç satırla uğraştığınızı bildirir: 2.287, çalışmak için çok büyük bir veri noktası sayısı değildir; umarız çok fazla null değer yoktur.Veri kalitesini değerlendirmeden önce, gerekli olmayan veya hedef sütundan (
Wins) türetilen sütunları eleyelim. Bu noktada, üzerinde çalıştığınız veriye dair bilgi sahibi olmak çok değerli hale gelir. Üzerinde çalıştığınız veriyi tanımıyorsanız, kodlama ya da istatistik bilgisi ne kadar iyi olursa olsun fark etmez. Ömür boyu bir beyzbol hayranı olmak bu projede bana kesinlikle yardımcı oldu.Yukarıda okuduğunuz gibi, null değerler veri kalitesini etkiler ve bu da makine öğrenimi algoritmalarında sorunlara yol açabilir.
Bu yüzden şimdi bunları kaldıracaksınız. Null değerleri ortadan kaldırmanın birkaç yolu vardır, ancak önce her sütun için null değer sayısını görüntülemek ve onlarla nasıl başa çıkılacağına karar vermek daha iyi bir fikir olabilir.
Burada bir ödünleşim göreceksiniz: Temiz veriye ihtiyacınız var, ancak elinizde gözden çıkaracak çok veri de yok. İki sütunda nispeten az sayıda null değer var.
SO(Strike Out) sütununda 110,DP(Double Play) sütununda 22 null değer bulunuyor. İki sütunda ise nispeten çok sayıda null değer var.CS(Çalarken Yakalanma) sütununda 419,HBP(Saha içi atışla vurulma) sütununda 1777 null değer var.Az sayıda null değeri olan sütunlardaki satırları elimine ederseniz, verinin yüzde beşinden biraz fazlasını kaybedersiniz. Galibiyetleri tahmin etmeye çalıştığınız için, atılan ve yenilen sayılar hedefle yüksek korelasyona sahiptir. Bu sütunlardaki verilerin oldukça doğru olmasını istersiniz.
Strike out (
SO) ve çifte oyun (DP) o kadar kritik değildir.Satırları tutup null değerleri her sütunun medyan değeriyle
fillna()yöntemiyle doldurmanın daha iyi olacağını düşünüyorum. Çalarken yakalanma (CS) ve saha içi atışla vurulma (HBP) da çok önemli değişkenler değil. Bu sütunlarda çok fazla null değer olduğundan, bu sütunları tamamen kaldırmak en iyisi.Veriyi Keşfetme ve Görselleştirme
Artık verinizi temizlediğinize göre, biraz keşif yapabilirsiniz. Birkaç basit görselleştirme ile veri kümesi hakkında daha iyi bir fikir edinebilirsiniz.
matplotlib, veri görselleştirme için mükemmel bir kütüphanedir.matplotlib.pyplot'ı içe aktarır ve verimlilik içinpltolarak yeniden adlandırırsınız. Bir Jupyter defteri ile çalışıyorsanız,%matplotlib inlinesihrini kullanmanız gerekir.Galibiyetlerin dağılımını görebilmek için hedef sütunun histogramını çizerek başlayacaksınız.
Jupyter defteri kullanmıyorsanız, grafikleri göstermek için
plt.show()kullanmanız gerektiğini unutmayın.Yıl başına ortalama galibiyetleri (
W) yazdırın. Bunun içinmean()yöntemini kullanabilirsiniz.Verinizi keşfederken hedef sütun için kutucuklar (bins) oluşturmak yararlı olabilir, ancak modeli eğitirken hedef sütundan türettiğiniz hiçbir özelliği dahil etmemeye dikkat etmelisiniz. Hedef sütundan türetilen etiketler içeren bir sütunu eğitim kümesine dahil etmek, modele sınavın cevaplarını vermek gibi olur.
Galibiyet etiketlerini oluşturmak için, bir tamsayı değerini (galibiyet) alan ve girdiye bağlı olarak 1-5 arasında tamsayı döndüren
assign_win_binsadlı bir işlev oluşturacaksınız.Sonra,
apply()yöntemini galibiyet sütununda kullanıpassign_win_bins()işlevini geçirerekwin_binsadlı yeni bir sütun oluşturacaksınız.Şimdi x ekseninde yıl, y ekseninde galibiyet ve
win_binssütununu renklerle vurgulayarak bir saçılım grafiği yapalım.Yukarıdaki saçılım grafiğinde görüldüğü gibi, 1900 öncesine ait çok az sezon var ve o zamanlar oyun oldukça farklıydı. Bu nedenle, bu satırları veri setinden çıkarmak mantıklıdır.
Sürekli verilerle çalışırken ve doğrusal modeller oluştururken, yıl gibi tamsayı değerleri sorunlara yol açabilir. Modelin çıkarımında, 1950 sayısının verinin geri kalanıyla aynı ilişkiye sahip olması olası değildir.
Bu sorunlardan kaçınmak için,
yearIDdeğerine dayalı olarak veriyi etiketleyen yeni değişkenler oluşturabilirsiniz.Beyzbolu takip eden herkes bilir ki MLB ilerledikçe, maç başına atılan sayıların önemli ölçüde arttığı veya azaldığı farklı dönemler ortaya çıkmıştır. 1900'lerin başındaki “dead ball” dönemi düşük skorlu bir döneme, 21. yüzyılın başındaki steroid dönemi ise yüksek skorlu bir döneme örnektir.
Aşağıda, her yıl ne kadar skor üretildiğini gösteren bir grafik yapalım.
runs_per_yearvegames_per_yearsözlüklerini oluşturarak başlayacaksınız.iterrows()yöntemiyle dataframe üzerinde döngü kurun.runs_per_yearsözlüğünü, anahtar olarak yılları ve değer olarak o yıl atılan toplam sayıları içerecek şekilde doldurun.games_per_yearsözlüğünü ise anahtar olarak yılları ve değer olarak o yıl oynanan toplam maç sayısını içerecek şekilde doldurun.Sonra
mlb_runs_per_gameadlı bir sözlük oluşturun.items()yöntemiylegames_per_yearsözlüğünde gezin.mlb_runs_per_gamesözlüğünü, anahtar olarak yılları ve lig genelinde maç başına atılan sayı sayısını değer olarak içerecek şekilde doldurun.Son olarak, yılları x eksenine ve maç başına atılan sayıları y eksenine koyarak
mlb_runs_per_gamesözlüğünden grafiğinizi oluşturun.Yeni Özellikler Ekleme
Artık skor eğilimleri hakkında daha iyi bir fikriniz olduğuna göre, her veri satırının
yearID'ye göre hangi döneme denk geldiğini gösteren yeni değişkenler oluşturabilirsiniz.win_binssütununu oluştururken izlediğiniz sürecin aynısını takip edeceksiniz.Bu kez, kukla (dummy) sütunlar oluşturacaksınız; her dönem için yeni bir sütun. Bunun için
get_dummies()yöntemini kullanabilirsiniz.Yıllara göre MLB maç başına sayı miktarını zaten belirlediğinize göre, bu veriyi veri setine ekleyin.
Şimdi yılları on yıllara dönüştürerek her on yıl için kukla sütunlar oluşturacaksınız. Ardından, artık ihtiyacınız olmayan sütunları kaldırabilirsiniz.
Beyzbol oyununda en temel konu, kaç sayı attığınız ve kaç sayı yediğinizdir. Verinizdeki diğer sütunların oranlarından oluşan sütunlar yaratarak modelinizin doğruluğunu önemli ölçüde artırabilirsiniz. Maç başına atılan sayılar ve maç başına yenilen sayılar, veri setimize eklemek için harika özellikler olacaktır.
Pandasbunu çok basit hale getirir;RsütununuGsütununa bölerekR_per_gamesütununu oluşturacak yeni bir sütun yaratırsınız.Şimdi, iki yeni değişkenin hedef galibiyet sütunu ile nasıl ilişkili olduğunu görmek için birkaç saçılım grafiği yapın. Bir grafikte x eksenine maç başına atılan sayıları, diğerinde x eksenine maç başına yenilen sayıları koyun. Her birinin y eksenine
Wsütununu yerleştirin.Herhangi bir makine öğrenimi modeline geçmeden önce, değişkenlerin hedef değişkenle ne kadar ilişkili olduğunu görmek faydalı olabilir.
Pandas,corr()yöntemiyle bunu kolaylaştırır.Veri setine ekleyebileceğiniz bir diğer özellik de
sklearntarafından sağlanan bir K-means kümeleme algoritmasından türetilen etiketlerdir. K-means, veriyi belirttiğiniz k merkez sayısına göre parçalayan basit bir kümeleme algoritmasıdır. Her veri noktası, kendisine en düşük Öklid uzaklığına sahip merkeze göre bir kümeye atanır.K-means kümeleme hakkında daha fazla bilgiyi burada bulabilirsiniz.
Önce, hedef değişkeni dışarıda bırakan bir DataFrame oluşturun:
K-means kümelemede, modeli kullanmadan önce belirlemeniz gereken bir konu, kaç küme istediğinizdir. sklearn’in
silhouette_score()işlevini kullanarak ideal küme sayınız hakkında daha iyi bir fikir edinebilirsiniz. Bu işlev, tüm örnekler için ortalama silüet katsayısını döndürür. Daha yüksek bir silüet skoru istersiniz ve kümeler arttıkça skor düşer.Şimdi modeli başlatabilirsiniz. Küme sayınızı 6 ve rastgele durumu
1olarak ayarlayın.fit_transform()yöntemiyle her veri noktası için Öklid uzaklıklarını belirleyin ve ardından kümeleri bir saçılım grafiğiyle görselleştirin.Şimdi kümelerinizden gelen etiketleri veri setine yeni bir sütun olarak ekleyin. Ayrıca daha sonra kullanmak üzere
attributeslistesine “labels” dizesini ekleyin.Modelinizi kurmadan önce, verinizi eğitim ve test kümelerine bölmeniz gerekir. Bunun nedeni, modeli test ettiğiniz verilerle aynı veriler üzerinde eğitmeye karar verirseniz, modelinizin veriye kolayca aşırı uyum sağlayabilmesidir: model, veriden öğrenmek yerine veriyi ezberler, bu da veriniz için gereğinden karmaşık modellere yol açar. Bu aynı zamanda aşırı uyumlu bir modelin, yeni verilerle tahmin yapmaya çalıştığınızda neden çok kötü performans göstereceğini de açıklar.
Ancak hemen endişelenmeyin, modelinizi çapraz doğrulamanın çeşitli yolları vardır.
Bu kez, verinizin rastgele yüzde 75'ini
trainveri kümesi olarak alacak ve kalan yüzde 25'itestveri kümesi olarak kullanacaksınız. Modelinizde kullanacağınız tüm sütunları içeren birnumeric_colslistesi oluşturun. Ardından,dfDataFrame'indennumeric_colslistesindeki sütunlarladataadlı yeni bir DataFrame oluşturun. Daha sonradataDataFrame'ini örnekleyerektrainvetestveri kümelerinizi de oluşturun.Hata Metrisini ve Modeli Seçme
Ortalama Mutlak Hata (MAE), modelinizin ne kadar doğru olduğunu belirlemek için kullanacağınız metriktir. Tahminlerin gerçek sonuçlara ne kadar yakın olduğunu ölçer. Özellikle bu veri için, bu hata metriği, tahmininizin hedefinden ortalama mutlak sapmayı size sağlar.
Bu, tahminleriniz hedef değerden ortalama 5 galibiyet sapıyorsa, hata metriğinizin 5 olacağı anlamına gelir.
Eğiteceğiniz ilk model doğrusal regresyon modeli olacaktır.
LinearRegressionvemean_absolute_error'ı sırasıylasklearn.linear_modelvesklearn.metrics'ten içe aktarabilir velrmodelini oluşturabilirsiniz. Sonra modeli fit edip, tahminler yapar ve modelin ortalama mutlak hatasını belirlersiniz.Yukarıda hatırlarsanız, ortalama galibiyet sayısı yaklaşık 79'dur. Model, ortalama olarak yalnızca 2,687 galibiyet farkıyla yanılmaktadır.
Şimdi bir Ridge regresyon modeli deneyin.
sklearn.linear_model'danRidgeCV'yi içe aktarın verrmmodelini oluşturun.RidgeCVmodeli, küçültme miktarını kontrol eden bir karmaşıklık parametresi olan alpha parametresini ayarlamanıza olanak tanır (daha fazlasını burada okuyun). Model, sağladığınız alpha parametrelerinden hangisinin ideal olduğunu belirlemek için çapraz doğrulamayı kullanacaktır.Yine, modelinizi fit edin, tahminler yapın ve ortalama mutlak hatayı belirleyin.
Bu model biraz daha iyi performans gösterdi ve ortalama olarak 2,673 galibiyet farkıyla yanıldı.
Spor Analitiği & Scikit-Learn
Bu eğitim serisinin ilk bölümü burada sona eriyor; scikit-Learn'ü spor verilerini analiz etmek için nasıl kullanabileceğinizi gördünüz. Verileri bir SQLite veritabanından içe aktardınız, temizlediniz, bazı yönlerini görsel olarak incelediniz ve birkaç yeni özellik tasarladınız. Bir K-means kümeleme modeli, birkaç farklı Doğrusal Regresyon modeli oluşturmayı ve tahminlerinizi ortalama mutlak hata metriği ile nasıl test edeceğinizi öğrendiniz.
İkinci bölümde, MLB Şöhretler Müzesi'ne hangi oyuncuların gireceğini sınıflandırma modelleriyle nasıl tahmin edeceğinizi göreceksiniz.