In [1]:
import pandas as df
import numpy as np
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
import matplotlib.pyplot as plt

data = df.read_csv(r'C:\Users\GelsthN\OneDrive - DVLA\Desktop\Machine Learning Assignment\data.csv')

# This is where I have cleansed the data for play time as I didn't need to see it to as many decimal places as I have. 
data['PlayTimeHours'] = data['PlayTimeHours'].round(1)

print(data)
       PlayerID  Age  Gender Location   GameGenre  PlayTimeHours  \
0          9000   43    Male    Other    Strategy           16.3   
1          9001   29  Female      USA    Strategy            5.5   
2          9002   22  Female      USA      Sports            8.2   
3          9003   35    Male      USA      Action            5.3   
4          9004   33    Male   Europe      Action           15.5   
...         ...  ...     ...      ...         ...            ...   
40029     49029   32    Male      USA    Strategy           20.6   
40030     49030   44  Female    Other  Simulation           13.5   
40031     49031   15  Female      USA         RPG            0.2   
40032     49032   34    Male      USA      Sports           14.0   
40033     49033   19    Male      USA      Sports           10.1   

       InGamePurchases GameDifficulty  SessionsPerWeek  \
0                    0         Medium                6   
1                    0         Medium                5   
2                    0           Easy               16   
3                    1           Easy                9   
4                    0         Medium                2   
...                ...            ...              ...   
40029                0           Easy                4   
40030                0           Hard               19   
40031                1           Easy               10   
40032                1         Medium                3   
40033                0           Easy               13   

       AvgSessionDurationMinutes  PlayerLevel  AchievementsUnlocked  \
0                            108           79                    25   
1                            144           11                    10   
2                            142           35                    41   
3                             85           57                    47   
4                            131           95                    37   
...                          ...          ...                   ...   
40029                         75           85                    14   
40030                        114           71                    27   
40031                        176           29                     1   
40032                        128           70                    10   
40033                         84           72                    39   

      EngagementLevel  
0              Medium  
1              Medium  
2                High  
3              Medium  
4              Medium  
...               ...  
40029          Medium  
40030            High  
40031            High  
40032          Medium  
40033          Medium  

[40034 rows x 13 columns]
In [2]:
import pandas as df
import numpy as np
from sklearn.model_selection import train_test_split, GridSearchCV, cross_val_score
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
import matplotlib.pyplot as plt
import joblib   # to save the trained model
data = df.read_csv(r'C:\Users\GelsthN\OneDrive - DVLA\Desktop\Machine Learning Assignment\data.csv')

# This is where I have cleansed the data for play time as I didn't need to see it to as many decimal places as I have. 
data['PlayTimeHours'] = data['PlayTimeHours'].round(1)
TARGET = 'EngagementLevel'

#Here I am mapping the non-numerical columns into numeric values so that they can be used by the machine learning model
gender_map = {'Male': 0, 'Female': 1}

location_map = {'Asia': 0, 'Europe': 1, 'USA': 2, 'Other': 3}

genre_map = {
    'Action': 0,
    'RPG': 1,
    'Simulation': 2,
    'Sports': 3,
    'Strategy': 4
}

difficulty_map = {'Easy': 0, 'Medium': 1, 'Hard': 2}

data['Gender'] = data['Gender'].map(gender_map)
data['Location'] = data['Location'].map(location_map)
data['GameGenre'] = data['GameGenre'].map(genre_map)
data['GameDifficulty'] = data['GameDifficulty'].map(difficulty_map)

engagement_map = {'Low': 0, 'Medium': 1, 'High': 2}
data[TARGET] = data[TARGET].map(engagement_map)

# Here I am choosing the data within the Target column which is the classifier for engagement level which is always either High, Medium or Low as the y axis as that is the column that was are targeting to see what influences it
y = data[TARGET]

# Here I am saying that the X axis is made up of all of the other columns within the dataset with the exception of the engagement Level column as it wouldn’t make sense to have that in both the Y and X for comparison
X = data.drop(columns=[TARGET])

print("Columns:", data.columns.tolist())
print("Rows:", len(data))
print(data.head())

#Here I am training the model splitting the X and Y columns randomly but using the number 42 as a way to be able to have someone else use the code and be able to see the same results. The model is using an 80% train and 20% testing ratio.
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

#Here I am training the Decision Tree model
model = DecisionTreeClassifier(
    random_state=42,
    max_depth=12,        # prevents overfitting
    min_samples_leaf=100 # requires meaningful leaf sizes
)

model.fit(X_train, y_train)

y_pred = model.predict(X_test)
Columns: ['PlayerID', 'Age', 'Gender', 'Location', 'GameGenre', 'PlayTimeHours', 'InGamePurchases', 'GameDifficulty', 'SessionsPerWeek', 'AvgSessionDurationMinutes', 'PlayerLevel', 'AchievementsUnlocked', 'EngagementLevel']
Rows: 40034
   PlayerID  Age  Gender  Location  GameGenre  PlayTimeHours  InGamePurchases  \
0      9000   43       0         3          4           16.3                0   
1      9001   29       1         2          4            5.5                0   
2      9002   22       1         2          3            8.2                0   
3      9003   35       0         2          0            5.3                1   
4      9004   33       0         1          0           15.5                0   

   GameDifficulty  SessionsPerWeek  AvgSessionDurationMinutes  PlayerLevel  \
0               1                6                        108           79   
1               1                5                        144           11   
2               0               16                        142           35   
3               0                9                         85           57   
4               1                2                        131           95   

   AchievementsUnlocked  EngagementLevel  
0                    25                1  
1                    10                1  
2                    41                2  
3                    47                1  
4                    37                1  
In [3]:
#Here I have evaluated the accuracy of this model
from sklearn.metrics import accuracy_score

accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)
Accuracy: 0.8877232421631073
In [4]:
#Here I have evaluated the Precision, Recall and F1-Score
from sklearn.metrics import classification_report

print("Classification Report:\n")
print(classification_report(y_test, y_pred, target_names=['Low', 'Medium', 'High']))
Classification Report:

              precision    recall  f1-score   support

         Low       0.89      0.83      0.86      2065
      Medium       0.87      0.93      0.90      3875
        High       0.92      0.87      0.89      2067

    accuracy                           0.89      8007
   macro avg       0.89      0.88      0.88      8007
weighted avg       0.89      0.89      0.89      8007

In [5]:
#Here I have produced a confusion Matrix
from sklearn.metrics import confusion_matrix
import seaborn as sns

cm = confusion_matrix(y_test, y_pred)
print("Confusion Matrix:\n", cm)

#Here I have included a visual representation to make it easier to see the results
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=['Low','Medium','High'], yticklabels=['Low','Medium','High'])
plt.xlabel("Predicted")
plt.ylabel("Actual")
plt.show()
Confusion Matrix:
 [[1709  306   50]
 [ 159 3605  111]
 [  61  212 1794]]
No description has been provided for this image
In [6]:
#Here I have calculated the AUC-ROC
from sklearn.metrics import roc_auc_score
from sklearn.preprocessing import label_binarize

y_test_bin = label_binarize(y_test, classes=[0,1,2])  # 0=Low,1=Medium,2=High
y_pred_prob = model.predict_proba(X_test)              # predicted probabilities for each class

auc_roc = roc_auc_score(y_test_bin, y_pred_prob, average='macro')
print("AUC-ROC (macro-average):", auc_roc)
AUC-ROC (macro-average): 0.9376145906916525
In [7]:
#Here I have produced a list of the column titles with an evaluation of each and which is the most important in affecting the overall enagementlevel of the user
importances = df.DataFrame({
    'Feature': X.columns,
    'Importance': model.feature_importances_
}).sort_values(by='Importance', ascending=False)

print(importances)
                      Feature  Importance
8             SessionsPerWeek    0.627061
9   AvgSessionDurationMinutes    0.338717
11       AchievementsUnlocked    0.017211
10                PlayerLevel    0.014477
5               PlayTimeHours    0.000949
0                    PlayerID    0.000717
1                         Age    0.000385
3                    Location    0.000192
7              GameDifficulty    0.000139
2                      Gender    0.000078
4                   GameGenre    0.000073
6             InGamePurchases    0.000000
In [19]:
#Now I am going to start on developing the SVM Model

from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
svm_model = SVC(
    kernel='sigmoid',
    probability=True,  
    random_state=42
)

svm_model.fit(X_train_scaled, y_train)

y_pred_svm = svm_model.predict(X_test_scaled)

accuracy_svm = accuracy_score(y_test, y_pred_svm)

report = classification_report(y_test, y_pred_svm, target_names=['Low', 'Medium', 'High'])
print(report)
              precision    recall  f1-score   support

         Low       0.59      0.59      0.59      2065
      Medium       0.69      0.72      0.71      3875
        High       0.77      0.71      0.74      2067

    accuracy                           0.68      8007
   macro avg       0.68      0.67      0.68      8007
weighted avg       0.69      0.68      0.69      8007

In [20]:
print("SVM Accuracy:", accuracy_svm)
SVM Accuracy: 0.6849007118771075
In [21]:
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt

cm_svm = confusion_matrix(y_test, y_pred_svm)
print("SVM Confusion Matrix:\n", cm_svm)

# Visualize it
sns.heatmap(cm_svm, annot=True, fmt='d', cmap='Greens',
            xticklabels=['Low','Medium','High'],
            yticklabels=['Low','Medium','High'])
plt.xlabel("Predicted")
plt.ylabel("Actual")
plt.title("SVM Confusion Matrix")
plt.show()
SVM Confusion Matrix:
 [[1218  776   71]
 [ 704 2801  370]
 [ 131  471 1465]]
No description has been provided for this image
In [36]:
#Here is where I have started to apply Kmeans (clustering) machine learning to this dataset

# I have removed the target column as this is not needed for the clustering 
X_clustering = data.drop(columns=['EngagementLevel'])
print("Shape of data used for clustering:", X_clustering.shape)

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
#Scaling has been applied here so that columns are normalised and so ones with large numbers like playtime don't dominate over columns I have manually assigned numbers from 0 to 3 and so the end result is not impacted
X_scaled = scaler.fit_transform(X_clustering)

#importing the machine learning model Kmeans which uses clustering
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=4, random_state=42)
cluster_labels = kmeans.fit_predict(X_scaled)
data['Cluster'] = cluster_labels

print("Cluster counts:")
print(data['Cluster'].value_counts())

cluster_summary = data.groupby('Cluster').mean()
print("Cluster Summary (averages of features):\n", cluster_summary)
Shape of data used for clustering: (40034, 13)
Cluster counts:
Cluster
1    11789
0    10163
2     9637
3     8445
Name: count, dtype: int64
Cluster Summary (averages of features):
              PlayerID        Age    Gender  Location  GameGenre  \
Cluster                                                           
0        29056.389058  31.787563  0.633474  0.412673   1.986028   
1        29097.671813  32.156502  0.000000  1.403172   1.966240   
2        29071.286189  32.108229  1.000000  1.976964   2.021999   
3        28792.663233  31.878271  0.000000  1.897099   2.043813   

         PlayTimeHours  InGamePurchases  GameDifficulty  SessionsPerWeek  \
Cluster                                                                    
0            12.125367         0.209092        0.441799         9.526124   
1            11.993935         0.208330        0.671898         9.460344   
2            11.960133         0.193110        0.871952         9.537408   
3            12.017928         0.189343        0.854115         9.347425   

         AvgSessionDurationMinutes  PlayerLevel  AchievementsUnlocked  \
Cluster                                                                 
0                       107.316737    48.836269             24.714258   
1                        53.447197    50.108406             24.801171   
2                        93.869254    49.880357             24.342223   
3                       138.489757    49.752872             24.127294   

         EngagementLevel  
Cluster                   
0               1.103710  
1               0.707948  
2               0.999585  
3               1.284784  
In [35]:
from sklearn.metrics import silhouette_score

score = silhouette_score(X_scaled, cluster_labels)
print("Silhouette Score:", score)
Silhouette Score: 0.08898699285863793
In [ ]: