AI ML Assignment 1
In [1]:
# importing required libraries
import pandas
import matplotlib.pyplot as plt
import seaborn
import numpy
from sklearn.svm import SVC
from sklearn.cluster import KMeans, MiniBatchKMeans
from sklearn.tree import DecisionTreeClassifier
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.pipeline import make_pipeline, Pipeline
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, ConfusionMatrixDisplay, roc_auc_score
In [2]:
# Loading and viewing a portion of the dataset
df = pandas.read_csv('online_gaming_behavior_dataset.csv')
df.info()
<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
In [3]:
# Used to know the number of values in the dataset and to perform central tendency and dispersion calculations
df.describe()
Out[3]:
| PlayerID | Age | PlayTimeHours | InGamePurchases | SessionsPerWeek | AvgSessionDurationMinutes | PlayerLevel | AchievementsUnlocked | |
|---|---|---|---|---|---|---|---|---|
| count | 40034.000000 | 40034.000000 | 40034.000000 | 40034.000000 | 40034.000000 | 40034.000000 | 40034.000000 | 40034.000000 |
| mean | 29016.500000 | 31.992531 | 12.024365 | 0.200854 | 9.471774 | 94.792252 | 49.655568 | 24.526477 |
| std | 11556.964675 | 10.043227 | 6.914638 | 0.400644 | 5.763667 | 49.011375 | 28.588379 | 14.430726 |
| min | 9000.000000 | 15.000000 | 0.000115 | 0.000000 | 0.000000 | 10.000000 | 1.000000 | 0.000000 |
| 25% | 19008.250000 | 23.000000 | 6.067501 | 0.000000 | 4.000000 | 52.000000 | 25.000000 | 12.000000 |
| 50% | 29016.500000 | 32.000000 | 12.008002 | 0.000000 | 9.000000 | 95.000000 | 49.000000 | 25.000000 |
| 75% | 39024.750000 | 41.000000 | 17.963831 | 0.000000 | 14.000000 | 137.000000 | 74.000000 | 37.000000 |
| max | 49033.000000 | 49.000000 | 23.999592 | 1.000000 | 19.000000 | 179.000000 | 99.000000 | 49.000000 |
In [4]:
df.head(10)
Out[4]:
| 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 |
| 5 | 9005 | 37 | Male | Europe | RPG | 20.561855 | 0 | Easy | 2 | 81 | 74 | 22 | Low |
| 6 | 9006 | 25 | Male | USA | Action | 9.752716 | 0 | Hard | 1 | 50 | 13 | 2 | Low |
| 7 | 9007 | 25 | Female | Asia | RPG | 4.401729 | 0 | Medium | 10 | 48 | 27 | 23 | Medium |
| 8 | 9008 | 38 | Female | Europe | Simulation | 18.152733 | 0 | Easy | 5 | 101 | 23 | 41 | Medium |
| 9 | 9009 | 38 | Female | Other | Sports | 23.942772 | 0 | Easy | 13 | 95 | 99 | 36 | High |
In [ ]:
# histograms showing distribution for age (left) and engagement level (right)
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
seaborn.histplot(df['Age'], bins=35, ax=axes[0])
seaborn.histplot(df['EngagementLevel'], ax=axes[1])
plt.show()
In [ ]:
playtime_values = df['PlayTimeHours'].values
#print(playtime_values)
# grouping values into lists based on numeric ranges 0-5, 5-10, 15-20, 20-24
zero_to_five = [number for number in playtime_values if number > 0 and number < 5]
five_to_ten = [number for number in playtime_values if number >= 5 and number < 10]
ten_to_fifteen = [number for number in playtime_values if number >= 10 and number < 15]
fifteen_to_twenty = [number for number in playtime_values if number >= 15 and number < 20]
twenty_to_twentyfour = [number for number in playtime_values if number >= 20 and number < 24]
# making a list containing the previous list to easily iterate over
joined = [
zero_to_five,
five_to_ten,
ten_to_fifteen,
fifteen_to_twenty,
twenty_to_twentyfour
]
# gets the number of values in each numeric range into a list
joined_counts = [len(i) for i in joined]
# plotting the data from joined_counts (left) and distribution of player locations
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
seaborn.barplot(joined_counts, ax=axes[0])
seaborn.histplot(df['Location'], ax=axes[1])
plt.show()
In [ ]:
# scatter graphs showing average session duration in minutes and playtime in hours (left), and age and playtime in hours (right)
fig, axes = plt.subplots(1, 2, figsize=(10,4))
seaborn.scatterplot(x=df.loc[:1000, 'PlayTimeHours'], y=df.loc[:1000, 'AvgSessionDurationMinutes'], ax=axes[0])
seaborn.scatterplot(x=df.loc[:1000, 'PlayTimeHours'], y=df.loc[:1000, 'Age'], ax=axes[1])
plt.show()
In [ ]:
numerical_columns = [
'Age',
'PlayTimeHours',
'SessionsPerWeek',
'AvgSessionDurationMinutes',
'PlayerLevel',
'AchievementsUnlocked'
]
# manually calculating the K-value for K-Means clustering
wcss = []
for i in range(1, 21):
kmeans = KMeans(n_clusters=i, init='k-means++')
kmeans.fit(df[numerical_columns])
wcss.append(kmeans.inertia_)
plt.plot(range(1,21), wcss)
plt.show()
In [ ]:
# manually calculating the K-value for Mini Batch K-Means clustering
wcsstwo = []
for i in range(1, 16):
mini = MiniBatchKMeans(n_clusters=i)
mini.fit(df[numerical_columns])
wcsstwo.append(mini.inertia_)
plt.plot(range(1,16), wcsstwo)
plt.show()
In [ ]:
fig, axes = plt.subplots(1, 4, figsize=(15,4))
# selects every row in the columns Age - AchievementsUnlocked and performs one-hot encoding on categorical columns
kmeans_features = pandas.get_dummies(df.loc[:, 'Age':'AchievementsUnlocked'])
kmeans = make_pipeline(StandardScaler(), KMeans(n_clusters=5, init='k-means++'))
mini_kmeans = make_pipeline(StandardScaler(), MiniBatchKMeans(n_clusters=5))
cluster_algos = [kmeans, mini_kmeans]
for algo in cluster_algos:
algo.fit_transform(kmeans_features)
kmeans_ypred, minik_ypred = tuple(algo.predict(kmeans_features) for algo in cluster_algos)
# results from k-means clustering
axes[0].scatter(x=df.loc[:1000, 'PlayTimeHours'], y=df.loc[:1000, 'AvgSessionDurationMinutes'], c=kmeans_ypred[:1001])
axes[1].scatter(x=df.loc[:1000, 'PlayTimeHours'], y=df.loc[:1000, 'Age'], c=kmeans_ypred[:1001])
axes[2].scatter(x=df.loc[:1000, 'Age'], y=df.loc[:1000, 'AchievementsUnlocked'], c=kmeans_ypred[:1001])
axes[3].scatter(x=df.loc[:300, 'Age'], y=df.loc[:300, 'PlayerLevel'], c=kmeans_ypred[:301])
plt.show()
In [ ]:
fig, axes = plt.subplots(1, 2, figsize=(15, 4))
# results from mini batch k-means (left) and k-means clustering (right)
seaborn.scatterplot(y=df.loc[:500, 'Age'], x=df.loc[:1000, 'PlayTimeHours'], hue=minik_ypred[:501], ax=axes[0])
seaborn.scatterplot(x=df.loc[:1000, 'PlayTimeHours'], y=df.loc[:1000, 'Age'], hue=kmeans_ypred[:1001], ax=axes[1])
plt.show()
In [3]:
# creating the ML models
linearsvc_model = SVC(kernel='linear', probability=True)
rbfsvc_model = SVC(kernel='rbf', probability=True)
polysvc_model = SVC(kernel='poly', probability=True)
sigsvc_model = SVC(kernel='sigmoid', probability=True)
dtree_classifier = DecisionTreeClassifier() # the decision tree classifier uses the gini criterion by default
dtcentro_model = DecisionTreeClassifier(criterion='entropy')
dtlog_model = DecisionTreeClassifier(criterion='log_loss')
# putting the models in a list to easily perform other actions
models = [
linearsvc_model,
rbfsvc_model,
polysvc_model,
sigsvc_model,
dtree_classifier,
dtcentro_model,
dtlog_model
]
features = df.loc[:, 'Age':'AchievementsUnlocked']
target = df['EngagementLevel']
features = pandas.get_dummies(features).to_numpy() # performs one hot encoding on the categorical columns and converts it into a numpy array
scaled_features = StandardScaler().fit_transform(features)
encoder = LabelEncoder()
target = encoder.fit_transform(target)
# splits the data into train-test split, 70% of the data is used for training while 30% is used for testing
X_train, X_test, y_train, y_test = train_test_split(scaled_features, target, test_size=0.3)
# fitting the data to all the algorithms using a for loop and the models list
for model in models:
model.fit(X_train, y_train)
In [4]:
# the predictions from each algorithms will be used later for evaluation
linear_ypred, rbf_ypred, poly_ypred, sig_ypred, dtree_ypred, dtcentro_ypred, dtlog_ypred = tuple(model.predict(X_test) for model in models)
model_names = {
'Linear Kernel': linear_ypred,
'RBF Kernel': rbf_ypred,
'Polynomial Kernel': poly_ypred,
'Sigmoid Kernel':sig_ypred,
'Decision Tree (Gini)': dtree_ypred,
}
# creates classification reports for all models by iterating over the dictionary
for name, y_preds in model_names.items():
print(f'{name} \n {classification_report(y_test, y_preds)}')
Linear Kernel
precision recall f1-score support
0 0.88 0.85 0.87 3110
1 0.79 0.70 0.75 3077
2 0.81 0.87 0.84 5824
accuracy 0.82 12011
macro avg 0.83 0.81 0.82 12011
weighted avg 0.82 0.82 0.82 12011
RBF Kernel
precision recall f1-score support
0 0.91 0.85 0.88 3110
1 0.89 0.82 0.85 3077
2 0.87 0.93 0.90 5824
accuracy 0.88 12011
macro avg 0.89 0.87 0.88 12011
weighted avg 0.89 0.88 0.88 12011
Polynomial Kernel
precision recall f1-score support
0 0.90 0.83 0.86 3110
1 0.86 0.77 0.81 3077
2 0.83 0.91 0.87 5824
accuracy 0.85 12011
macro avg 0.86 0.84 0.85 12011
weighted avg 0.85 0.85 0.85 12011
Sigmoid Kernel
precision recall f1-score support
0 0.73 0.73 0.73 3110
1 0.62 0.62 0.62 3077
2 0.69 0.70 0.70 5824
accuracy 0.68 12011
macro avg 0.68 0.68 0.68 12011
weighted avg 0.68 0.68 0.68 12011
Decision Tree (Gini)
precision recall f1-score support
0 0.80 0.81 0.80 3110
1 0.79 0.82 0.80 3077
2 0.87 0.85 0.86 5824
accuracy 0.83 12011
macro avg 0.82 0.82 0.82 12011
weighted avg 0.83 0.83 0.83 12011
In [ ]:
svc_models = [
linearsvc_model,
rbfsvc_model,
polysvc_model,
sigsvc_model
]
# displaying AUC-ROC scores of each svm kernel using a for loop
for model in svc_models:
print(print(roc_auc_score(y_test, model.predict_proba(X_test), multi_class='ovr')))
0.9159844205125074 None 0.9388362141258195 None 0.9251697492733064 None 0.8342830304633182 None
In [12]:
print(encoder.classes_)
['High' 'Low' 'Medium']
In [ ]:
# confusion matrices for each svm kernel
fig, axes = plt.subplots(1, 4, figsize=(30, 5))
ConfusionMatrixDisplay.from_estimator(
linearsvc_model,
X_test,
y_test,
display_labels=encoder.classes_,
ax=axes[0]
)
ConfusionMatrixDisplay.from_estimator(
rbfsvc_model,
X_test,
y_test,
display_labels=encoder.classes_,
ax=axes[1]
)
ConfusionMatrixDisplay.from_estimator(
polysvc_model,
X_test,
y_test,
display_labels=encoder.classes_,
ax=axes[2]
)
ConfusionMatrixDisplay.from_estimator(
sigsvc_model,
X_test,
y_test,
display_labels=encoder.classes_,
ax=axes[3]
)
plt.show()
In [ ]:
# confusion matrices of svm with the rbf kernel (left) and the decision tree with the logistic loss criterion
fig, axes = plt.subplots(1, 2, figsize=(15, 5))
ConfusionMatrixDisplay.from_estimator(
rbfsvc_model,
X_test,
y_test,
display_labels=encoder.classes_,
ax=axes[0]
)
ConfusionMatrixDisplay.from_estimator(
dtlog_model,
X_test,
y_test,
display_labels=encoder.classes_,
ax=axes[1]
)
plt.show()
In [9]:
# calculating misclassification as a percentage
print(f'''
SVM \n
medium: {(473 + 360) / (5431 + 473 + 360) * 100}
low: {(223 + 91) / (223 + 2525 + 91) * 100}
high: {(170 + 79) / (170 + 79 + 2659) * 100}
DTree \n
medium: {(362 + 352) / (5040 + 362 + 352) * 100}
low: {(405 + 220) / (405 + 2514 + 220) * 100}
high: {(379 + 201) / (379 + 201 + 2538) * 100}
''')
# print(f'''
# DTree \n
# medium: {(362 + 352) / (5040 + 362 + 352) * 100}
# low: {(405 + 220) / (405 + 2514 + 220) * 100}
# high: {(379 + 201) / (379 + 201 + 2538) * 100}
# ''')
SVM medium: 13.298212005108557 low: 11.060232476224023 high: 8.562585969738652 DTree medium: 12.408759124087592 low: 19.910799617712645 high: 18.601667735728032