High School Math Performance
By: Richard Han
Tags: Regression, Mathematics Education, Machine Learning, Education, Data Science

Photo by Sven Mieke on Unsplash

Introduction

In the world of math education, one of the major issues that universities and educators have is that students do not succeed at mathematics at a satisfactory level and at a rate that is satisfactory. Universities and educators complain of the high failure, drop, and withdrawal rates of their students. This is a problem for students because low performance in math prevents them from pursuing their degrees and careers. It is a problem for universities and educators because it means that the university or educator is not successfully teaching students, not retaining their students, and not satisfying the needs of their students — these problems hurt the profitability and attractiveness of the university and educator.

If we can gain some insights into what factors most contribute to or hurt student performance in math, we have the potential to solve the above-mentioned problems. If we can produce predictive models that can predict whether a student will pass or fail, that can predict the numerical score of students on math assessments, and that can predict the overall strength and promise of a student, then universities and educators will be able to use these models to better place students at the appropriate level of competence, to better select students for admission, and to better understand the factors that can be improved upon to help students be successful.

In this paper, we will perform data science and machine learning to a dataset representing the math performance of students from two Portuguese high schools. The dataset can be found at the link provided at the end of this article.

The data file was separated by semicolons rather than commas. I replaced the semicolons by commas. Then, copy and pasted everything into notepad. Then, convert to a csv file using the steps from the following link:

https://knowledgebase.constantcontact.com/articles/KnowledgeBase/6269-convert-a-text-file-to-an-excel-file?lang=en_US

Now, I have a nice csv file.

There are 30 attributes that include things like student age, parent’s education, parent’s job, weekly study time, number of absences, number of past class failures, etc. There are grades for years 1, 2, and 3; these are denoted by G1, G2, and G3. The grades range from 0–20. G1 and G2 can be used as input features, and G3 will be the main target output.

Some of the attributes are ordinal, some are binary yes-no, some are numeric, and some are nominal. We do need to do some data preprocessing. For the binary yes-no attributes, I will encode them using 0’s and 1’s. I did this for schoolsup, famsup, paid, activities, nursery, higher, internet, and romantic. The attributes famrel, freetime, goout, Dalc, Walc, and health are ordinal; the values for these range from 1 to 5. The attributes Medu, Fedu, traveltime, studytime, failures are also ordinal; the values range from 0 to 4 or 1 to 4. The attribute absences is a count attribute; the values range from 0 to 93. The attributes sex, school, address, Pstatus, Mjob, Fjob, guardian, famsize, reason are nominal. For nominal attributes, we can use one-hot encoding. The attributes age, G1, G2, and G3 can be thought of as interval attributes.

I one-hot encoded each nominal attribute, one at a time. I exported the dataframe as a csv file each time, relabeling the columns as I go. Finally, I reordered the columns.

Here is the python code:

import numpy as np import pandas as pd dataset = pd.read_csv(‘C:\\Users\\ricky\\Downloads\\studentmath.csv’) X = dataset.iloc[:,:-1].values Y = dataset.iloc[:,32].values from sklearn.preprocessing import LabelEncoder, OneHotEncoder labelencoder_X = LabelEncoder() # Encoding binary yes-no attributes X[:,15] = labelencoder_X.fit_transform(X[:,15]) X[:,16] = labelencoder_X.fit_transform(X[:,16]) X[:,17] = labelencoder_X.fit_transform(X[:,17]) X[:,18] = labelencoder_X.fit_transform(X[:,18]) X[:,19] = labelencoder_X.fit_transform(X[:,19]) X[:,20] = labelencoder_X.fit_transform(X[:,20]) X[:,21] = labelencoder_X.fit_transform(X[:,21]) X[:,22] = labelencoder_X.fit_transform(X[:,22]) # Encoding nominal attributes X[:,0] = labelencoder_X.fit_transform(X[:,0]) X[:,1] = labelencoder_X.fit_transform(X[:,1]) X[:,3] = labelencoder_X.fit_transform(X[:,3]) X[:,4] = labelencoder_X.fit_transform(X[:,4]) X[:,5] = labelencoder_X.fit_transform(X[:,5]) X[:,8] = labelencoder_X.fit_transform(X[:,8]) X[:,9] = labelencoder_X.fit_transform(X[:,9]) X[:,10] = labelencoder_X.fit_transform(X[:,10]) X[:,11] = labelencoder_X.fit_transform(X[:,11]) onehotencoder = OneHotEncoder(categorical_features = [0]) X = onehotencoder.fit_transform(X).toarray() from pandas import DataFrame df = DataFrame(X) export_csv = df.to_csv (r’C:\Users\Ricky\Downloads\highschoolmath.csv’, index = None, header=True)

Using seaborn, we can take a look at some visualizations. Here’s a histogram for “absences”.

Note that most students have a very low number of absences and that as the absences increases the number of students with that many absences decreases.

Let’s look at the distributions for grades G1, G2, and G3:

For G1, the first year grade, the scores look normally distributed. For G2 and G3, there are two maxima if you look at the curve; a certain number of students seem to have low scores near 0.

One might wonder how age affects the grades G1, G2, and G3. Here are some boxplots for age against G1:

The median score appears to have a local maximum at age 16, decreasing until it reaches age 19, then increasing sharply at age 20. The same thing can be seen with age versus G2:

In the third year, the local maximum at age 16 disappears, but the sharp increase at age 20 remains:

Note also that the range in scores gets tighter at ages 19 and 20.

We might also wonder whether males or females perform better. In all of three years, the median score for males is higher than for females. For instance, here’s the boxplots for Male vs G3:

If we apply linear regression to model G3 as a function of G1, we get the following:

As G1 score increases, so does G3 score. Similarly, we can see a linear relationship between G3 and G2:

Here is the python code: