Linear Regression | Weather Prediction

We have a data set related to weather and we want to predict the apparent temperature based of some independent variables and build a simple linear regression model.

Overview

Let’s import our data set

library(tidyverse)
library(ggplot2)
library(ggcorrplot)
library(dplyr)
library(mlbench)
library(caret)

#importing data set
data <- read.csv('Weather_History.csv')

and have a look at our data

summary(data)
##  Precip.Type         Temperature      Apparent.Temperature    Humidity     
##  Length:96453       Min.   :-21.822   Min.   :-27.717      Min.   :0.0000  
##  Class :character   1st Qu.:  4.689   1st Qu.:  2.311      1st Qu.:0.6000  
##  Mode  :character   Median : 12.000   Median : 12.000      Median :0.7800  
##                     Mean   : 11.933   Mean   : 10.855      Mean   :0.7349  
##                     3rd Qu.: 18.839   3rd Qu.: 18.839      3rd Qu.:0.8900  
##                     Max.   : 39.906   Max.   : 39.344      Max.   :1.0000  
##    Wind.Speed      Wind.Bearing     Visibility      Loud.Cover    Pressure   
##  Min.   : 0.000   Min.   :  0.0   Min.   : 0.00   Min.   :0    Min.   :   0  
##  1st Qu.: 5.828   1st Qu.:116.0   1st Qu.: 8.34   1st Qu.:0    1st Qu.:1012  
##  Median : 9.966   Median :180.0   Median :10.05   Median :0    Median :1016  
##  Mean   :10.811   Mean   :187.5   Mean   :10.35   Mean   :0    Mean   :1003  
##  3rd Qu.:14.136   3rd Qu.:290.0   3rd Qu.:14.81   3rd Qu.:0    3rd Qu.:1021  
##  Max.   :63.853   Max.   :359.0   Max.   :16.10   Max.   :0    Max.   :1046
colnames(data)
## [1] "Precip.Type"          "Temperature"          "Apparent.Temperature"
## [4] "Humidity"             "Wind.Speed"           "Wind.Bearing"        
## [7] "Visibility"           "Loud.Cover"           "Pressure"
#checking for missing values
sum(is.na(data))
## [1] 0
#one of the columns has only 0 values so we'll remove it
data<-data[,-8]
# Removing zero pressure, Looks like an error #
data<-data %>% filter(!data$Pressure==0)
data$Precip.Type[data$Precip.Type=="null"]<- "none"

Correlation Matrix

Let’s measure the strength and direction of the relationship between two variables by looking at the correlation coefficient:

num_cols <- data %>% select(where(is.numeric)) %>% colnames()
options(repr.plot.width = 10.0, repr.plot.height = 10.0)
ggcorrplot(cor(data[,num_cols], method = 'pearson'), type="upper", lab=T, title = 'Correlations')

Linear model

Now we’ll look at the model (and let’s say principal assumptions are true):

model <- lm(Apparent.Temperature~Humidity+Wind.Speed+Visibility+Pressure+Wind.Bearing,data = data)  
summary(model)
## 
## Call:
## lm(formula = Apparent.Temperature ~ Humidity + Wind.Speed + Visibility + 
##     Pressure + Wind.Bearing, data = data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -57.501  -4.797   0.677   5.354  27.419 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   4.735e+02  3.313e+00  142.91   <2e-16 ***
## Humidity     -3.314e+01  1.349e-01 -245.69   <2e-16 ***
## Wind.Speed   -4.454e-01  3.694e-03 -120.58   <2e-16 ***
## Visibility    3.374e-01  6.241e-03   54.06   <2e-16 ***
## Pressure     -4.303e-01  3.226e-03 -133.38   <2e-16 ***
## Wind.Bearing  2.912e-03  2.244e-04   12.97   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 7.377 on 95159 degrees of freedom
## Multiple R-squared:  0.5235, Adjusted R-squared:  0.5234 
## F-statistic: 2.091e+04 on 5 and 95159 DF,  p-value: < 2.2e-16

We removed Temperature form the model to avoid multicollinearity.

Bulding training model

If you’re only interested in how well your model works on the data you already have, you don’t need to split your data.

But if you want your model to work well on new, unseen data, then you need to check how it performs on data it hasn’t seen before. That’s why we split the data into two parts:

Training set: Used to build the model.

Test set: Used to check how good the model really is.

Because our data is big, let’s use a sample:

weather<-sample_n(data,1000)

We want to split our data set into two parts, one (bigger) on which the model is trained, and the other (smaller) that is used for model evaluation. Before we do anything, let’s set a random seed. Train/test split is a random process, and seed ensures the randomization works the same:

set.seed(10)

80% of the data is used for training, and the remaining 20% is used for testing.

Index<-createDataPartition(weather$Apparent.Temperature,p=0.8,list=FALSE)
TrainingSet<-weather[Index,]
TestingSet<-weather[-Index,]

NewModel<-train(Apparent.Temperature~.,
                data = TrainingSet,
                method = "lm",
                na.action = na.omit, #omitting missing values
                preProcess = c("scale","center"), #scaling variables
                trControl=trainControl(method="none"))

We’re trying to predict the Apparent Temp as a linear combination of every other attribute. R also handles the categorical variables automatically, which is nice.

ModelTraining<-predict(NewModel,TrainingSet)
ModelTesting<-predict(NewModel,TestingSet)

Let’s see the how good do actual value and predicted value fit by looking at the scatter plots:

plot(TrainingSet$Apparent.Temperature,ModelTraining)

plot(TestingSet$Apparent.Temperature,ModelTesting)