In [179]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# To scale the data using z-score
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
# Algorithms to use
from sklearn.metrics import RocCurveDisplay
from sklearn.metrics import roc_auc_score
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.decomposition import PCA
from sklearn.datasets import make_blobs
# Metrics to evaluate the model
from sklearn import metrics
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, precision_recall_curve,recall_score, roc_curve
# To ignore warnings
import warnings
warnings.filterwarnings("ignore")
In [136]:
# Loading the dataset
data =pd.read_csv(r'C:/Users/jacob/Desktop/UNI WORK/online_gaming_behavior_dataset.csv')
data.info()
data.nunique()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 40034 entries, 0 to 40033 Data columns (total 13 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 PlayerID 40034 non-null int64 1 Age 40034 non-null int64 2 Gender 40034 non-null object 3 Location 40034 non-null object 4 GameGenre 40034 non-null object 5 PlayTimeHours 40034 non-null float64 6 InGamePurchases 40034 non-null int64 7 GameDifficulty 40034 non-null object 8 SessionsPerWeek 40034 non-null int64 9 AvgSessionDurationMinutes 40034 non-null int64 10 PlayerLevel 40034 non-null int64 11 AchievementsUnlocked 40034 non-null int64 12 EngagementLevel 40034 non-null object dtypes: float64(1), int64(7), object(5) memory usage: 4.0+ MB
Out[136]:
PlayerID 40034 Age 35 Gender 2 Location 4 GameGenre 5 PlayTimeHours 40034 InGamePurchases 2 GameDifficulty 3 SessionsPerWeek 20 AvgSessionDurationMinutes 170 PlayerLevel 99 AchievementsUnlocked 50 EngagementLevel 3 dtype: int64
In [137]:
data.head()
Out[137]:
| PlayerID | Age | Gender | Location | GameGenre | PlayTimeHours | InGamePurchases | GameDifficulty | SessionsPerWeek | AvgSessionDurationMinutes | PlayerLevel | AchievementsUnlocked | EngagementLevel | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 9000 | 43 | Male | Other | Strategy | 16.271119 | 0 | Medium | 6 | 108 | 79 | 25 | Medium |
| 1 | 9001 | 29 | Female | USA | Strategy | 5.525961 | 0 | Medium | 5 | 144 | 11 | 10 | Medium |
| 2 | 9002 | 22 | Female | USA | Sports | 8.223755 | 0 | Easy | 16 | 142 | 35 | 41 | High |
| 3 | 9003 | 35 | Male | USA | Action | 5.265351 | 1 | Easy | 9 | 85 | 57 | 47 | Medium |
| 4 | 9004 | 33 | Male | Europe | Action | 15.531945 | 0 | Medium | 2 | 131 | 95 | 37 | Medium |
In [138]:
data=data.drop(['PlayerID',],axis=1)
In [139]:
# Creating numerical columns
num_cols=['Age','PlayTimeHours', 'InGamePurchases','SessionsPerWeek', 'AvgSessionDurationMinutes', 'PlayerLevel', 'AchievementsUnlocked',]
In [140]:
#Creating object columns to compare
cat_cols = ['Gender','Location','GameGenre', 'GameDifficulty', 'EngagementLevel']
# Checking summary statistics
data[num_cols].describe().T
Out[140]:
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| Age | 40034.0 | 31.992531 | 10.043227 | 15.000000 | 23.000000 | 32.000000 | 41.000000 | 49.000000 |
| PlayTimeHours | 40034.0 | 12.024365 | 6.914638 | 0.000115 | 6.067501 | 12.008002 | 17.963831 | 23.999592 |
| InGamePurchases | 40034.0 | 0.200854 | 0.400644 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 |
| SessionsPerWeek | 40034.0 | 9.471774 | 5.763667 | 0.000000 | 4.000000 | 9.000000 | 14.000000 | 19.000000 |
| AvgSessionDurationMinutes | 40034.0 | 94.792252 | 49.011375 | 10.000000 | 52.000000 | 95.000000 | 137.000000 | 179.000000 |
| PlayerLevel | 40034.0 | 49.655568 | 28.588379 | 1.000000 | 25.000000 | 49.000000 | 74.000000 | 99.000000 |
| AchievementsUnlocked | 40034.0 | 24.526477 | 14.430726 | 0.000000 | 12.000000 | 25.000000 | 37.000000 | 49.000000 |
In [174]:
data.describe(include=['object'])
Out[174]:
| Gender | Location | GameGenre | GameDifficulty | EngagementLevel | |
|---|---|---|---|---|---|
| count | 40034 | 40034 | 40034 | 40034 | 40034 |
| unique | 2 | 4 | 5 | 3 | 3 |
| top | Male | USA | Sports | Easy | Medium |
| freq | 23959 | 16000 | 8048 | 20015 | 19374 |
In [141]:
# Creating histograms
data[num_cols].hist(figsize=(20,20))
plt.show()
In [ ]:
In [142]:
#Confirming that PlayerID has been dropped as a feature
print(data)
Age Gender Location GameGenre PlayTimeHours InGamePurchases \
0 43 Male Other Strategy 16.271119 0
1 29 Female USA Strategy 5.525961 0
2 22 Female USA Sports 8.223755 0
3 35 Male USA Action 5.265351 1
4 33 Male Europe Action 15.531945 0
... ... ... ... ... ... ...
40029 32 Male USA Strategy 20.619662 0
40030 44 Female Other Simulation 13.539280 0
40031 15 Female USA RPG 0.240057 1
40032 34 Male USA Sports 14.017818 1
40033 19 Male USA Sports 10.083804 0
GameDifficulty SessionsPerWeek AvgSessionDurationMinutes PlayerLevel \
0 Medium 6 108 79
1 Medium 5 144 11
2 Easy 16 142 35
3 Easy 9 85 57
4 Medium 2 131 95
... ... ... ... ...
40029 Easy 4 75 85
40030 Hard 19 114 71
40031 Easy 10 176 29
40032 Medium 3 128 70
40033 Easy 13 84 72
AchievementsUnlocked EngagementLevel
0 25 Medium
1 10 Medium
2 41 High
3 47 Medium
4 37 Medium
... ... ...
40029 14 Medium
40030 27 High
40031 1 High
40032 10 Medium
40033 39 Medium
[40034 rows x 12 columns]
In [143]:
#Features used for training
features=['Age', 'SessionsPerWeek', 'AvgSessionDurationMinutes']
X=data[features]
Y=data['EngagementLevel']
In [144]:
#Initialising training, with test size of 0.3 of the dataset
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3, random_state=42)
In [145]:
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
In [146]:
#Label Encoder for object features (EngagementLevel)
le = LabelEncoder()
Y_train = le.fit_transform(Y_train)
Y_test = le.transform(Y_test)
In [147]:
param_grid = {
'max_depth': [3, 5, 7, 10, None],
'min_samples_split': [2, 5, 10, 20],
'min_samples_leaf': [1, 2, 5, 10],
'criterion': ['gini', 'entropy']
}
In [148]:
# Initialize model
dt = DecisionTreeClassifier(random_state=42)
In [149]:
# Grid Search to find best Decision Tree Classifier Parameters
grid_search = GridSearchCV(
dt,
param_grid,
scoring='accuracy',
cv=5,
n_jobs=-1
)
In [150]:
# Train the model with the training dataset
grid_search.fit(X_train, Y_train)
Out[150]:
GridSearchCV(cv=5, estimator=DecisionTreeClassifier(random_state=42), n_jobs=-1,
param_grid={'criterion': ['gini', 'entropy'],
'max_depth': [3, 5, 7, 10, None],
'min_samples_leaf': [1, 2, 5, 10],
'min_samples_split': [2, 5, 10, 20]},
scoring='accuracy')In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
GridSearchCV(cv=5, estimator=DecisionTreeClassifier(random_state=42), n_jobs=-1,
param_grid={'criterion': ['gini', 'entropy'],
'max_depth': [3, 5, 7, 10, None],
'min_samples_leaf': [1, 2, 5, 10],
'min_samples_split': [2, 5, 10, 20]},
scoring='accuracy')DecisionTreeClassifier(criterion='entropy', max_depth=7, min_samples_leaf=5,
random_state=42)DecisionTreeClassifier(criterion='entropy', max_depth=7, min_samples_leaf=5,
random_state=42)In [151]:
# Displays best hypertuning parameters for Decision Tree
best_dt = grid_search.best_estimator_
print("Best Parameters:", grid_search.best_params_)
print("Best CV Accuracy:", grid_search.best_score_)
Best Parameters: {'criterion': 'entropy', 'max_depth': 7, 'min_samples_leaf': 5, 'min_samples_split': 2}
Best CV Accuracy: 0.8815972533955293
In [152]:
#Decicision Tree Plotte
plt.figure(figsize=(30, 15))
tree.plot_tree(best_dt,feature_names=features, filled=True,
rounded=True)
plt.show()
In [186]:
#Restricted tree depth for visialisation on report
pruned_dt = DecisionTreeClassifier(
criterion='entropy',
max_depth=3,
min_samples_split=10,
min_samples_leaf=5,
random_state=42
)
pruned_dt.fit(X_train, Y_train)
Out[186]:
DecisionTreeClassifier(criterion='entropy', max_depth=3, min_samples_leaf=5,
min_samples_split=10, random_state=42)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
DecisionTreeClassifier(criterion='entropy', max_depth=3, min_samples_leaf=5,
min_samples_split=10, random_state=42)In [188]:
plt.figure(figsize=(25,10))
tree.plot_tree(pruned_dt,
feature_names=X.columns,
class_names=['Low','Medium','High'],
filled=True,
rounded=True)
plt.show()
In [154]:
#We can input an [Age, Session Duration, Average Session], which tests Decision Tree and provides an output 0,1,2 for Low, Medium, High engagement levels
print(best_dt.predict([[30, 20, 20]]))
[1]
In [155]:
Y_pred_dt = best_dt.predict(X_test)
In [156]:
#Creates precision, recall, f1-score
print('Accuracy Score on train data: ', accuracy_score(Y_train, best_dt.predict(X_train)))
print("Decision Tree Test Accuracy:", accuracy_score(Y_test, Y_pred_dt))
print(classification_report(Y_test, Y_pred_dt))
Accuracy Score on train data: 0.8860578810262998
Decision Tree Test Accuracy: 0.8794438431437849
precision recall f1-score support
0 0.91 0.87 0.89 3132
1 0.84 0.85 0.84 3069
2 0.88 0.90 0.89 5810
accuracy 0.88 12011
macro avg 0.88 0.87 0.88 12011
weighted avg 0.88 0.88 0.88 12011
In [ ]:
In [157]:
# Initialize and train SVM
svm_model = SVC(kernel='linear', random_state=42)
svm_model.fit(X_train_scaled, Y_train)
# Predictions
Y_pred_svm = svm_model.predict(X_test_scaled)
# Evaluation
print("SVM Accuracy:", accuracy_score(Y_test, Y_pred_svm))
print(classification_report(Y_test, Y_pred_svm))
# Creating Confusion Matrix before hypertuning
plt.figure(figsize=(6,5))
sns.heatmap(confusion_matrix(Y_test, Y_pred_svm), annot=True, fmt='d', cmap='Greens')
plt.title("SVM Confusion Matrix")
plt.xlabel("Predicted")
plt.ylabel("Actual")
plt.show()
SVM Accuracy: 0.8183331945716427
precision recall f1-score support
0 0.88 0.84 0.86 3132
1 0.79 0.70 0.74 3069
2 0.80 0.87 0.84 5810
accuracy 0.82 12011
macro avg 0.82 0.80 0.81 12011
weighted avg 0.82 0.82 0.82 12011
In [158]:
#Hypertuning SVM through RandomSearchCV (Grid was taking forever)
param_grid_svm = {
'C': [0.1, 1, 10],
'kernel': ['linear', 'rbf'],
'gamma': ['scale', 'auto'] # gamma only used for rbf
}
random_svm = RandomizedSearchCV(
SVC(probability=True, random_state=42),
param_distributions=param_grid_svm,
n_iter=3, # check 5 random combinations
cv=3,
scoring='f1_macro',
random_state=42
)
random_svm.fit(X_train_scaled, Y_train)
Out[158]:
RandomizedSearchCV(cv=3, estimator=SVC(probability=True, random_state=42),
n_iter=3,
param_distributions={'C': [0.1, 1, 10],
'gamma': ['scale', 'auto'],
'kernel': ['linear', 'rbf']},
random_state=42, scoring='f1_macro')In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
RandomizedSearchCV(cv=3, estimator=SVC(probability=True, random_state=42),
n_iter=3,
param_distributions={'C': [0.1, 1, 10],
'gamma': ['scale', 'auto'],
'kernel': ['linear', 'rbf']},
random_state=42, scoring='f1_macro')SVC(C=10, probability=True, random_state=42)
SVC(C=10, probability=True, random_state=42)
In [159]:
#Displays best estimated tuning for SVM
print("Best Params:", random_svm.best_params_)
print("Best CV F1 Score:", random_svm.best_score_)
Best Params: {'kernel': 'rbf', 'gamma': 'scale', 'C': 10}
Best CV F1 Score: 0.8781717398448093
In [160]:
#SVM Tuned
Y_pred_svm_tuned = random_svm.predict(X_test_scaled)
print("Tuned SVM Accuracy:", accuracy_score(Y_test, Y_pred_svm_tuned))
print(classification_report(Y_test, Y_pred_svm_tuned))
Tuned SVM Accuracy: 0.8815252685038715
precision recall f1-score support
0 0.91 0.87 0.89 3132
1 0.86 0.83 0.84 3069
2 0.88 0.92 0.90 5810
accuracy 0.88 12011
macro avg 0.88 0.87 0.88 12011
weighted avg 0.88 0.88 0.88 12011
In [161]:
# Confusion Matrix for tuned SVM
cm_svm_tuned = confusion_matrix(Y_test, Y_pred_svm_tuned)
plt.figure(figsize=(6,5))
sns.heatmap(cm_svm_tuned, annot=True, fmt='d', cmap='Greens')
plt.title("SVM Confusion Matrix")
plt.xlabel("Predicted")
plt.ylabel("Actual")
plt.show()
In [162]:
#Decision Tree AUC-ROC
Y_prob_dt = best_dt.predict_proba(X_test)
auc_dt = roc_auc_score(Y_test, Y_prob_dt, multi_class='ovr')
print("DT AUC-ROC:", auc_dt)
DT AUC-ROC: 0.9345166926454157
In [184]:
#SVC AUC-ROC
y_prob_svm = random_svm.predict_proba(X_test_scaled)
auc_svm = roc_auc_score(Y_test, y_prob_svm, multi_class='ovr')
print("SVM AUC-ROC:", auc_svm)
SVM AUC-ROC: 0.936914462552849
In [165]:
#KMeans Clustering
plt.scatter(data['Age'],data['SessionsPerWeek'])
plt.xlabel('Age')
plt.ylabel('SessionsPerWeeks')
plt.show()
In [166]:
#KMeans Clustering
plt.scatter(data['InGamePurchases'],data['AvgSessionDurationMinutes'])
plt.xlabel('InGamePurchases')
plt.ylabel('AvgSessionDurationMinutes')
plt.show()
In [167]:
km_sample = KMeans(n_clusters=3)
km_sample.fit(data[['Age','AvgSessionDurationMinutes']])
predicted_labels = km_sample.labels_
silhouette_val = silhouette_score(data[['Age', 'AvgSessionDurationMinutes']], predicted_labels)
print("Silhouette Score:", silhouette_val)
Silhouette Score: 0.5119049729376428
In [168]:
km_sample = KMeans(n_clusters=3)
km_sample.fit(data[['Age','SessionsPerWeek']])
predicted_labels = km_sample.labels_
silhouette_val = silhouette_score(data[['Age', 'SessionsPerWeek']], predicted_labels)
print("Silhouette Score:", silhouette_val)
Silhouette Score: 0.3952189164270027
In [169]:
labels_sample = km_sample.labels_
data['label'] = labels_sample
sns.scatterplot(x=data['Age'],y=data['AvgSessionDurationMinutes'],hue=data['label'],palette='Set1')
Out[169]:
<Axes: xlabel='Age', ylabel='AvgSessionDurationMinutes'>
In [170]:
labels_sample = km_sample.labels_
data['label'] = labels_sample
sns.scatterplot(x=data['Age'],y=data['SessionsPerWeek'],hue=data['label'],palette='Set1')
Out[170]:
<Axes: xlabel='Age', ylabel='SessionsPerWeek'>
In [171]:
labels_sample = km_sample.labels_
data['label'] = labels_sample
sns.scatterplot(x=data['InGamePurchases'],y=data['Age'],hue=data['label'],palette='Set1')
Out[171]:
<Axes: xlabel='InGamePurchases', ylabel='Age'>
In [172]:
WCSS= []
K = range(1,9)
for i in K:
Kmeanmodel=KMeans(n_clusters=i, init='k-means++', max_iter=500, n_init=10, random_state=42)
Kmeanmodel.fit(data[['Age','AvgSessionDurationMinutes']])
WCSS.append(Kmeanmodel.inertia_)
In [173]:
plt.plot(range(1,9),WCSS)
plt.xlabel('Number of clusters')
plt.ylabel('WCSS')
plt.show()
In [ ]: