Dünya Kupası 2014, Veri Analizi
Daha önceki maç verisine bakarak 2014 Dünya Kupası maçlarını tahmin
edebilen istatistik (yapay öğrenim) teknikleri Google mühendisleri
tarafından paylaşıldı, kullanılan teknik lojistik regresyon. Verinin
şekillendirilmesi, veriden özellik (feature) yaratmak işin püf
noktalarından - veri hangi detay seviyesinde (maç seviyesinde mi takım
seviyesinde mi) ve hangi kolonlar üzerinden modele dahil edilecek?
Görülüyor ki nihai regresyon her maç için iki takımı yanyana koyuyor
(A takımı öğeleri belli kolonlar B öğeleri belli kolonlar) ve 1,0
etiketini tahmine uğraşıyor. Öğelerin önemli bir özelliği o ana kadar
her iki takımın oynadığı önceki N maçın özeti olmaları. Yani A takımı
son 3 maçta (N=3) maçta dakikada 5 pas atmışsa passes öğesi 5
olacaktır, B takımı dakikada 10 atmışsa op_passes
10
olacaktır. Böylece lojistik regresyona 5'e karşı 10 pas ağırlığı olan
bir veri satırı hakkında irdeleme yapma imkanı veriyoruz; ve bilinen
etikete göre LR gerekli ağırlıkları hesaplayarak sonuca erişiyor.
Projede kullanılan 4 Python dosyası var:
match_stats
: Maç istatistiklerini yükleyen kodlar.
features
: Ham istatistik verileri özelliklere (features) döndürüyor,
ki bu özellikler yapay öğrenim modeline girilebilsin. Bu özellikler önceki
K maçın verilerini özetleme amaçlı yaratıldılar, ki bu özelliklere
dayanarak bir sonraki maçı tahmnin edebilelim.
world_cup
: Veriyi temizlemek ve modeli kurmak için kullanılan
yardımcı kodlar.
power
: Birbiriyle belli sayıda maç yapmış takımların bir ``güç
sıralamasını'' hesaplamak.
Özellik inşası
Sonraki maç tahmini için önceki K maçın özet istatistiklerine bakıyoruz, K'nın
ne olduğu history_size
ile tanımlı.
import world_cup
import features
import match_stats
import pandas as pd
import math
pd.set_option('display.max_columns', None)
history_size = 3
game_summaries = features.get_game_summaries()
data = features.get_features(history_size)
Bu özellikler, dediğimiz gibi, önceki K maçın özeti. Bu özetlerin çoğu bir ortalamadır, ayrıca bu ortalamaların çoğu dakika bazlı çünkü maç zamanını aşan maçları da hesaba katmak için.. Eğer maç başına yapılan pas değeri alınsaydı, o zaman vakti aşan bir maçta o değer normalden çok daha fazla olacaktı, bu modeli bozardı.
Modelde kullanılacak özellikler:
is_home
: Takım evinde mi, deplasmanda mı oynuyor. Futbolda bu
değişkenin çok önemli olduğunu biliyoruz.
avg_points
: Önceki K maçta kazanılan ortalama puan (galibiyet için
3, eşitlik için 1, kayıp için 0).
avg_goals
: Önceki K maçta atılan averaj gol.
op_average_goals
: Rakip tarafından son K maçta atılan averaj gol.
pass_70/80
: Hücum sahasının 30%-20%'sinde dakika başına verilen
başarılı pas.
op_pass70/80
: Hücum sahasının 30%-20%'sinde rakip tarafından
verilmiş dakika bazında başarılı paslar.
expected_goals
: Son K maçtaki gol beklentisi, ki bu beklenti atılan
şut ve ve şutun kaleden uzaklığı baz alınarak hesaplanan bir sayı.
passes
: Dakika başına atılan paslar.
bad_passes
: Dakika bazında verilen ama başarılı olmayan paslar.
pass_ratio
: Başarılı pasların oranı.
corners
: Dakika bazında atılan kornerler.
fouls
: Yapılan faul sayısı (dk bazlı)
cards
: Kırmızı ya da sarı alınan kart ceza sayısı (maç başına).
shots
: Dakika bazında atılan şut.
op_*
: Rakipler hakkındaki bazı tarihi istatistikler. Dikkat, bu
`rakip''
opteamnamede gösterilen rakip değil, genel olarak bu
takımın rakiplerinin ona karşı nasıl oynadığını göstermeye çalışan bir
istatistik. Mesela
op_corners` bu takımın rakiplerinin dakika başına
kaç korner kazandığını gösteriyor.
*_op_ratio
: Takimin istatistiklerinin rakiplerine olan orani [?]
Ozellik olmayan kolonlar
matchid
: Maçın id'si
teamid
: Takımın id'si
op_teamid
: Rakip takımın özgün id'si
team_name
: Takımın ismi
op_team_name
: Rakip takımın ismi
timestamp
: Maç ne zaman oynandı
competitionid
: Genel müsabakayı gösteren kod (dünya kupası, vs).
Hedef kolonlar:
Alttaki kolonlar tahmin edilmeye uğraşılabilecek olan kolonlar. Eğer bilinen veri üzerinde tahmin yapmak istiyorsak, bu kolonları tahmin öncesi dışarı atmalıyız, bunu unutmayalım. Birkaç hedef kolon var ama, biz sadece kazanılan puanı tahmin etmeye uğraşacağız, belki diğer modeller diğer kolonları tahmin etmeye uğraşırlar, mesela atılan gol sayısı gibi.
points
: Maçın puan sonucu.
goals
: teamid
deki takımın attığı gol sayısı.
op_goals
: op_teamid
ile gösterilen takımın attığı gol sayısı.
club_data = data[data['competitionid'] != 4]
# Show the features latest game in competition id 4, which is the world cup.
print (data[data['competitionid'] == 4].iloc[0])
matchid 731828
teamid 366
op_teamid 632
competitionid 4
seasonid 2013
is_home 0
team_name Netherlands
op_team_name Argentina
timestamp 2014-07-09 21:00:00.000000
goals 0
op_goals 0
points 1
avg_points 2.333333
avg_goals 1.333333
op_avg_goals 0.333333
pass_70 0.472036
pass_80 0.150698
op_pass_70 0.26478
op_pass_80 0.078501
expected_goals 1.444374
op_expected_goals 0.411425
passes 3.834864
bad_passes 1.013622
pass_ratio 0.765595
corners 0.070991
fouls 0.126237
cards 1.0
shots 0.155226
op_passes 3.38986
op_bad_passes 1.024551
op_corners 0.03468
op_fouls 0.157066
op_cards 2.666667
op_shots 0.092497
goals_op_ratio 1.333333
shots_op_ratio 1.702273
pass_op_ratio 1.025426
Name: 0, dtype: object
Maç bazında atılan goller ve maçın sonucunu eksenlere alarak bir tablo yaratalım (crosstab).
import pandas as pd
print (pd.crosstab(
club_data['goals'],
club_data.replace(
{'points': {
0: 'lose', 1: 'tie', 3: 'win'}})['points']))
points lose tie win
goals
0 768 279 0
1 508 416 334
2 134 218 531
3 23 42 325
4 2 6 158
5 0 2 67
6 0 0 13
7 0 0 6
8 0 0 1
5'den fazla gol atmak tabii ki kazanmayı garantiliyor, hiç atmamak 75\% ihtimalle kaybedilecek demektir (bazen de beraberlik olur tabii!). Not: Fakat tabloda 4 gol sonrası kazanımlar direk artmıyor, niye? Çünkü bu maçlar uzatma sonrası atılan penaltılardan geliyor, her iki takımda bu sırada çok gol atıyor, ve biri mutlaka kaybediyor [1].
Modeli eğitmek
Veri tabanımızdaki klüp verisini kullanarak (yani hiç dünya kupası verisi
kullanmadan) eğiteceğiz. Bu kod world_cup.py
içinde. Sonuç bir
lojistik regresyon modeli olacak, ve sonra test verisi üzerinde tahmin
yapacağız. Regresyonun Rsquared değerini göstereceğiz, ki bu eğitim
verisi üzerinden gösterilebilir. Rsquared modelin veriye ne kadar uyduğunu
gösteren bir rakamdır, ne kadar yüksekse o kadar iyidir.
import world_cup
import match_stats
pd.set_option('display.width', 80)
# Don't train on games that ended in a draw, since they have less signal.
train = club_data.loc[club_data['points'] != 1]
# train = club_data
(model, test) = world_cup.train_model(
train, match_stats.get_non_feature_columns())
print ("Rsquared: %0.03g" % model.prsquared)
Rsquared: 0.149
Önemli özellikleri seçmek
Lojistik regresyon modelimiz regülarizasyon kullanıyor; bu demektir ki daha çetrefil modeller cezalandırılıyor. Bu cezalandırmanın yan etkisi olarak biz hangi özelliklerin daha önemli olduğunu görebiliyoruz, çünkü daha önemsiz olan özellikler modelden atılıyorlar (katsayıları sıfıra iniyor).
Bu bağlamda özellikleri üçe ayırabiliriz:
Pozitif özellikler: Bu özellikler mevcut ise takımın kazanma şansı yükseliyor.
Negative özellikler: Tam tersi
Atılan değerler: Önemli olmayan özellikler, ki bu özellikler modele dahil edilirse aşırı uygunluk (overfitting) durumu ortaya çıkar.
def print_params(model, limit=None):
params = model.params.copy()
params.sort_values(ascending=False)
del params['intercept']
if not limit:
limit = len(params)
print("Pozitif ozellikler")
params.sort_values(ascending=False)
print (np.exp(params[[param > 0.001 for param in params]]).sub(1)[:limit])
print("\nAtilan ozellikler")
print (params[[param == 0.0 for param in params]][:limit])
print("\nNegatif ozellikler")
params.sort_values(ascending=True)
print (np.exp(params[[param < -0.001 for param in params]]).sub(1)[:limit])
print_params(model, 10)
Pozitif ozellikler
is_home 0.848337
avg_goals 0.092000
pass_70 0.254729
expected_goals 0.169235
passes 0.051791
fouls 0.062809
shots 0.001786
op_passes 0.120319
pass_op_ratio 0.018882
opp_pass_80 0.014662
dtype: float64
Atilan ozellikler
avg_points 0.0
op_avg_goals 0.0
op_pass_70 0.0
pass_ratio 0.0
corners 0.0
op_bad_passes 0.0
op_fouls 0.0
op_cards 0.0
goals_op_ratio 0.0
shots_op_ratio 0.0
dtype: float64
Negatif ozellikler
pass_80 -0.014450
op_pass_80 -0.087566
op_expected_goals -0.042092
bad_passes -0.070335
cards -0.064461
op_corners -0.137309
op_shots -0.017699
opp_avg_goals -0.084249
opp_pass_70 -0.203015
opp_expected_goals -0.144740
dtype: float64
Klüp verisi üzerinde tahmin
predicted
: Takımın kazanma şansı (tahmin).
points
: Gerçekten ne oldu.
results = world_cup.predict_model(model, test, match_stats.get_non_feature_columns())
predictions = world_cup.extract_predictions(results.copy(), results['predicted'])
print ('Dogru tahminler:')
print (predictions[(predictions['predicted'] > 50) & (predictions['points'] == 3)][:5])
Dogru tahminler:
team_name op_team_name predicted expected \
8 Portland Timbers Real Salt Lake 52.418756 Portland Timbers
42 Rayo Vallecano Granada CF 60.862465 Rayo Vallecano
49 Atlético de Madrid Getafe 64.383541 Atlético de Madrid
57 Colorado Rapids Vancouver Whitecaps 51.836366 Colorado Rapids
58 Real Madrid Real Sociedad 64.100904 Real Madrid
winner points
8 Portland Timbers 3
42 Rayo Vallecano 3
49 Atlético de Madrid 3
57 Colorado Rapids 3
58 Real Madrid 3
print ('Yanlis tahminler:')
print (predictions[(predictions['predicted'] > 50) & (predictions['points'] < 3)][:5])
Yanlis tahminler:
team_name op_team_name predicted \
1 Seattle Sounders FC Vancouver Whitecaps 51.544963
2 New England Revolution Real Salt Lake 63.950714
3 Philadelphia Union FC Dallas 54.213693
14 New England Revolution Montreal Impact 52.762065
20 New York Red Bulls Toronto FC 55.533969
expected winner points
1 Seattle Sounders FC Vancouver Whitecaps 0
2 New England Revolution Real Salt Lake 0
3 Philadelphia Union FC Dallas 0
14 New England Revolution Montreal Impact 0
20 New York Red Bulls Toronto FC 0
Tahminlerimizi kontrol etmek
Kontrol için mesela hesabımızın rasgele tahminden ne kadar iyi olduğunu hesaplayabiliriz (lift) ya da AUC hesabı yapıp ROC eğrisini hesaplarız. AUC herhalde en iyisi, bu hesap çok ilginçtir, 0.5 (kafadan atmak) ve 1.0 arasındadır (mükemmel tahmin), ve bu hesap dengesiz veri setlerine karşı dayanıklıdır. Mesela 0/1 etiketi tahmininde test setinde diyelim ki yüzde 90 oranında olsa ve modelimiz sürekli 1 tahmin etse, basit bir ölçüm bize modelimizin yüzde 90 başarılı olduğunu söylerdi. AUC böyle durumlara karşı dayanıklıdır, bize 0.5 sonucunu verir.
baseline = (sum([yval == 3 for yval in club_data['points']])
* 1.0 / len(club_data))
y = [yval == 3 for yval in test['points']]
world_cup.validate(3, y, results['predicted'], baseline,
compute_auc=True)
plt.savefig('stat_worldcup_01.png')
(3) Lift: 1.42 Auc: 0.738
Modelde eksik olan bir şey var; sonraki maçı önceki birkaç maçın özetinden tahmin etmeye uğraşıyoruz ama belki bazı takımlar önceki K maçta çok zorlu rakiplerle uğraşmıştır, bazıları çok kolay rakiplerle uğraşmıştır. Bu durumda önceki maçların istatistiği bize tüm hikayeyi anlatmayacaktır.
Bu problemi çözmek için ayrı bir regresyon daha işletebiliriz. Bu regresyon bir güç sıralaması (power ranking) hesaplayabilir, bu hesap FIFA/CocaCola'nın enternasyonel takımlar için yaptığı güç sıralama hesabına benzer. ABD'de beyzbol ve Amerikan futbolu için de benzer bir hesap yapılıyor.
Güç sıralaması hesabını yaptıktan sonra -tek bir sayı, bazı takımlar için daha yüksek bazı takımlar için daha alçak, ki onun üzerinden sıralama yapılabilsin- onu bir özellik olarak lojistik regresyon modeline dahil edebiliriz. Güç sıralaması esas olarak şu tür irdelemelerin modelimize dahilini mümkün kılar; A takımı B'yi yendiyse, B C'yi yendiyse, A büyük ihtimalle C'yi yener. Bu tür bilgi niye önemli? Çünkü elimizde yapılabilecek tüm maçların kombinasyonu yok, maç verisi seyrek (sparse). Ama eldeki birkaç maçtan bir güç sıralaması hesaplayabilirsek, bu bize takımlar arasında, daha önce maç oynamamış olsalar bile, otomatik olarak bir ek irdeleme yapabilmemizi sağlayacaktır.
Sıralama hesabı yapıldıktan sonra bazı kontrolleri hızla, çıplak gözle yapabiliriz, mesela sonuca bakarız, eğer Wiggan (zayıf bir takım) 1.0 değeri almış, Chelsea (güçlü bir takım) 0.0 değeri almış ise bir şeyler yanlış demektir.
Tabii buna rağmen bazı takımlara hala uygun sıralama veremeyebiliriz, mesela A,B'yi, B,C'yi yeniyor, sonra veriye göre, C A'yı yeniyor. Bu şekilde sıralayamadığımız durumda takıma 0.5 verip tam ortaya koyacağız.
Ayrıca enternasyonel takımların sıralaması çok gürültülü veri olduğu ve (klüp verisinden bile daha) seyrek olduğu için onu yüzdeliklere (quartiles) ayırarak göstereceğiz, yani sıralamalar 0, .33, .66, or 1.0 olarak gözükecekler.
Fakat hesap işi bitince, ve bu sıralamayı nihai lojistik modele dahil edince başarı oranımızın zıplama yaptığını göreceğiz.
import power
def points_to_sgn(p):
if p > 0.1: return 1.0
elif p < -0.1: return -1.0
else: return 0.0
power_cols = [
('points', points_to_sgn, 'points'),
]
power_data = power.add_power(club_data, game_summaries, power_cols)
power_train = power_data.loc[power_data['points'] != 1]
# power_train = power_data
(power_model, power_test) = world_cup.train_model(
power_train, match_stats.get_non_feature_columns())
print ("\nRsquared: %0.03g, Power Coef %0.03g" % (
power_model.prsquared,
math.exp(power_model.params['power_points'])))
power_results = world_cup.predict_model(power_model, power_test,
match_stats.get_non_feature_columns())
power_y = [yval == 3 for yval in power_test['points']]
world_cup.validate(3, power_y, power_results['predicted'], baseline,
compute_auc=True, quiet=False)
print_params(power_model, 8)
plt.plot([0, 1], [0, 1], '--', color=(0.6, 0.6, 0.6), label='Luck')
# Add the old model to the graph
world_cup.validate('old', y, results['predicted'], baseline,
compute_auc=True, quiet=True)
plt.legend(loc="lower right")
plt.savefig('world_cup_02.png')
New season 2014
New season 2013
New season 2013
New season 2012
New season 2012
New season 2011
['D.C. United: 0.000', 'Real Zaragoza: 0.000', 'Blackburn Rovers:
0.000', 'Toronto FC: 0.015', 'Deportivo de La Coruña: 0.019',
'Reading: 0.019', 'Mallorca: 0.022', 'Wolverhampton Wanderers: 0.027',
'Almería: 0.034', 'Osasuna: 0.044', 'Bolton Wanderers: 0.045',
'Granada CF: 0.047', 'Queens Park Rangers: 0.049', 'Chivas USA:
0.050', 'Espanyol: 0.050', 'Aston Villa: 0.057', 'Real Betis: 0.062',
'Norwich City: 0.068', 'Getafe: 0.070', 'Rayo Vallecano: 0.074',
'Levante: 0.082', 'Real Valladolid: 0.084', 'Celta de Vigo: 0.090',
'Southampton: 0.117', 'Swansea City: 0.119', 'Sunderland: 0.119',
'Stoke City: 0.126', 'Fulham: 0.144', 'West Bromwich Albion: 0.148',
'Málaga: 0.151', 'Villarreal: 0.157', 'Athletic Club: 0.159',
'Valencia CF: 0.166', 'Valencia: 0.166', 'Sevilla: 0.176', 'West Ham
United: 0.183', 'Columbus Crew: 0.195', 'Real Sociedad: 0.264',
'Liverpool: 0.298', 'Everton: 0.316', 'Newcastle United: 0.322',
'Arsenal: 0.332', 'Montreal Impact: 0.370', 'Chelsea: 0.399', 'Chicago
Fire: 0.418', 'New England Revolution: 0.436', 'San Jose Earthquakes:
0.470', 'Atlético de Madrid: 0.473', 'Tottenham Hotspur: 0.496',
'Elche: 0.500', 'Wigan Athletic: 0.500', 'New York Red Bulls: 0.587',
'Philadelphia Union: 0.602', 'Houston Dynamo: 0.614', 'Sporting Kansas
City: 0.672', 'FC Dallas: 0.712', 'Real Madrid: 0.744', 'Vancouver
Whitecaps: 0.768', 'Real Salt Lake: 0.775', 'LA Galaxy: 0.803',
'Portland Timbers: 0.810', 'Seattle Sounders FC: 0.813', 'Manchester
City: 0.854', 'Colorado Rapids: 1.000', 'Barcelona: 1.000',
'Manchester United: 1.000']
Rsquared: 0.215, Power Coef 1.88
(3) Lift: 1.46 Auc: 0.75
Base: 0.374 Acc: 0.671 P(1|t): 0.728 P(0|f): 0.637
Fp/Fn/Tp/Tn p/n/c: 110/245/295/430 540/540/1080
Pozitif ozellikler
is_home 0.985326
pass_70 0.086559
pass_80 0.085011
expected_goals 0.035091
passes 0.045325
fouls 0.074550
op_passes 0.123758
op_bad_passes 0.006521
dtype: float64
Atilan ozellikler
avg_points 0.0
avg_goals 0.0
op_pass_70 0.0
bad_passes 0.0
pass_ratio 0.0
corners 0.0
cards 0.0
shots 0.0
dtype: float64
Negatif ozellikler
op_avg_goals -0.008003
op_pass_80 -0.024318
op_expected_goals -0.062309
op_corners -0.040983
opp_pass_70 -0.079663
opp_pass_80 -0.078350
opp_expected_goals -0.033901
opp_passes -0.043359
dtype: float64
(old) Lift: 1.42 Auc: 0.738
Şimdi dünya kupasını tahmin edelim!
Aynen klüp verisinde yaptığımız gibi dünya kupası için de benzer istatistikleri hesaplayabiliriz. Bu durumda elimizde hedefler olmayacak, yani kimin kazandığını bilemeyeceğiz (aslında bazı dünya kupası maçlarının sonucunu biliyoruz, ama tahminlerimizi hiçbir maçı bilmiyormuş gibi yapalım). Ve tekrar vurgulayalım: klüp verisiyle eğittiğimiz modeli kullanarak dünya kupasını tahmin edeceğiz. Yani model ve tahmin tamamen farklı takımlar üzerinden yapılacak!
features.get_wc_features()
bize tüm dünya kupası maçları için
gereken özellikleri yaratıp döndürecektir.
import world_cup
import features
wc_data = world_cup.prepare_data(features.get_wc_features(history_size))
wc_labeled = world_cup.prepare_data(features.get_features(history_size))
wc_labeled = wc_labeled[wc_labeled['competitionid'] == 4]
wc_power_train = game_summaries[game_summaries['competitionid'] == 4].copy()
Ev sahası avantajı
Klüp verisi ile dünya kupası verisi arasındaki bazı farklardan biri budur: dünya kupasında bir maçta ev sahibi olmak ya da deplasmanda olmak ne demektir? Resmi olarak tek ev sahibi tüm 2014 kupasına ev sahipliği yapan Brezilya'dır, o zaman sadece Brezilya mı oynadığı maçlarda ev sahibi olabilir? Bu pek akla yatkın gelmiyor.
Belki diğer Latin Amerika takımlarını da ev sahibi olarak
görebiliriz.. Adam aynı kıtadan, belki o kıtaya alışık, iklimi vs ona
normal geliyor.. ? Olabilir mi? Diğer bazı modeller is_home
u sadece
Brezilya'ya vermiş, sonra aynı kitadaki diğer takımlara da 'azıcık' ev
sahipliği vermişler, çünkü istatistiklere göre bu takımlar kendi
kıtalarında daha iyi performans gösteriyorlarmış, vs.
Biz daha değişik bir model kullanacağız, bu model belki biraz
sübjektif.. Biz is_home
öğesine 0.0 ila 1.0 arasında bir değer
atayacağız, ve bu değerin büyüklüğü o takımın taraftarlarının hem sayı, hem
de destek enerjisi üzerinden ölçülecek. Bunu yapmamızın sebebi ilk turlarda
görüldüğü üzere, taraftarının daha iyi desteklediği takımların diğerlerine
göre daha iyi performans göstermesi. Mesela Şili'nin taraftarı takımını
müthiş destekledi, İspanya taraftarı oralı bile olmadı, Şili-İspanya maçını
Şili 2-0 kazandı. Bunun gibi pek çok maç gözlemledik, çoğunda güney Amerika
takımları vardı, ama çok taraftar gönderen takımlar da vardı, mesela
Meksika. Ya da ABD vardı, çok taraftarı vardı ama sessizdiler, onlar daha
düşük skorlar aldılar.
import pandas as pd
wc_home = pd.read_csv('wc_home.csv')
def add_home_override(df, home_map):
for ii in range(len(df)):
team = df.iloc[ii]['teamid']
if team in home_map:
df['is_home'].iloc[ii] = home_map[team]
else:
# If we don't know, assume not at home.
df['is_home'].iloc[ii] = 0.0
home_override = {}
for ii in range(len(wc_home)):
row = wc_home.iloc[ii]
home_override[row['teamid']] = row['is_home']
# Add home team overrides.
add_home_override(wc_data, home_override)
Dünya Kupası Güç Sıralaması
Bu hesabın dünya kupası verisi üzerinde yapılması lazım, çünkü güç sıralaması o takımların arasındaki maçlara dayanılarak yapılan bir hesap. Bu maçlar ise, dünya kupası takımları bağlamında, oldukça seyrek çünkü bazı takımlar bazı takımlarla neredeyse onyıldır oynamamış. Çoğu Avrupa takımı mesela güney Amerika takımıyla oynamamış, Asyalı takımlarla daha bile az oynamış. Klüp bazında kullandığımız aynı numarayı burada da kullanabiliriz, ama başarısızlığa hazır olmak lazım!
Hesap altta
# Guc verisiyle egitirken, kupa birden fazla maca yayildigi icin
# is_home'u 0.5'e set et. Yoksa 2010'daki kupa maclarina baktigimizda
# Guney Afrika yerine Brezilya'nin hala ev sahibi olduugnu zannedebilirdik.
wc_power_train['is_home'] = 0.5
wc_power_data = power.add_power(wc_data, wc_power_train, power_cols)
wc_results = world_cup.predict_model(power_model, wc_power_data,
match_stats.get_non_feature_columns())
New season 2013
New season 2009
New season 6
['Cameroon: 0.000', 'Honduras: 0.024', 'Nigeria: 0.047', 'Serbia:
0.072', 'USA: 0.073', 'Sweden: 0.098', 'Iran: 0.099', 'Algeria:
0.104', 'Japan: 0.115', 'Mexico: 0.127', 'Costa Rica: 0.130', "Côte
d'Ivoire: 0.148", 'Ecuador: 0.156', 'Chile: 0.166', 'England: 0.169',
'Australia: 0.177', 'Ukraine: 0.201', 'South Korea: 0.213',
'Switzerland: 0.240', 'France: 0.251', 'Uruguay: 0.318', 'Portugal:
0.382', 'Belgium: 0.466', 'Brazil: 0.470', 'Argentina: 0.486', 'Italy:
0.491', 'Greece: 0.500', 'Ghana: 0.500', 'Croatia: 0.500', 'Paraguay:
0.500', 'Slovakia: 0.500', 'Spain: 0.685', 'Germany: 0.740',
'Netherlands: 0.812', 'Colombia: 1.000']
Güç sırası da ayrı bir lojistik regresyon aslında, power.py
içinde
biz bu regresyona giren matris ve etiketleri hesap yapılmadan önce çekip
çıkarttık, ve bir dosyaya kaydettirdik. Bakarsak,
games = pd.read_csv('/tmp/games.csv')
outcomes = pd.read_csv('/tmp/outcomes.csv')
Herhangi bir satıra göz atalım,
print ('mac', games[100:101])
print ('sonuc', outcomes[100:101])
mac 366 632 614 357 838 360 832 368 596 497 1215 1216 517 659 \
100 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
837 831 1041 536 359 1219 830 847 1042 537 1221 1266 119 \
100 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
114 494 535 118 575 835 507 1801 369 1804 364 365 522 \
100 0.0 1.5625 0.0 0.0 0.0 0.0 0.0 0.0 -1.5625 0.0 0.0 0.0 0.0
1161 510 361 1264 1223 511 1794 367 1224
100 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
sonuc 0
100 -1.0
Yani güç sıralaması lojistik regresyonuna girdi olan matrisin her satırı ayrı bir maç, her kolonu ise ayrı bir takım. Maç yapan iki takımın değerleri olacak, diğerleri sıfır olacak. Üstteki satır mesela, 369. takım ve rakipte 494. takım için,
raw_games = pd.read_csv('results-20140714-124014.csv')
tmp = raw_games[(raw_games['teamid'] == 369) & (raw_games['op_teamid'] == 494)]
tmp = tmp[['teamid','team_name','op_team_name','is_home','points']]
print (tmp)
teamid team_name op_team_name is_home points
4231 369 Denmark Cameroon 0 3
Danimarka Kamerun maçına aitmiş. Bu maçta Danimarka kazandı, ev sahibi Kamerun. Şimdi burada birkaç önemli takla atılıyor, Google veri bilimcileri lojistik regresyonda, girdi olarak, deplasman takımına her maç başında otomatik olarak eksi bir değer veriyorlar, ev sahibine artı değer veriyorlar. Etiket ise 'ev sahibi kazandı mı?' sorusunun cevabı.
Ev sahibi olup kazanmak daha kolay, regresyon bağlamında artı değere sahip olursanız, az bir katsayı modeli uydurmaya yeterli olabilir, pozitife hemen yaklaşırız. Diğer yandan deplasman takımı ne kadar iyi oynarsa, onun büyüyen katsayısı eksi değerini o kadar arttırır, ve ev sahibinin artışını (onun öğesi çarpı katsayısı yani) eksilterek kaybetme durumuna yaklaştırır.
Kötü oynayan deplasman takımının eksi değeri eksi katsayı ile çarpılır, ve daha büyük bir artı sayıyı oluşturur, ev sahibinin kazanması durumunu güçlendirir.
Katsayıları doğal olarak bir takımın ne kadar iyi olduğunu gösterecektir.
Tabii regresyona pek çok satır verilecek, Kamerun birden fazla satırda ortaya çıkabilecek (ama hep aynı kolonda, işin püf noktası burada), bazen artı değerli olarak (ev sahibi) bazen eksi değerli olarak (deplasman).
İtiraf etmek gerekir ki veri bilimi bağlamında üstteki teknik, model, düşünce tarzı dahiyane bir yaklaşım, alanın ruhunu göstermesi bakımından eğitici. Veri temsilinden tutun, regresyonun kodlanmasında çeyrekliklere ayırmak, az veri olduğu için yaklaşıksallık (convergence) olmayabilir diye değişik parametrelerle regresyonu birkaç kez işletmek, bunu yaklaşıksallık olana kadar yapmak, tam anlamıyla bir ders niteliği taşıyor.
Tahmin
Nihayet hazırlandığımız ana geldik. Şimdi dünya kupası maçlarını tahmin edelim. Birkaç kolon göstereceğiz:
predicted
: Yüzde kaç ihtimalle (ismi ilk gelen) takımın kazanacağı
points
: Gerçekten ne olduğu. Oynanmayan maç NaN
. Dikkat,
penaltı atışlarına giden maçlar eşitlik olarak gösterilecek.
Ama bir dakika! Bu sonuçlar daha önce gösterdiğiniz [Google tahminleri kastediliyor] tahminlerinden değişik! Bunun sebepleri şunlar: Bazı hataları tamir ettik, yani kod değişti. İlk model mesela uzayan maçlar yüzünden kabaran istatistiklerin durumunu hesaba almıyordu.
İkinci sebep, model baştan planlı (deterministik) değil, eğitim verisi için verinin belli bir kısmını rasgele olarak seçiyoruz, bu sebeple sonuçlar bir hesaptan diğerine değişik çıkabiliyor (ki bazen sonuçlar çok değişik olabiliyor). Not: Aslında bu kod değiştirilerek rasgelelik içinden tamamen çıkartılabilir (ev ödeviniz!).
16'ıncı turu tahmin ederken mesela önceki 3 maçı, çeyrek finaller için
önceki 4, yarıfınaller için 5, ve finaller için önceki 6 maçı
kullandık [biz bu dokümanda önceki 3 maçı kullandık, history_size
parametresiyle oynayarak değişik sonuçlar kontrol edilebilir].
pd.set_option('display.max_rows', 5000)
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1000)
wc_with_points = wc_power_data.copy()
wc_with_points.index = pd.Index(
zip(wc_with_points['matchid'], wc_with_points['teamid']))
wc_labeled.index = pd.Index(
zip(wc_labeled['matchid'], wc_labeled['teamid']))
wc_with_points['points'] = wc_labeled['points']
wc_pred = world_cup.extract_predictions(wc_with_points,
wc_results['predicted'])
# Reverse our predictions to show the most recent first.
wc_pred.reindex(index=wc_pred.index[::-1])
# Show our predictions for the games that have already happenned.
print (wc_pred)
team_name op_team_name predicted expected winner points
0 Argentina Germany 44.097950 Germany NA NaN
1 Netherlands Brazil 52.711308 Netherlands NA NaN
2 Netherlands Argentina 55.089671 Netherlands draw 1.0
3 Germany Brazil 52.791680 Germany Germany 3.0
4 Costa Rica Netherlands 17.418232 Netherlands draw 1.0
5 Belgium Argentina 29.081041 Argentina Argentina 0.0
6 Colombia Brazil 54.574633 Colombia Brazil 0.0
7 Germany France 81.681317 Germany Germany 3.0
8 USA Belgium 30.412694 Belgium Belgium 0.0
9 Switzerland Argentina 23.703298 Argentina Argentina 0.0
10 Algeria Germany 5.044527 Germany Germany 0.0
11 Nigeria France 10.745266 France France 0.0
12 Greece Costa Rica 57.996999 Greece draw 1.0
13 Mexico Netherlands 15.457466 Netherlands Netherlands 0.0
14 Uruguay Colombia 21.643826 Colombia Colombia 0.0
15 Chile Brazil 33.248079 Brazil draw 1.0
16 Germany USA 85.693707 Germany Germany 3.0
17 Ghana Portugal 63.890478 Ghana Portugal 0.0
18 Switzerland Honduras 67.070892 Switzerland Switzerland 3.0
19 France Ecuador 70.147018 France draw 1.0
20 Argentina Nigeria 89.621653 Argentina Argentina 3.0
21 Côte d'Ivoire Greece 36.873530 Greece Greece 0.0
22 Uruguay Italy 44.068286 Italy Uruguay 3.0
23 England Costa Rica 50.811389 England draw 1.0
24 Brazil Cameroon 91.057925 Brazil Brazil 3.0
25 Mexico Croatia 34.390212 Croatia Mexico 3.0
26 Spain Australia 86.025932 Spain Spain 3.0
27 Chile Netherlands 28.282544 Netherlands Netherlands 0.0
28 Portugal USA 52.652170 Portugal draw 1.0
29 Algeria South Korea 26.317364 South Korea Algeria 3.0
30 Ghana Germany 24.399186 Germany draw 1.0
31 Iran Argentina 12.232761 Argentina Argentina 0.0
32 Ecuador Honduras 54.617619 Ecuador Ecuador 3.0
33 France Switzerland 56.941174 France France 3.0
34 Costa Rica Italy 33.018788 Italy Costa Rica 3.0
35 Greece Japan 79.512996 Greece draw 1.0
36 England Uruguay 48.133873 Uruguay Uruguay 0.0
37 Croatia Cameroon 75.721526 Croatia Croatia 3.0
38 Chile Spain 33.871803 Spain Chile 3.0
39 Netherlands Australia 88.036065 Netherlands Netherlands 3.0
40 Mexico Brazil 25.555167 Brazil draw 1.0
41 USA Ghana 37.708800 Ghana USA 3.0
42 Nigeria Iran 30.426153 Iran draw 1.0
43 Portugal Germany 18.933847 Germany Germany 0.0
44 Honduras France 35.414093 France France 0.0
45 Ecuador Switzerland 49.518118 Switzerland Switzerland 0.0
46 Japan Côte d'Ivoire 32.050843 Côte d'Ivoire Côte d'Ivoire 0.0
47 Italy England 68.182745 Italy Italy 3.0
48 Costa Rica Uruguay 41.624123 Uruguay Costa Rica 3.0
49 Australia Chile 28.013709 Chile Chile 0.0
50 Netherlands Spain 45.491918 Spain Netherlands 3.0
51 Cameroon Mexico 36.828052 Mexico Mexico 0.0
52 Croatia Brazil 26.510888 Brazil Brazil 0.0
53 Spain Netherlands 53.126882 Spain Spain 3.0
54 Germany Uruguay 69.230393 Germany Germany 3.0
55 Spain Germany 49.094405 Germany Spain 3.0
56 Netherlands Uruguay 71.470148 Netherlands Netherlands 3.0
57 Spain Paraguay 78.167146 Spain Spain 3.0
58 Germany Argentina 41.107626 Argentina Germany 3.0
59 Ghana Uruguay 47.702576 Uruguay draw 1.0
60 Brazil Netherlands 49.262939 Netherlands Netherlands 0.0
61 Portugal Spain 11.149447 Spain Spain 0.0
62 Japan Paraguay 22.665241 Paraguay draw 1.0
63 Chile Brazil 34.753812 Brazil Brazil 0.0
64 Slovakia Netherlands 17.862216 Netherlands Netherlands 0.0
65 Mexico Argentina 19.963579 Argentina Argentina 0.0
66 England Germany 19.612815 Germany Germany 0.0
67 Ghana USA 70.369020 Ghana Ghana 3.0
68 South Korea Uruguay 27.634301 Uruguay Uruguay 0.0
69 Brazil Portugal 77.683818 Brazil draw 1.0
70 Germany Ghana 73.474151 Germany Germany 3.0
71 Serbia Australia 31.253679 Australia Australia 0.0
72 Côte d'Ivoire Brazil 16.341842 Brazil Brazil 0.0
73 Australia Ghana 38.165116 Ghana draw 1.0
74 Japan Netherlands 6.998814 Netherlands Netherlands 0.0
75 Serbia Germany 6.130914 Germany Serbia 3.0
76 Mexico France 52.503379 Mexico Mexico 3.0
77 South Korea Argentina 14.223277 Argentina Argentina 0.0
78 Switzerland Spain 15.908251 Spain Switzerland 3.0
79 Portugal Côte d'Ivoire 69.916891 Portugal draw 1.0
80 Paraguay Italy 43.871427 Italy draw 1.0
81 Australia Germany 16.694780 Germany Germany 0.0
82 Ghana Serbia 85.417376 Ghana Ghana 3.0
83 USA England 52.553244 USA draw 1.0
84 France Italy 34.562803 Italy draw 1.0
85 Portugal Germany 16.075847 Germany Germany 0.0
86 France Portugal 56.422181 France France 3.0
87 Italy Germany 21.500138 Germany Italy 3.0
88 France Brazil 23.160437 Brazil France 3.0
89 Portugal England 52.083159 Portugal draw 1.0
90 Ukraine Italy 26.756031 Italy Italy 0.0
91 Argentina Germany 41.445493 Germany draw 1.0
92 France Spain 20.617480 Spain France 3.0
93 Ghana Brazil 16.941207 Brazil Brazil 0.0
94 Ukraine Switzerland 48.073103 Switzerland draw 1.0
95 Australia Italy 22.532935 Italy Italy 0.0
96 Netherlands Portugal 75.542414 Netherlands Portugal 0.0
97 Ecuador England 39.677182 England England 0.0
98 Mexico Argentina 31.243456 Argentina Argentina 0.0
99 Sweden Germany 8.403587 Germany Germany 0.0
Helper codes are under features.py, matchstats.py, [power.py)(power.py), worldcup.py
Kaynaklar
[1] Google Cloud Platform Blog, Google Cloud Platform goes 8 for 8 in World Cup predictions, http://googlecloudplatform.blogspot.de/2014/07/google-cloud-platform-goes-8-for-8-in-soccer-predictions.html
[2] Google Cloud Platform, Sample iPython notebook with soccer predictions, https://github.com/GoogleCloudPlatform/ipython-soccer-predictions
[3] Google, Predicting the World Cup with the Google Cloud Platform, http://nbviewer.ipython.org/github/GoogleCloudPlatform/ipython-soccer-predictions/blob/master/predict/wc-final.ipynb
Yukarı