“… Jika saya harus duduk di sana dan menghadapi diri sendiri dan berkata pada diri sendiri, 'Kamu gagal,' menurut saya itu lebih buruk, itu hampir lebih buruk daripada kematian.”

- Kobe Bean Bryant

Saya berada di kereta ketika saya mengetahui tentang kecelakaan helikopter tragis yang merenggut nyawa 9 penumpang. Saya ingat melewatkan perhentian saya dan menatap ponsel saya ketika semua cerita berdatangan. Awalnya tidak tampak nyata.

Menjadi penggemar Toronto Raptors berarti Anda memiliki hubungan yang menarik dengan Kobe Bryant. Terperosok dalam keadaan biasa-biasa saja di pertengahan tahun 2000-an, segala sesuatunya tidak selalu menjadi “We The North-y” bagi para pendukung setia Raptors. Pada tanggal 22 Januari 2006, kami selamanya terikat dengan Kobe. Permainan 81 poinnya akan menjadi penampilan dengan skor tertinggi kedua dalam sejarah liga. Hal ini membuat saya berpikir tentang tahun-tahun awalnya di liga, dan bagaimana seorang pendatang baru yang tampaknya biasa-biasa saja berubah menjadi salah satu pencetak gol terbanyak NBA sepanjang masa.

Mungkin mengejutkan bahwa tahun rookie Bean hampir tidak melebihi ekspektasi liga. Jika dibandingkan dengan Yordania, perbedaannya sangat mencolok…

Proyek ini berpusat pada pertanyaan apakah kita dapat menggunakan data historis dari NBA sejak tahun 1980 untuk memprediksi hasil karier seorang pemain. Lebih khusus lagi, bisakah kita menggunakan statistik tahun pemula seorang pemain untuk menentukan berapa total poin akhir mereka? Poin menjadi metrik yang mencakup nilai ofensif pemain di liga.

Pada akhirnya, saya memutuskan untuk menggunakan data tersebut untuk melihat apakah kita dapat menggunakan statistik tahun pemula seorang pemain untuk memprediksi hasil biner: apakah pemain tersebut akan di atas rata-rata atau di bawah rata-ratadalam mencetak gol pada akhir karir mereka. Dengan cara ini, tim dapat menyadari potensi 'kemerosotan tingkat dua' dan 'kegagalan' pada pemain baru mereka yang baru direkrut.

https://www.kaggle.com/drgilermo/nba-players-stats?select=Seasons_Stats.csv

Kumpulan dataGoldstein adalah kumpulan data NBA terlengkap yang diambil dari Referensi Bola Basket. Kumpulan data ini mencakup hampir semua metrik analitik lanjutan untuk setiap pemain di liga dari tahun 1950 hingga 2017.

Setelah beberapa proses awal dan pembersihan, saya mengisolasi tahun pemula setiap pemain sejak tahun 1980. Tahun khusus ini dipilih karena merupakan tahun di mana garis 3 poin diterapkan sepenuhnya ke dalam pelacakan statistik. Sebagai referensi, kita memiliki 2.331 pemain dan 37 musim data. Selain itu, saya memutuskan untuk hanya memasukkan 22 variabel yang terkait dengan statistik pemain secara keseluruhan. Ini termasuk:

'FG', 'FGA', 'FG%', '3P', '3PA', '3P%', '2P', '2PA', '2P%', 'eFG%', 'FT' , 'FTA', 'FT%', 'ORB', 'DRB', 'TRB', 'AST', 'STL', 'BLK', 'TOV', 'PF', 'PTS'

Variabel ke-23, total poin karier, kemudian ditambahkan ke akhir kerangka data sebagai 'total_pts'. Inilah yang akan kami coba prediksikan oleh model kami.

Melalui pemilihan fitur regresi linier, 9 variabel dipilih yang paling relevan untuk memprediksi total_pts.

array = stats_df.values
X = array[:,0:21]
Y = array[:,21]
#feature selection
model = LinearRegression()
rfe = RFE(model, 9)
fit = rfe.fit(X, Y)
print("Num Features: %d" % fit.n_features_)
print("Selected Features: %s" % fit.support_)
print("Feature Ranking: %s" % fit.ranking_)

9 fitur teratas yang dipilih ditampilkan di bawah bersama total_pts:

Langkah selanjutnya terbuka untuk interpretasi, tetapi demi kesederhanaan, saya memutuskan untuk mengubah kolom total_pts menjadi kolom biner dengan total_pts di atas rata-rata atau total_pts di bawah rata-rata.

Total poin rata-rata yang dicetak seorang pemain selama jangka waktu 37 tahun ini adalah 3523. Jadi, apa pun yang di atas rata-rata akan diklasifikasikan sebagai (1) dan di bawah rata-rata akan menjadi (0).

final_df['TOTAL_PTS'].values[final_df['TOTAL_PTS'] < 3522] = 0
final_df['TOTAL_PTS'].values[final_df['TOTAL_PTS'] >= 3523] = 1
final_df.head()

Di bawah ini saya telah menyertakan pemisahan pelatihan/tes serta kode pengambilan sampel ulang:

#split into TRAIN/TEST
msk = np.random.rand(len(final_df)) < 0.70
train_df = final_df[msk]
test_df = final_df[~msk]
#split test into X_test and y_test for later
y_test = test_df['TOTAL_PTS']
X_test = test_df.drop('TOTAL_PTS',axis=1)
#class count
count_class_0, count_class_1 = train_df.TOTAL_PTS.value_counts()
#divide by class
df_class_0 = train_df[train_df['TOTAL_PTS'] == 0]
df_class_1 = train_df[train_df['TOTAL_PTS'] == 1]
df_class_1_over = df_class_1.sample(count_class_0, replace=True)
df_test_over = pd.concat([df_class_1_over, df_class_0], axis=0)
print('Random over-sampling:')
print(df_test_over.TOTAL_PTS.value_counts())
df_test_over.TOTAL_PTS.value_counts().plot(kind='bar', title='Count (TOTAL_PTS)')

Selanjutnya, saya menyesuaikan data yang diambil sampelnya ke beberapa algoritma ML yang berbeda. Di bawah ini, saya telah menyertakan skrip untuk model dengan kinerja terbaik, pengklasifikasi regresi logistik:

df2_test_over = pd.DataFrame(df_test_over)
#split into X_train and y_train
X_over_train = df2_test_over.drop('TOTAL_PTS',axis=1)
y_over_train = df2_test_over['TOTAL_PTS']
#fitting Logistic Regression to the training set
reg_classifier = LogisticRegression(penalty = 'l2', solver = 'liblinear')
reg_classifier.fit(X_over_train, y_over_train)
#predicting the test set results
predictions = reg_classifier.predict(X_test)
#confusion matrix
conf_mat = confusion_matrix(y_true=y_test, y_pred=predictions)
print('Confusion matrix:\n', conf_mat)
labels = ['Class 0', 'Class 1']
fig = plt.figure()
ax = fig.add_subplot(111)
cax = ax.matshow(conf_mat, cmap=plt.cm.Blues)
fig.colorbar(cax)
ax.set_xticklabels([''] + labels)
ax.set_yticklabels([''] + labels)
plt.xlabel('Predicted')
plt.ylabel('Expected')
plt.show()

#calculate accuracy/precision/recall/f1
# accuracy: (tp + tn) / (p + n)
accuracy = (accuracy_score(y_test, predictions)).astype('float64')
print('{:>10}: {:0.2%}'.format('Accuracy',accuracy))
# precision tp / (tp + fp)
precision = (precision_score(y_test, predictions)).astype('float64')
print('{:>10}: {:0.2%}'.format('Precision',precision))
# recall: tp / (tp + fn)
recall = (recall_score(y_test, predictions)).astype('float64')
print('{:>10}: {:0.2%}'.format('Recall',recall))
# f1: 2 tp / (2 tp + fp + fn)
f1 = (f1_score(y_test, predictions)).astype('float64')
print('{:>10}: {:0.2%}'.format('F1 score',f1))
#ROC curve
false_positive_rate, true_positive_rate, thresholds = roc_curve(y_test, predictions)
roc_auc = (auc(false_positive_rate, true_positive_rate)).astype('float64')
print('{:>10}: {:0.2%}'.format('ROC score',roc_auc))

Meskipun tidak sempurna, model ini memiliki kinerja yang baik, dan kami dapat mengatakan dengan akurasi sekitar 76,69% ​​dan ROC sebesar 75,7% sehingga kami dapat memprediksi apakah seorang pemula akan menjadi pencetak gol di atas rata-rata di NBA pada saat karier mereka berakhir. .

Ke depan, saya ingin melihat apakah saya dapat menggunakan ML untuk memprediksi skor pemain pada tahun berikutnya untuk setiap tahun mereka berada di NBA, dan berpotensi membuat model tersebut memprediksi variabel kelas jamak (yaitu apa tepatnya mereka) penilaiannya akan dilakukan untuk tahun depan) bukan hanya variabel biner 1|0.

Buku catatan selengkapnya dapat dilihat di sini:



Jangan ragu untuk mengikuti saya di Github di @vladtheladd, email saya langsung, atau temukan saya di Linkedin. Saya ingin mendengar pendapat Anda jika menurut Anda saya dapat membantu Anda atau tim Anda dengan pekerjaan terkait Ilmu Data!