Week 3: Predicting CO2 emissions
By: Letícia Gerola
Tags: Machine Learning, Data Science, Python

Photo by Alexander Popov on Unsplash

Week 3: Predicting CO2 emissions

Built a Machine Learning model that uses linear regression to predict the amount of polution an engine car could emit

We’re on third week of Pyrentena and time just flew by! After messing around with avocado sales dataset, I decided to dig in into a much more serious theme and start some Machine Learning predictions. The dataset of this week is available on Kaggle and contains data of cars and its CO2 emission. We have some features such as vehicle class, model, size of the engine, model year, cylinders… I have to say: cars ain’t really my biggest interest, but helping the environments definitely is! Machine Learning to help prevent environmental disasters, for me, is the coolest thing ever and I dream of working with something related to this in the future. Let’s take a look at the dataset:

Graph 1: head()

This dataset contain 13 columns and 1067 rows. After doing some research, I found out that the power of the engine, named here as ENGINESIZE, is the feature that have a direct impact on the levels of CO2 emissions. After importing some libraries, I started ploting some graphs to see what this relationship looked like and which ML model would work on this situation:

# ploting graph engine size x CO2 emissions plt.figure(figsize=(13,5))

sns.lineplot(x=df['ENGINESIZE'], y=df['CO2EMISSIONS']) plt.xlabel('Motor engine')

plt.ylabel('CO2 emissions')

plt.show()

Graph 2: engine x CO2

The lineplot showed a positive relation between the size/power of the engine motor and the carbon emission. With some variation, I could say that the bigger the engine, the greater the levels of CO2 emited. I already knew this could be a nice dataset to try some linear regression model, and ploting this graph started to confirm this information.

Spliting data to train the model

I needed more libraries to start building the model! After importing them, I assigned the features I was interest in in two variables:

# importing necessary libraries from sklearn import linear_model

from sklearn.metrics import r2_score, mean_squared_error,mean_absolute_error

from sklearn.model_selection import train_test_split # features into variables engine= df[['ENGINESIZE']]

co2 = df[['CO2EMISSIONS']]

I was ready to split the data into ‘train’ and ‘test’ to train my model and see If could predict well enough. To do that, I used train_test_split and ploted the correlation between this two variables in the TRAIN dataset:

# spliting data in train and test with train_test_split engine_treino, engine_test, co2_treino, co2_test = train_test_split(engine, co2, test_size=0.2, random_state=42) # ploting the correlation between features on train dataset plt.scatter(engine_treino, co2_treino, color='blue')

plt.xlabel('engine')

plt.ylabel('co2 emission')

plt.show()

Graph 3: corr engine x CO2

Ploting the correlation on train dataset resulted on the graphic above. Despite having quite some residual, a linear regression line was able to be drawn — and that is what I did next:

Creating the model with the train dataset

The linear regression formula is Y = A + B*X. This means that the model had to figure out the values of ‘A’ and ‘B’ in order to predict the CO2 emission ‘Y’ when given an engine size ‘X’. Time to build the model and train it to find this two coeficients:

# creating a linear regression model

# LinearRegression is a method of sklearn modelo = linear_model.LinearRegression() # linear regression formula: (Y = A + B.X)

# training the model to obtain the values of A and B (always do it in the train dataset) modelo.fit(engine_treino, co2_treino) # exibiting the coeficients A and B that the model generated print(f'(A) intercept: {modelo.intercept_} | (B) inclination: {modelo.coef_}') # output (A) intercept: [126.28970217] | (B) inclination: [[38.99297872]]

There! I have my A and B coeficients according to the model trained with linear regression algorithm. Seemed a good idea to plot the linear regression line before applying the model on the TEST dataset to see It’s accuracy:

Graph 4: LR on corr (train)

Executing the model on test dataset and evalutating the results

I decide to plote the ‘correlation graphic’ between the two features on the test dataset to see how different would be from graphic 4:

# print linear regression line on our TEST dataset plt.scatter(engine_test, co2_test, color='green')

plt.plot(engine_test, modelo.coef_[0][0]*engine_test + modelo.intercept_[0], '-r')

plt.ylabel('CO2 emissions')

plt.xlabel('Engine')

plt.show()

Graph 5: LR on corr (test)

You can se that the datapoints are a bit more spread out, but the reltationship was there. Time to evaluate our model! I decided to print the following metrics (hold on tight, statiscs is coming!):

-Sum fo squared error (SSE): sum all of the residuals and square them to better acuracy.

-Mean of squared error (MSE): it gets the average of SSE.

-Sqrt of mean squared error (RMSE): is the sqrt of MSE

-r2-score: explains the variance of the variable Y when it comes to X.

# Showing metrics to check the acuracy of our model print(f'Sum of squared error (SSE): {np.sum((predictCO2 - co2_test)**2)}')

print(f'Mean squared error (MSE): {mean_squared_error(co2_test, predictCO2)}')

print (f'Sqrt of mean squared error (RMSE): {sqrt(mean_squared_error(co2_test, predictCO2))}')

print(f'R2-score: {r2_score(predictCO2, co2_test)}') # output



Sum of squared error (SSE): CO2EMISSIONS 210990.768215

dtype: float64

Mean squared error (MSE): 985.9381692274999

Sqrt of mean squared error (RMSE): 31.399652374309813

R2-score: 0.6782015355440534

r2-score is the easiest one to understand when it comes to evaluating the model, but is always good to calculate other statiscal metrics too.

All of the metrics above help evaluate the acuracy of the model! r2, for instance, is 0.68: this means that our linear regression model (values A and B given) is able to explain 68% of the variance between the CO2 emission and engine of the cars. Is nice to mention that the usual benchmark for this metric is 0.70, so It is a quite satisfactory result!