We all have plotted line graphs on coordinate planes (X-axis and Y-axis) before. Where x variable is an independent variable, usually called a predictor variable and y is a dependent variable, called the criterion variable. To predict the relationship between these two variables, regression analysis is used.

For instance, you are aware of the fact that a house of 2,200 square feet costs 50,000$. You wish to buy a 3,500 square feet house. How much it will cost you? In order to find the price, you need a relationship between price and the area of the house. Linear regression solves helps you do this. Let’s find out!

Simple Linear Regression

Simple linear regression is the simplest approach for statistical learning. It is a part of Bivariate Statistics. Bivariate meaning, two variables. Now the relationship between variable 1 and variable 2 is special in case of Linear regression. Thus, the value of one variable is a function of the other variable. 

y = f(x)

The first equation which crosses our minds after reading this is the equation of the line.

The slope-intercept form of a line:

y=m*x+b

In this formula, x is an independent variable, y is a dependent variable along with two real components, m, and b. Where, m is the slope of the line and b is the y-intercept that is when the line crosses the Y-axis i.e. value of y when x=0.

Now, let’s take an example:

y=2*x+3

We can learn a lot about this equation by superimposing this equation on the slope-intercept form of the line equation.

The slope of the line = 2

Y-intercept = 2(0)+3 = 3

On plotting, it gives a straight line- 

We had a look at the algebric formula of lines and now we will examine its connection with linear regression.

Linear Regression Equation:

Consider the following dataset in Table-1, which has prices of houses based on the area of each house. 

Area (in square feet)
Price (in thousand $)
1500
340
1750
390
2600
550
3000
565
3200
610
3600
680
4000
725
2000
490

Now, with the help of the data provided in the table, we have to predict the price of the house that has an area of 3,500 square feet.

Step – 1: We will plot a scatter graph using the available data points.

Note: The order in which data points are plotted doesn’t matter. We can graph the points in any order. This just happens to be the final graph we ended up with.

Step – 2: Look for a rough visual line.

Warning: If you try and find a linear regression equation through an automated program like Excel, you will find a solution, but it does not necessarily mean the equation is a good fit for your data. 

As you can see, there are several lines passing through the data points. We don’t know that any one of these lines here is the actual regression line. So which line is it? To answer this question, let’s get to the next step.

Step – 3: In this step, descriptive statistics is done in order to find the ‘best-fit line. We will start by finding the mean of each variable.

The formula for finding the mean-

Mean = \frac{Sum of Observation}{Total number of Observations}

Mean for Area = xm = 2706.25 square feet

Mean for House prices = ym = 543.75 $

Plot this point, (xm,ym) in the graph. This point is termed the centroid.

Note: The best-fit regression line must pass through the centroid, which comprises the mean of x variable and mean of y variable.

Step – 4: To make the best-fit line we need two points. The centroid gives you one point to work with. Let’s move ahead with the calculations.

Mathematically, the regression line shares the characteristics of being linear with adjustable parameters. Remember the general equation we learned of the line, the slope formula.

y = mx+b

where m is the slope of the line and b is the y-intercept.

Finding for finding slope-

 m=\frac{\displaystyle\sum_{i=1}^{n}(x - xm) (y - ym)} {\sum_{i=1}^{n}(x - xm)^2}

Finding the value of y-intercept b, we take ym which is the mean of the dependent variable and then subtract the slope times the mean of the independent variable.

b=ym-m*(xm)

We already calculated values of xm and ym earlier in Step – 3.

Calculations: In order to form our linear equation, each data point should be considered for calculating slope. So let’s re-create our Table-1 by adding the necessary columns.

Area (sq. feet) x
Price ($) y
Area Deviation  (x - xm)
Price Deviation  (y - ym)
Deviation Product  (x - xm)(y - ym)
Area Deviation squared  (x - xm)^2
1500
340
-1206.25
-203.75
245773.4375
1455039.063
1750
390
-956.25
-153.75
147023.4375
914414.0625
2000
490
-706.25
-53.75
37960.9375
498789.0625
2600
550
-106.25
6.25
-664.0625
11289.0625
3000
565
293.75
21.25
6242.1875
86289.0625
3200
610
493.75
66.25
32710.9375
243789.0625
3600
680
893.75
136.25
121773.4375
798789.0625
4000
725
1293.75
181.25
234492.1875
1673789.063

Note: Regression is very sensitive to rounding. Thus, it is best to take your calculations to four decimal places.

From the table, we can say-

Sum of deviation product =  \displaystyle\sum_{i=1}^n(x - xm)(y - ym) = 825312.5

Sum of area deviation squared =  \displaystyle\sum_{i=1}^n(x - xm)^2 = 5682187.5

From these two above answers,

Slope = m=  \frac{\displaystyle\sum_{i=1}^{n}(x - xm) (y - ym)} {\sum_{i=1}^{n}(x - xm)^2} =  \frac{825312.5}{5682187.5} = 0.14526

We found the values xm, ym, m and thus y-intercept is

b=ym-m*(xm) =  543.75 - 0.14526 * 2706.25 = 150.64

Now, as our final step, we will assemble the values of slope and y-intercept gives us the following regression equation.

y=0.14526*x+150.64

This equation is our answer.

Remember we discussed that our centroid has to fall on the best-fit regression line. Well, it does.

This method is The Least Squares method.

Interpretation: For every 1 square foot the area increases, we would expect the price to increase by 0.14526 thousand $ that is, 145.26$.

Implementation using Kotlin

You are now aware of the concept of linear regression. Let’s start with the implementation of what we learned.

Dataset-

We will be using a self-generated dataset. This is just an arbitrary choice, you can use any other dataset of your choice. The first step is splitting the data between testing and training data sets.

The training process builds up the machine learning algorithm. This data is fed to the algorithm, the model evaluates the data repeatedly to learn about the behavior of data and then reveals patterns to serve the intended purpose. 

After the model is built, testing data validates that it can make accurate predictions. The testing data should be unlabeled. It acts as a real-world check of an unseen dataset to confirm that the algorithm is trained effectively.

We usually split the data around 20%-80% between the testing and training stages.

Code-

Starting with the training dataset representing salary in thousands per year of experience. 

				
					val xs = arrayListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) //independent variable
val ys = arrayListOf(25, 35, 49, 60, 75, 90, 115, 130, 150, 200) //dependent variable

				
			

As discussed earlier, the next step is to find the centroid. That is the mean of both variables.

				
					val meanX = xs.average() //Mean of independent variable
println(meanX) //print function
				
			

Output: 5.5

				
					val meanY = ys.average() //Mean of dependent variable
println(meanY) //print function
				
			

Output: 92.9

The coordinates of the centroid are (5.5, 92.9). Let’s move forward!

Training the model-

				
					val yearsdeviation = xs.map{it - 5.5} //Finding the deviation of years
//map function is an inbuilt function whih applies the specified condition to every element of list
println(yearsdeviation)
				
			

Output: [-4.5, -3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5]

				
					val salarydeviation = ys.map{it - 92.9} //Finding deviation in the salary
println(salarydeviation)
				
			

Output: [-67.9, -57.900000000000006, -43.900000000000006, -32.900000000000006, -17.900000000000006, -2.9000000000000057, 22.099999999999994, 37.099999999999994, 57.099999999999994, 107.1]

				
					val deviationproduct = xs.zip(ys) { x, y -> (x - meanX) * (y - meanY) } //Multiplying both the list generated
//zip function merges two different lists into a new list 
println(deviationproduct)
				
			

Output: [305.55, 202.65000000000003, 109.75000000000001, 49.35000000000001, 8.950000000000003, -1.4500000000000028, 33.14999999999999, 92.74999999999999, 199.84999999999997, 481.95]

				
					val sqofyearsdeviation = area.map {e -> e.pow(2)} //Squaring of deviation of years column
//e denotes each element in the list
println(sqofyearsdeviation)
				
			

Output: [20.25, 12.25, 6.25, 2.25, 0.25, 0.25, 2.25, 6.25, 12.25, 20.25]

				
					val num = deviationproduct.sum() //summation of all elements in the list
println(num)
				
			

Output: 1482.5

				
					val deno = sqofyearsdeviation.sum()
println(deno)
				
			

Output: 82.5

Now let’s calculate value of slope-

Slope =  \frac {num}{deno}

				
					val slope = num / deno
println(slope)

				
			

Output: 17.96969696969697

				
					val slope:Double = String.format("%.3f", 17.96969696969697).toDouble() //Rounding off the value of slope
println(slope)
				
			

Output: 17.97

After calculating slope, the centroid is used to find Y intercept –

				
					val yIntercept = meanY - slope * meanX // Finding value of Y Intercept
yIntercept

				
			

Output: -5.934999999999988

				
					//Final equation of linear regression
val simpleLinearRegression = { independentVariable: Double -> slope * independentVariable + yIntercept }
				
			

Our model is trained now. Let’s test it!

Testing the model-

For instance, how much an individual with 2.5 or 6.5 years of experience should be entitled to earn?

				
					val testcaseone = simpleLinearRegression.invoke(2.5) // Predicting the salary of an employee with experience of 2.5 years
testcaseone
				
			

Output: 38.99000000000001

				
					//Rounding off predicted value of test case 1
val testcaseone:Double = String.format("%.3f", 38.99000000000001).toDouble()
testcaseone
				
			

Output: 38.99

				
					val testcasetwo = simpleLinearRegression.invoke(6.5) // Predicting salary of an emplyee with 6.5 years experience 
testcasetwo
				
			

Output: 128.83999999999997

				
					//Rounding off predicted value of test case 2
val testcasetwo:Double = String.format("%.3f", 128.83999999999997).toDouble()
testcasetwo
				
			

Output: 128.84

Our model predicted the salary with respect to years of experience of the employee. Now the question is, how accurate is this value? What is the error percentage between the original value and the predicted value? To answer these questions let’s move to the next section. 

Building Regression Model in S2

S2/Kotlin has ample packages to solve linear model problems using regression models. We will implement the Ordinary Least Squares(OLS) model. To build and analyze a model for a given dataset, LMProblem is constructed.

Q. Consider a response vector(dependent variables) as:  Y = \begin{bmatrix}1\\2\\4\\5\\10\end{bmatrix} and design matrix of explanatory vector(independent variables) as:  X = \begin{bmatrix}25\\35\\60\\75\\200\end{bmatrix}. Construct a OLS model using S2 IDE.

				
					%use s2 //a keyword used in every program of S2

//Defining the vector Y
val Y: Vector = DenseVector(arrayOf(1.0, 2.0, 4.0, 5.0, 10.0))

//Defining the matrix X
val X: Matrix = DenseMatrix(
    arrayOf(
        doubleArrayOf(25.0),
        doubleArrayOf(35.0),
        doubleArrayOf(60.0),
        doubleArrayOf(75.0),
        doubleArrayOf(200.0)
    )
)

//estimation of true intercept 
val intercept = true
val problem1 = LMProblem(Y, X, intercept)
printOLSResults(problem1) //calling the function

//Runs an OLS regression
//Block for defining the function
fun printOLSResults(problem: LMProblem?) {
    val ols = OLSRegression(problem)
    val olsResiduals: OLSResiduals = ols.residuals()
    //coefficients for explanatory variables
    println("beta hat: ${ols.beta().betaHat()}\nstderr: ${ols.beta().stderr()},\nt: ${ols.beta().t()},\nresiduals: ${olsResiduals.residuals()}")
    //beta is the slope value
    //Standard error is stderr
    //Residual is the difference between original and model value
}
				
			

Output:

beta hat: [0.048918, 0.535481]

stderr: [0.005264, 0.532022] ,

t: [9.293036, 1.006500]

residuals: [-0.758430, -0.247609, 0.529441, 0.795672, -0.319074]

FIT of regression model

Till now we have covered and coded fundamental concepts of Simple Linear Regression. In this section, we will learn to evaluate how a regression line fits the data it models.

A regression model is unique to the data it represents. Once a regression model is built, the sum of squared errors or residuals is calculated using the regression line. Till now we have calculated the regression line using the Least Squares Method. Now, we will find the errors and residuals.

In statistics, the residual and error are not the same. Error is defined as the difference between the observed value and true value(unobserved value). Whereas, residual is defined as the difference between observed value and model value(predicted values).

Error Calculation:

Recall the example of house prices we considered. We already discussed and found the equation of linear regression on selected data and how the line passes through the centroid. Now let’s move on to the part where we calculate predicted prices for each house with the help of the equation we derived earlier.

Area (square feet)
Price (thousand $)
y=0.14526*x+150.64
y (predicted prices)
1500
340
y=0.14526*(1500)+150.64
368.53
1750
390
y=0.14526*(1750)+150.64
404.845
2600
550
y=0.14526*(2600)+150.64
528.316
3000
565
y=0.14526*(3000)+150.64
586.42
3200
610
y=0.14526*(3200)+150.64
615.472
3600
680
y=0.14526*(3600)+150.64
673.576
4000
725
y=0.14526*(4000)+150.64
731.68
2000
490
y=0.14526*(2000)+150.64
441.16

All we are doing in the above table is to substitute each area value in place of x. After evaluating these equations, it will give us the predicted price in the last column. Basically in this case the point to be noted is that our training data and testing data are the same.

Note: Instead of grabbing a calculator for the above calculations. Open S2 and code for each data point.

				
					val y=0.14526*(1500)+150.64 //Calculating for first row
println(y)
				
			

Output: 368.53

Observations: For a house of 1500 square feet, the price was 340 thousand $ and according to our regression equation we predicted 368.53 thousand $. Thus, you can observe the price of houses is not exactly the same as our predicted value. This discrepancy in values is what we refer to as an error.

So let’s find the difference in the original price and the predicted price for all the data points we have.

Area (square feet)
Price (thousand $)
y (predicted prices)
Error = Observed – Predicted
Squared Error
1500
340
368.53
-28.53
813.9609
1750
390
404.845
-14.845
220.3740
2600
550
528.316
21.684
470.1958
3000
565
586.42
-21.42
458.8164
3200
610
615.472
-5.472
29.9428
3600
680
673.576
6.424
41.2678
4000
725
731.68
-6.68
44.6224
2000
490
441.16
48.84
2385.3456

Squaring the differences, the residuals come out as mentioned in the last column of the above table. On adding them up we get the Sum of Squared Errors (SSE).

Sum of Squared Error = SSE =  \displaystyle\sum_{i=1}^n(Observed-Predicted)^2 = 4464.5257

Error in the scatter graph of Table -1 is the distance from the true line to each observed data point. Squaring all these errors (SSE) can be represented on the graph as –

Residual Analysis:

Residual analysis is important to assess the appropriateness of a linear regression model. It is the second major step towards validating a model. If the model assumptions are not satisfied, residual analysis often suggests ways for improving the model in order to obtain better results.

For understanding residuals, recall the dataset and its scatter plot we studied in Table-1. Now, construct a parallel line to X-axis using the value of Ymean that is, 543.75.

Interpretation: In the above graph, observe how the distance from the line Ymean to the observed data point can be divided into exactly two distances. One is the SSE we discussed in the previous section and the second is the SSR.

Sum of Squared Residuals(SSR) is a statistical way to study the amount of variance in a regression model. It is the sum of squared values of residuals. Graphical interpretation will be –

SSR = SST – SSE

Here we have calculated SSE and now let’s calculate the Total Sum of Squared (SST). Consider the following diagram –

Note: In this case, we considered only the dependent variable which is the price of the house. We figured out its mean and marked a horizontal line at $543.75.

Squaring the distance between the observed data point to mainline and then adding them.

Area (square feet)
Price (thousand $)
Price difference wrt ymean
Squared
1500
340
-203.75
41514.0625
1750
390
-153.75
23639.0625
2600
550
6.25
39.0625
3000
565
21.25
451.5625
3200
610
66.25
4389.0625
3600
680
-136.25
18564.0625
4000
725
181.25
32851.5625
2000
490
-53.75
2889.0625

In the last column, on adding the values we get the Total Sum of Squares (SST).

Total Sum of Squares = SST =  \displaystyle\sum_{i=1}^n(Observed(dependent) -ymean)^2 = 124337.5

Recall the relation between SSR, SSE, and SST.

SSR = SST – SSE = 124337.5 – 4464.5257 = 119872.9743

Thus, we can say that “Residual is the estimation of error”.

Coefficient of Determination: Now that we have values of SSR, SSE, and SST. Let’s go ahead and find the coefficient of determination represented as R^2. It is a statistical technique to measure the goodness of fit.

R-squared is generally interpreted as the percentage. If SSR is large, more SST is used and thus, SSE is smaller relative to the total. This ratio acts as a percentage.

Mathematically, it’s the sum of squares regression divided by the Total Sum of Squares.

R^2 = \frac{Sum of Squared Regression}{Total Sum of Squares} = \frac{SSR}{SST}

Note-1: The value is always between 0(0%) and 1(100%).

Note-2: Larger values of R^2 suggest that our linear model is a good fit for the data we provided.

In our case,

R^2 = \frac{119872.9743}{124337.5} = 0.9641 or 96.41%

Conclusion: We can conclude that 96.41% of the total sum of squares can be explained by our regression equation to predict house prices. Thus the error percentage is less than 4% which implies a GOOD FIT for our model.

While coding in S2, we include the following line to print the coefficient of determination.

				
					    println("R2: ${olsResiduals.R2()}",)

				
			

Mean Square Error: Represented as s^2 and tells us about how spread out the data points are from the regression line. s^2 is the estimate of sigma squared that is variance.

So, MSE is SSE divided by its degrees of freedom which in our case is 2 because we are estimating slope and intercept.

Note-1: In simple linear regression, the degree of freedom is always 2.

Note-2: MSE is not simply the average of residuals.

s^2 = \frac{SSE}{n-2} = \frac{4464.5257}{6} = 744.08

Standard Error: It is the standard deviation of the overall error. Represented as s. It is termed as the average distance an observation/data point falls from the regression line in units of the dependent variable.

s = \sqrt[2]{MSE} = \sqrt[2]{744.08} = 27.278

s is a measure of how well the regression model makes prediction.

When coding in S2, the following lines are typed printing –

				
					    println("standard error: ${olsResiduals.stderr()}, f: ${olsResiduals.Fstat()}",) //standard error

				
			

Testing Data Implementation

Consider the same question we coded previously in the “Building Regression Model” section. Here, we will predict values and find errors associated with the data. Consider the vector for testing as: Y = \begin{bmatrix}1.2\\2.4\\4.1\\5.3\\9.9\end{bmatrix}.

				
					%use s2

val Y: Vector = DenseVector(arrayOf(1.0, 2.0, 4.0, 5.0, 10.0))

val X: Matrix = DenseMatrix(
    arrayOf(
        doubleArrayOf(25.0),
        doubleArrayOf(35.0),
        doubleArrayOf(60.0),
        doubleArrayOf(75.0),
        doubleArrayOf(200.0)
    )
)

val intercept = true
val problem1 = LMProblem(Y, X, intercept)
printOLSResults(problem1)

// Testing data vector
val W: Vector = DenseVector(arrayOf(1.2, 2.4, 4.1, 5.3, 9.9))
val problem2 = LMProblem(Y, X, intercept, W)
printOLSResults(problem2)

fun printOLSResults(problem: LMProblem?) {
    val ols = OLSRegression(problem)
    val olsResiduals: OLSResiduals = ols.residuals()
    println("beta hat: ${ols.beta().betaHat()},\nstderr: ${ols.beta().stderr()}, \nresiduals: ${olsResiduals.residuals()}")
    println("R2: ${olsResiduals.R2()}, standard error: ${olsResiduals.stderr()}, f: ${olsResiduals.Fstat()}",)
    println("fitted values: ${olsResiduals.fitted()}")
    println("sum of squared residuals: ${olsResiduals.RSS()}")
    println("total sum of squares: ${olsResiduals.TSS()}")
    println()
}

				
			

Output:

beta hat: [0.048918, 0.535481] ,
stderr: [0.005264, 0.532022] , 
residuals: [-0.758430, -0.247609, 0.529441, 0.795672, -0.319074] 
R2: 0.9664281242711773, standard error: 0.7420099473407974, f: 86.36051188299813
fitted values: [1.758430, 2.247609, 3.470559, 4.204328, 10.319074] 
sum of squared residuals: 1.6517362858580784
total sum of squares: 49.2

beta hat: [0.045201, 1.055123] ,
stderr: [0.003621, 0.504376] , 
residuals: [-1.185147, -0.637157, 0.232818, 0.554804, -0.095319] 
R2: 0.9811093504747105, standard error: 1.23873309823374, f: 155.80872682454918
fitted values: [2.185147, 2.637157, 3.767182, 4.445196, 10.095319] 
sum of squared residuals: 4.60337906597928
total sum of squares: 243.68558951965065

Outliers

We have now covered the most important part of regression. In this section, we will understand the concept of outliers.

Sometimes when you make a scatter plot, some data points or point just don’t look right. Consider the following scatter plot for example.

Here, you will notice that in the above case the orange point looks way out of place. So, for one of the variables considered, a value can appear out of the norm. A point having such large residual values even though it is in the range of one variable is termed as an outlier.

Note: Outlier affects the slope of the regression line as it falls outside the general pattern of data.

 

We now conclude the topic, “Simple Linear Regression”.

Thank you for spending time on this course! Hope you learned a lot.