This project uses a dataset containing information about 480 students. The goal is to analyze how various factors, such as class participation, parental involvement, and absences, affect students' academic performance. We use Logistic Regression to predict the performance category of the student.
gender: Gender of the student (e.g., Male, Female)NationalITy: Nationality of the studentPlaceofBirth: Where the student was bornStageID: The stage or level of education the student is inGradeID: The grade the student is inSectionID: The section the student belongs toTopic: The subject the student is studyingSemester: The semester during which data was recordedRelation: Parent’s relationship statusraisedhands: Number of times the student raised their hand in classVisITedResources: Number of resources the student accessed for learningAnnouncementsView: Number of announcements the student viewedDiscussion: Number of discussions the student took part inParentAnsweringSurvey: Whether the student’s parent answered a survey (Yes/No)ParentschoolSatisfaction: How satisfied the parent is with the schoolStudentAbsenceDays: Number of days the student was absentClass: Performance classification (e.g., "Good", "Average", "Bad")
We can use this data to predict how students perform based on their engagement in class, parental involvement, and attendance.
Q.1 Visualize just the categorical features individually to see what options are included and how each option fares when it comes to count(how many times it appears) and see what can be deduce from that?
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
df = pd.read_csv(r"C:\Users\Asus\Desktop\ML Dataset\xAPI-Edu-Data.csv")
def EDA_info(df):
print("Shape of dataframe")
print(df.shape,'\n')
print("First 5 rows of DataFrame")
print(df.head(),'\n')
print("Last 5 rows of DataFrame")
print(df.tail(),'\n')
print("DataFrame info")
print(df.info(),'\n')
print("Display all column in DataFrame")
print(df.columns.tolist(),'\n')
print("Statistical summary of numeric column")
print(df.describe(),'\n')Q.2 To Check outlier and missing value using def function
def EDA_with_outlier(df):
print("To Check Missing Values")
print(df.isnull().sum(),'\n')
print("To Check Outlier in Data")
sns.boxplot(data = df)Q.2 Look at some categorical features in relation to each other, to see what insights could be possibly read?
def Categorical_features(df):
for col in df.columns:
if df[col].dtype == 'object':
plt.figure(figsize=(8, 6))
sns.countplot(data=df, x=col)
plt.title(f"Distribution of {col}")
plt.xticks(rotation=45)
plt.show()def categorical_relationships_heatmap(data, feature_pairs):
for feature1, feature2 in feature_pairs:
crosstab = pd.crosstab(data[feature1], data[feature2])
plt.figure(figsize=(6, 6))
sns.heatmap(crosstab, annot=True, cmap="YlGnBu", fmt='d', cbar=True)
plt.title(f"Heatmap of Relationship Between {feature1} and {feature2}", fontsize=14)
plt.xlabel(feature2, fontsize=12)
plt.ylabel(feature1, fontsize=12)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
feature_pairs = [
('gender', 'Class'),
('StageID', 'GradeID'),
('Relation', 'ParentschoolSatisfaction'),
('Semester', 'StudentAbsenceDays')
]
categorical_relationships_heatmap(df, feature_pairs)Q.3 Visualize categorical variables with numerical variables and give conclusions?
categorical_features = [
'gender', 'NationalITy', 'StageID', 'ParentAnsweringSurvey',
'ParentschoolSatisfaction', 'StudentAbsenceDays', 'Class'
]
numerical_features = ['raisedhands', 'VisITedResources', 'AnnouncementsView', 'Discussion']
def visualize_cat_var_with_num_var():
for cat in categorical_features:
for num in numerical_features:
plt.figure(figsize=(8, 4))
sns.barplot(data=df, x=cat, y=num, palette='viridis')
plt.title(f'{num} by {cat}')
plt.xticks(rotation=45)
plt.show()
visualize_cat_var_with_num_var()Q.4 From the above result, what are the factors that leads to get low grades of the students?
Q.5 Build classification model and present it's classification report?
from sklearn.preprocessing import LabelEncoder
def data_preprocess(df):
numeric_data = df.select_dtypes(include=(np.number))
category_data = df.select_dtypes(include=('object'))
category_data = category_data.apply(LabelEncoder().fit_transform)
combined_data = pd.concat([numeric_data,category_data], axis=1)
return numeric_data, category_data, combined_data
numeric_data, category_data, combined_data = data_preprocess(df)import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SequentialFeatureSelector as sfs
from sklearn.linear_model import LogisticRegression
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
from sklearn.naive_bayes import GaussianNB
def train_model_with_sampling(data, target_column, n_features=5, test_size=0.20, random_state=36, sampling_method='both'):
X = data.drop(target_column, axis=1)
Y = data[target_column]
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=test_size, random_state=random_state)
if sampling_method == 'oversample':
smote = SMOTE(random_state=random_state)
X_train, y_train = smote.fit_resample(X_train, y_train)
elif sampling_method == 'undersample':
rus = RandomUnderSampler(random_state=random_state)
X_train, y_train = rus.fit_resample(X_train, y_train)
elif sampling_method == 'both':
smote = SMOTE(random_state=random_state)
rus = RandomUnderSampler(random_state=random_state)
X_train, y_train = smote.fit_resample(X_train, y_train)
X_train, y_train = rus.fit_resample(X_train, y_train)
logreg = LogisticRegression(random_state=random_state)
selector = sfs(logreg, n_features_to_select=n_features, direction='forward', scoring='accuracy')
selector.fit(X_train, y_train)
selected_features = selector.get_support(indices=True)
selected_feature_names = X_train.columns[selected_features]
X_train_selected = X_train.iloc[:, selected_features]
X_test_selected = X_test.iloc[:, selected_features]
logreg_model = logreg.fit(X_train_selected, y_train)
nb_model = GaussianNB()
nb_model.fit(X_train_selected, y_train)
return logreg_model, nb_model, selected_feature_names, X_train_selected, X_test_selected, y_train, y_test
logreg_model, nb_model, selected_features, X_train_selected, X_test_selected, y_train, y_test = train_model_with_sampling(
combined_data, 'Class', sampling_method='both')
print("Selected Features:", selected_features)Prediction On train data
import numpy as np
from sklearn.metrics import classification_report
def train_prediction(df, Model, X_train_selected, y_train):
training_data = pd.concat([X_train_selected, y_train], axis=1)
training_data['Bad_Probability'] = Model.predict_proba(X_train_selected)[:, 1]
training_data['Predicted'] = np.where(training_data['Bad_Probability'] >= 0.7, 1, 0)
print(classification_report(training_data['Class'], training_data['Predicted']))
return training_data
training_data_prediction = train_prediction(df, logreg_model, X_train_selected, y_train)Prediction on test data
import numpy as np
from sklearn.metrics import classification_report
def test_prediction(df, Model, X_test_selected, y_test):
testing_data = pd.concat([X_test_selected, y_test], axis=1)
testing_data['Bad_Probability'] = Model.predict_proba(X_test_selected)[:, 1]
testing_data['Predicted'] = np.where(testing_data['Bad_Probability'] >= 0.7, 1, 0)
print(classification_report(testing_data['Class'], testing_data['Predicted']))
return testing_data
testing_data_prediction = test_prediction(df, logreg_model, X_test_selected, y_test)











