FIFA18のデータからサンフレッチェの選手の価格を予想してみた
データ分析のコンペティションで有名なKaggleはさまざまなデータが公開されています。例えば EA SPORTSからFIFA18のデータが公開されています。そこで今回はこのデータを使用して何か分析をしてみようと思います。(私はFIFA18をしないですが。。。)
https://www.kaggle.com/thec03u5/fifa-18-demo-player-dataset
FIFA18のデータは海外の有名選手やJリーグの選手含めて登録されています。また、データの項目として選手の能力や価格があります。そこでサンフレッチェの選手が他の選手の能力と比較してどのぐらいの価格が妥当か予測してみました。分析するデータはFIFA18に登録されているデータを元にしてますので、結果が悪くてもEA SPORTSに言ってくださいw。また、FIFA18といいつつも選手のデータは2017年のデータですので今年度のデータはありません。
FIFA18に登録されているサンフレッチェ広島の価格について
フィールドプレーヤーはごらんのとおりです。単位はEUROです。DF陣が低いですね。そして、皆川が思ったより高いのが
name | eur_value | |
---|---|---|
4689 | Felipe Silva | 2500000 |
4877 | T. Aoyama | 1500000 |
5053 | Y. Kashiwa | 1700000 |
5397 | Patric | 1800000 |
5436 | K. Shibasaki | 1400000 |
5965 | Anderson Lopes | 1400000 |
6269 | D. Niwa | 700000 |
6477 | M. Mikić | 350000 |
7871 | M. Kudo | 900000 |
8072 | K. Chiba | 450000 |
8961 | H. Mizumoto | 425000 |
10110 | K. Morisaki | 70000 |
10651 | T. Miyayoshi | 725000 |
10877 | N. Burns | 550000 |
11074 | S. Inagaki | 575000 |
12756 | K. Mukuhara | 300000 |
13090 | Y. Chajima | 375000 |
13429 | Y. Minagawa | 375000 |
14240 | T. Morishima | 375000 |
14859 | T. Marutani | 190000 |
15740 | S. Sasaki | 110000 |
15769 | Y. Nogami | 130000 |
16312 | S. Takahashi | 140000 |
16706 | O. Iyoha | 180000 |
17938 | T. Matsumoto | 60000 |
GKはこちらの通りです。
name | eur_value | |
---|---|---|
10100 | T. Hayashi | 220000 |
14571 | R. Hironaga | 160000 |
15826 | H. Nakabayashi | 80000 |
データの解析
まず、データを読み込みます。気を付けたい点は文字コードをUTF-8で読み込むことです。そうしないとクロアチア人のデータが読み込めません。
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import numpy as np from scipy.stats import norm from sklearn.preprocessing import StandardScaler from scipy import stats %matplotlib inline base = pd.read_csv('complete.csv', encoding='utf_8')
サンフレとそれ以外のデータに分けます。また、フィールドプレーヤーとGKに分けます。
base2 = base.copy() sanf_base = base2[base2['club'].isin(['Sanfrecce Hiroshima'])] base3 = base2[(base2['club'] != 'Sanfrecce Hiroshima')] sanf_f = sanf_base[sanf_base['gk'].isnull()] sanf_g = sanf_base[sanf_base['cf'].isnull()] base_f = base3[base3['gk'].isnull()] base_g = base3[base3['cf'].isnull()]
サンフレの選手はこんな感じです。
ID | name | full_name | club | special | age | league | |
---|---|---|---|---|---|---|---|
4689 | 192982 | Felipe Silva | Felipe de Oliveira Silva | Sanfrecce Hiroshima | 1659 | 27 | Japanese J1 League |
4877 | 222988 | T. Aoyama | Toshihiro Aoyama | Sanfrecce Hiroshima | 1879 | 31 | Japanese J1 League |
5053 | 232512 | Y. Kashiwa | Yoshifumi Kashiwa | Sanfrecce Hiroshima | 1714 | 29 | Japanese J1 League |
5397 | 202401 | Patric | Anderson Patric Aguiar Oliveira | Sanfrecce Hiroshima | 1670 | 29 | Japanese J1 League |
5436 | 232619 | K. Shibasaki | Kosei Shibasaki | Sanfrecce Hiroshima | 1812 | 32 | Japanese J1 League |
5965 | 229949 | Anderson Lopes | Anderson José Lopes de Souza | Sanfrecce Hiroshima | 1722 | 23 | Japanese J1 League |
6269 | 232598 | D. Niwa | Daiki Niwa | Sanfrecce Hiroshima | 1459 | 31 | Japanese J1 League |
6477 | 141265 | M. Mikić | Mihael Mikić | Sanfrecce Hiroshima | 1792 | 37 | Japanese J1 League |
7871 | 231972 | M. Kudo | Masato Kudo | Sanfrecce Hiroshima | 1603 | 27 | Japanese J1 League |
8072 | 162388 | K. Chiba | Kazuhiko Chiba | Sanfrecce Hiroshima | 1541 | 32 | Japanese J1 League |
8961 | 197422 | H. Mizumoto | Hiroki Mizumoto | Sanfrecce Hiroshima | 1568 | 31 | Japanese J1 League |
10110 | 232509 | K. Morisaki | Kazuyuki Morisaki | Sanfrecce Hiroshima | 1557 | 36 | Japanese J1 League |
10651 | 232896 | T. Miyayoshi | Takumi Miyayoshi | Sanfrecce Hiroshima | 1522 | 24 | Japanese J1 League |
10877 | 181491 | N. Burns | Nathan Burns | Sanfrecce Hiroshima | 1777 | 29 | Japanese J1 League |
11074 | 232991 | S. Inagaki | Sho Inagaki | Sanfrecce Hiroshima | 1747 | 25 | Japanese J1 League |
12756 | 237788 | K. Mukuhara | Kenta Mukuhara | Sanfrecce Hiroshima | 1478 | 27 | Japanese J1 League |
13090 | 232513 | Y. Chajima | Yusuke Chajima | Sanfrecce Hiroshima | 1649 | 25 | Japanese J1 League |
13429 | 232614 | Y. Minagawa | Yusuke Minagawa | Sanfrecce Hiroshima | 1400 | 25 | Japanese J1 League |
14240 | 232898 | T. Morishima | Tsukasa Morishima | Sanfrecce Hiroshima | 1453 | 20 | Japanese J1 League |
14859 | 232613 | T. Marutani | Takuya Marutani | Sanfrecce Hiroshima | 1509 | 28 | Japanese J1 League |
15740 | 232511 | S. Sasaki | Sho Sasaki | Sanfrecce Hiroshima | 1402 | 27 | Japanese J1 League |
15769 | 235089 | Y. Nogami | Yuki Nogami | Sanfrecce Hiroshima | 1341 | 26 | Japanese J1 League |
16312 | 232621 | S. Takahashi | Soya Takahashi | Sanfrecce Hiroshima | 1458 | 21 | Japanese J1 League |
16706 | 236761 | O. Iyoha | Osamu Henry Iyoha | Sanfrecce Hiroshima | 1306 | 19 | Japanese J1 League |
17938 | 237535 | T. Matsumoto | Taishi Matsumoto | Sanfrecce Hiroshima | 1345 | 18 | Japanese J1 League |
ちなみに他のデータはこんな感じです。なぜメッシよりR.ロナウドが上なのか分りません。
ID | name | full_name | club | special | age | ||
---|---|---|---|---|---|---|---|
0 | 20801 | Cristiano Ronaldo | C. Ronaldo dos Santos Aveiro | Real Madrid CF | 2228 | 32 | Spanish Primera División |
1 | 158023 | L. Messi | Lionel Messi | FC Barcelona | 2158 | 30 | Spanish Primera División |
2 | 190871 | Neymar | Neymar da Silva Santos Jr. | Paris Saint-Germain | 2100 | 25 | French Ligue 1 |
3 | 176580 | L. Suárez | Luis Suárez | FC Barcelona | 2291 | 30 | Spanish Primera División |
5 | 188545 | R. Lewandowski | Robert Lewandowski | FC Bayern Munich | 2146 | 28 | German Bundesliga |
選手の価格帯のを調べます。明らかに正規分布にはなってないですね。。こちらはフィールドプレーヤーですがGKも同じような分布になりました。
sns.distplot(base_f['eur_value']);
次に欠損値について調べます。フィールドプレーヤーで調べたのでGKが100%となっています。eur_release_clauseは今回使用しないので列ごと削除します。league、clubのデータが0ですが、これは未所属であり価格が0であり、データ分析に有用とはならないので削除します。また価格が0の選手もすべて削除します。
base_f_na = (base_f.isnull().sum() / len(base_f)) * 100 base_f_na = base_f_na.drop(base_f_na[base_f_na == 0].index).sort_values(ascending=False)[:30] missing_data = pd.DataFrame({'Missing Ratio' :base_f_na}) missing_data.head(20)
Missing Ratio | |
---|---|
gk | 100.000000 |
eur_release_clause | 8.590419 |
league | 1.348131 |
club | 1.348131 |
分析用にデータを分けます。
base_f =base_f.drop(['eur_release_clause','gk'], axis=1) base_f = base_f.dropna(how='any') base_f = base_f.drop(base_f[(base_f['eur_value']==0)].index) base_g = base_g.drop(base_g[(base_g['eur_value']==0)].index) base_g =base_g.drop(['eur_release_clause','rs','rw','rf','ram','rcm','rm','rdm','rcb','rb','rwb','st','lw','cf','cam','cm','lm','cdm','cb','lb','lwb','ls','lf','lam','lcm','ldm','lcb'], axis=1) base_g = base_g.dropna(how='any') train_f_ID =base_f.loc[:,['ID','name','full_name']] train_g_ID =base_g.loc[:,['ID','name','full_name']] test_f_ID =sanf_f.loc[:,['ID','name','full_name']] test_g_ID =sanf_g.loc[:,['ID','name','full_name']] y_f_train = base_f['eur_value'] y_g_train = base_g['eur_value'] y_f_test = sanf_f['eur_value'] y_g_test = sanf_g['eur_value'] X_f_train =base_f.drop(['ID','name','full_name','eur_value','eur_wage'], axis=1) X_g_train =base_g.drop(['ID','name','full_name','eur_value','eur_wage'], axis=1) X_f_test =sanf_f.drop(['ID','name','full_name','eur_value','eur_wage','eur_release_clause','gk'], axis=1) X_g_test =sanf_g.drop(['ID','name','full_name','eur_value','eur_wage','eur_release_clause','rs','rw','rf','ram','rcm','rm','rdm','rcb','rb','rwb','st','lw','cf','cam','cm','lm','cdm','cb','lb','lwb','ls','lf','lam','lcm','ldm','lcb'], axis=1)
文字列、ブール型になっている値を LabelEncoder使って実数に変換します。
from sklearn.preprocessing import LabelEncoder for i in range(X_f_train.shape[1]): if X_f_train.iloc[:,i].dtypes == object: lbl = LabelEncoder() lbl.fit(list(X_f_train.iloc[:,i].values) + list(X_f_test.iloc[:,i].values)) X_f_train.iloc[:,i] = lbl.transform(list(X_f_train.iloc[:,i].values)) X_f_test.iloc[:,i] = lbl.transform(list(X_f_test.iloc[:,i].values)) for i in range(X_f_train.shape[1]): if X_f_train.iloc[:,i].dtypes == bool: lbl = LabelEncoder() lbl.fit(list(X_f_train.iloc[:,i].values) + list(X_f_test.iloc[:,i].values)) X_f_train.iloc[:,i] = lbl.transform(list(X_f_train.iloc[:,i].values)) X_f_test.iloc[:,i] = lbl.transform(list(X_f_test.iloc[:,i].values)) for i in range(X_g_train.shape[1]): if X_g_train.iloc[:,i].dtypes == bool: lbl = LabelEncoder() lbl.fit(list(X_g_train.iloc[:,i].values) + list(X_g_test.iloc[:,i].values)) X_g_train.iloc[:,i] = lbl.transform(list(X_g_train.iloc[:,i].values)) X_g_test.iloc[:,i] = lbl.transform(list(X_g_test.iloc[:,i].values)) for i in range(X_g_train.shape[1]): if X_g_train.iloc[:,i].dtypes == object: lbl = LabelEncoder() lbl.fit(list(X_g_train.iloc[:,i].values) + list(X_g_test.iloc[:,i].values)) X_g_train.iloc[:,i] = lbl.transform(list(X_g_train.iloc[:,i].values)) X_g_test.iloc[:,i] = lbl.transform(list(X_g_test.iloc[:,i].values))
価格をlogを使用して擬似的に正規分布にします。
y_f_train = np.log(y_f_train) y_g_train = np.log(y_g_train)
重要な項目について累乗します。
X_f_train['overall2'] = X_f_train['overall'] ** 2 X_f_train['potential2'] = X_f_train['potential'] ** 2 X_f_test['overall2'] = X_f_test['overall'] ** 2 X_f_test['potential2'] = X_f_test['potential'] ** 2 X_g_train['gk2'] = X_g_train['gk'] ** 2 X_g_train['overall2'] = X_g_train['overall'] ** 2 X_g_train['potential2'] = X_g_train['potential'] ** 2 X_g_test['gk2'] = X_g_test['gk'] ** 2 X_g_test['overall2'] = X_g_test['overall'] ** 2 X_g_test['potential2'] = X_g_test['potential'] ** 2
あとはXGBoostとLightGBMを使用して価格を予測します。こちらはフィールドプレーヤーですがGKもおんなじような感じです。
reg = xgb.XGBRegressor(max_depth=2,n_estimators=300,min_child_weight=1,gamma=0.1,subsample=0.2,colsample_bytree=0.4,learning_rate=0.1,reg_alpha=0.0001) reg.fit(X_f_train, y_f_train) import lightgbm as lgb lgb_train = lgb.Dataset(X_f_train, y_f_train) lgb_eval = lgb.Dataset(X_f_test, y_f_test, reference=lgb_train) params = { 'task': 'train', 'boosting_type': 'gbdt', 'objective': 'regression', 'metric': {'l2'}, 'num_leaves': 128, 'learning_rate': 0.01, 'num_iterations':100, 'feature_fraction': 0.38, 'bagging_fraction': 0.68, 'bagging_freq': 5, 'verbose': 0 } gbm = lgb.train(params, lgb_train, num_boost_round=1500, valid_sets=lgb_eval, early_stopping_rounds=15) X_f_train2 = pd.DataFrame( {'XGB': reg.predict(X_f_train), 'LGB': gbm.predict(np.array(X_f_train), num_iteration=gbm.best_iteration), }) from sklearn import linear_model reg_all = linear_model.LinearRegression() reg_all.fit(X_f_train2, y_f_train) X_f_test2 = pd.DataFrame( {'XGB': reg.predict(X_f_test), 'LGB': gbm.predict(np.array(X_f_test), num_iteration=gbm.best_iteration), }) predictions = np.exp(reg_all.predict(X_f_test2)) submission = pd.DataFrame({ 'ID': test_f_ID['ID'], 'name' : test_f_ID['name'], 'full_name' : test_f_ID['full_name'], 'eur_value<200b>' : predictions}) submission
結果はこのようになりました。皆川が高いのが違和感あるなあ。
ID | eur_value? | full_name | name | |
---|---|---|---|---|
0 | 192982 | 2376986 | Felipe de Oliveira Silva | Felipe Silva |
1 | 222988 | 1324306 | Toshihiro Aoyama | T. Aoyama |
2 | 232512 | 1634586 | Yoshifumi Kashiwa | Y. Kashiwa |
3 | 202401 | 1693254 | Anderson Patric Aguiar Oliveira | Patric |
4 | 232619 | 1366923 | Kosei Shibasaki | K. Shibasaki |
5 | 229949 | 1548074 | Anderson Jos? Lopes de Souza | Anderson Lopes |
6 | 232598 | 685995 | Daiki Niwa | D. Niwa |
7 | 141265 | 329592 | Mihael Miki? | M. Miki? |
8 | 231972 | 842412 | Masato Kudo | M. Kudo |
9 | 162388 | 463991 | Kazuhiko Chiba | K. Chiba |
10 | 197422 | 439531 | Hiroki Mizumoto | H. Mizumoto |
11 | 232509 | 99654 | Kazuyuki Morisaki | K. Morisaki |
12 | 232896 | 694564 | Takumi Miyayoshi | T. Miyayoshi |
13 | 181491 | 537812 | Nathan Burns | N. Burns |
14 | 232991 | 641852 | Sho Inagaki | S. Inagaki |
15 | 237788 | 311987 | Kenta Mukuhara | K. Mukuhara |
16 | 232513 | 356286 | Yusuke Chajima | Y. Chajima |
17 | 232614 | 374843 | Yusuke Minagawa | Y. Minagawa |
18 | 232898 | 367593 | Tsukasa Morishima | T. Morishima |
19 | 232613 | 182939 | Takuya Marutani | T. Marutani |
20 | 232511 | 108015 | Sho Sasaki | S. Sasaki |
21 | 235089 | 131221 | Yuki Nogami | Y. Nogami |
22 | 232621 | 152696 | Soya Takahashi | S. Takahashi |
23 | 236761 | 198621 | Osamu Henry Iyoha | O. Iyoha |
24 | 237535 | 65290 | Taishi Matsumoto | T. Matsumoto |
GKはこのような結果となりました。廣永のほうが高いのが意外ですね。
ID | eur_value | full_name | name | |
---|---|---|---|---|
10100 | 232505 | 233405 | Takuto Hayashi | T. Hayashi |
14571 | 232507 | 169154 | Ryotaro Hironaga | R. Hironaga |
15826 | 237426 | 78575 | Hirotsugu Nakabayashi | H. Nakabayashi |