Create “Weather-Proof” Validations for your Time Series Forecasting Model
By: Rahulraj Singh
Tags: Data Science, Predictive Analytics, Forecasting, Time Series Analysis, Python

Create “Weather-Proof” Validations for your Time Series Forecasting Model

Photo by Marco Brito on Unsplash

TIME TRAVEL!!— It is time to take our explorations to the next level and work on predicting outcomes that are dependent on time. Time Series is a sequence of data that is present in intervals of time. These intervals can be hourly, daily, weekly, or any quantifiable repetitive duration of time. A sequence of these observations made over regular time intervals is called time series.

Forecasting time series deals with predicting the next cycle or observation of events that would occur in a future-referenced time frame.

Throughout this story, we will aim to build a Time Series Forecast that would be ideal for all problems. The idea here is to not build the best solution for one problem, but a solution that can be approached, for most problems.

Important Constructs and Tests needed for a Successful Time Series

Resampling Stationarity in Time Series ARIMA and Pyramind ARIMA Modelling Seasonality and Missing value imputation Ad-Fuller (ADF) Tests Autocorrelation and Partial Correlation Granger Causality Tests

Understanding the flow of Time Series Forecasting

Step-by-Step Flow of Time Series Forecasting and Analysis | Image by Author

Panel Data: Panel is a time-based dataset that in addition to sequential data also contains one or more linked variables that are quantified for some periods of time. These dependent variables help in providing valuable insights for predicting the value of ‘Y’.

Lags in Time Series: Lag, as a general English term refers to slower response time, often called latency. In a time-series forecast or analysis, a lag in the range of 1 to 8 is considered appropriate for quarterly timed data. For a monthly spaced time series, lags of 6, 12, or 24 are considered appropriate. To understand lags better, let us take this scenario. For a discrete set of values that belong to a time series, for lag 1, the comparison of this time series will be made with the same time series at a period before the current one. In other words, the time series is shifted to one time period in the past.

One way to understand whether a dataset is a time series or panel is to understand if the time column is the only part of the data that is affecting the outcome of the prediction.

From the next section, we start getting our hands dirty (we code!!) and for simplicity, I will only add pseudo code in this story. But, to be able to walk through the entire code I am linking the code repository below. It’s just one Python Notebook, and I recommend you follow it along with this story.

1. Resampling a Time Series

Resampling is a technique used for changing the frequency of time-series observations. Within pandas’ data frames, the resample method makes this frequency conversion convenient. Pre-conditions required are, that the object must have DateTime data type formats (DateTime, DateTimeIndex, PeriodIndex, TimeDeltaIndex, etc.). There exist two resampling types, as mentioned below. Although, in both cases, data must be invented.

Upsampling: The frequency of sample data is increased. For instance, changing a minute-based frequency to seconds. Downsampling: The vice-versa of upsampling. For example, changing a day-based frequency to months.

Resampling is needed when the frequency at which data is available is not the same frequency at which your analysis is going.

But in the most common cases, Resampling is used to provide some level of additional structure and insight into the machine learning problem for supervised learning algorithms.

# The series module from Pandas will help in creating a time series

from pandas import Series,DataFrame

import seaborn as sns # Before resampling

timeseries_mm = time_series['wind_speed']

timeseries_mm.plot(style='g--')

plt.show() # Resampling the dataset using the Mean() resample method

timeseries_mm = time_series['wind_speed'].resample("A").mean()

timeseries_mm.plot(style='g--')

plt.show()

Wind Speed Variations as recorded before and after resampling the time series | Image by Author

2. Stationary and Non-Stationary Time Series

Stationarity is considered a feature in every time series. In the case of a stationary series, the values of the time series are not a function of time.

This means measures like mean, variance, and autocorrelation of current values with past values, are all constant over time. A stationary time series is also not affected by seasonal changes.

Almost every time series can be made stationary by applying appropriate transformations.

Making a Time Series Stationary

Time Series data can be made stationary using any of the following mentioned procedures:

Differencing the series once or more: The concept of differencing states that subtracting a series value in the current time by a value of the same series in a previous unit of time will make it stationary. Meaning, subtracting the next value by the current value is called differencing.

— For example, consider the following series: [1, 5, 2, 12, 20]. First differencing gives: [5–1, 2–5, 12–2, 20–12] = [4, -3, 10, 8]. Differencing it the second time gives: [-3–4, -10–3, 8–10] = [-7, -13, -2] Taking the Log of the existing Time Series Taking the Nth root of the current series. Combining one or more of the above techniques.

Why is a Stationary Time Series important?

A stationary time series is comparatively easy to forecast and is more reliable.

The reason being, forecasting models are fundamentally linear regression algorithms that employ the lag(s) of these series data to form predictors.

We also know that linear regression algorithms work best in scenarios where the predictors (X) are not correlated with each other. Making a time series stationary removes all and any incessant autocorrelation between the predictors, hence, making the series better for regression to perform. Once the lag(s) or predictors of the series are independent, the forecasting is expected to give reliable predictions.

**Ad-Fuller Tests in the section below will test the series for Stationarity.

3. ARIMA and Pyramind ARIMA Modelling

A general term in the statistics and economics world, autoregressive integrated moving average (ARIMA) is used to describe a moving average construct. These have found great interest in building Time Series forecasting models.

ARIMA models are applied to instances where the input data shows evidence of non-stationarity in the sense of mean, but there is no significant variance observed.

We can break the definition of ARIMA as follows, the AR part of ARIMA stands for an evolving variable that is regressed on its self-lag (old values). The MA part shows the regression error that is a linear combination of error terms that have occurred at various times in the past. The remaining “I” (integrated) indicated that the data got replaced with differences between current and previous values. These individual processes may have to be performed multiple times. The purpose of each of these features is to make the model fit the data as well as possible.

From Python Documentation — Pyramid is a no-nonsense statistical Python library with a solitary objective: bring R’s auto.arima functionality to Python. Pyramid operates by wrapping statsmodels.tsa.ARIMA and statsmodels.tsa.statespace.SARIMAX into one estimator class and creating a more user-friendly estimator interface for programmers familiar with scikit-learn.

Originally called pyramid-arima, pmdarima is a statistical library that aids in filling data voids in Python’s time series. It contains a collection of statistical tests for checking stationarity and seasonality. Features such as differencing of time series and inverse differencing are also included.

# Predicting Wind Speeds using "pmdarima" package in Python from pmdarima.arima import auto_arima

from pmdarima.arima import ADFTest train=df[:1300]

test=df[-250:]

plt.figure(figsize=(15,10)) adf_test=ADFTest(alpha=0.05)

adf_test.should_diff(time_series_train["wind_speed"])

df = time_series_train["wind_speed"] model = auto_arima(train,start_p=0,d=1,start_q=0,max_p=5,max_d=5,max_q=5, start_P=0,D=1, start_Q=0, max_P=5,max_D=5,max_Q=5, m=12,seasonal=True,error_action='warn',trace=True,supress_warnings=True,stepwise=True,random_state=20,n_fits=50) plt.plot(train)

plt.plot(test)

plt.autoscale()

The portion (orange) of data predicted using pmdarima modeling for Wind Speeds | Image by Author

4. Seasonality and Missing value imputation

Seasonality in time series data is the presence of variations that occur at specific intervals of time that is less than a year. These intervals can be hourly, monthly, weekly, or quarterly. Various considerations such as weather or climatic changes can cause seasonality.

Patterns causing Seasonality are always cyclic and occur in periodic patterns.

Understanding seasonality is important for businesses whose work depends on these variations like stock markets, labor organizations, etc. Seasonal Variations have several reasons of study and significance:

The explanation of seasonal effects on a dataset provides a detailed understanding of the impact of seasonal changes on the data.

Once a seasonal pattern is established, significant methodologies can be employed to eradicate it from the time series. This will help in studying the effects of other components of the dataset that are irregular in nature. De-seasonalizing is the concept of eliminating seasonality.

Historical patterns of seasonality and regular variations help in forecasting future trends of similar data. For example, prediction of climatic patterns.

Treating missing values within Time Series

It is very common to observe missing data in any dataset. Similarly, for data representing time series, it is possible to observe the series with missing dates or times. It is always possible that data was captured and was zero. In which case, the false-negative needs to be ignored.

Also, an important point to note is, mean or median imputation is not a good practice to follow for time series data. Especially, if the time series is not exhibiting stationarity. A better and more sensible approach would be to fill the forward data with historical values of that time frame.

However, based on the study of the data and the landscape of the series, there are multiple approaches that can be tried to impute missing values. Some noteworthy and common techniques of imputing missing time series values are mentioned below:

Backward Fill

Linear Interpolation

Quadratic interpolation

Mean of nearest neighbors

Mean of seasonal counterparts

It is also important to measure the performance of the time series after the new values have been introduced to the dataset.

It is considered a good practice to use two or more ways of imputing the values and then calculating the accuracy of the model using methods like Root Mean Square (RMSE). This helps in deciding which imputation technique is best suited for the data.

5. Ad-Fuller (ADF) Tests

The Augmented Dickey-Fuller test (ADF), also known as the Ad-Fuller Test is an important testing mechanism in respect to Time Series Analysis. It tests a basic null hypothesis that a given input unit root is present in the entire time series sample. The alternative hypothesis is usually stationarity or trend stationarity of the series.

The augmented Dickey–Fuller (ADF) statistic, that is predominantly used in this test, is a negative number. The more negative it is, the stronger the rejection of the hypothesis that there is a unit root at some level of confidence.

The inspiration behind the Ad-Fuller test is that, if the time series is characterized by a unit root process, then in that case the lagged level of the series (y-1) will not yield any relevant information in predicting future changes in (y) except for those changes that were observed in the delta of (y-1). In such cases, the null hypothesis is not rejected. On the other side, if the existing process has no unit root, that states that it is stationary and therefore shows a reversion to the mean. Here, the lagged level will provide relevant information in forecasting future changes.

# Statsmodel and Adfuller will help in testing the stationarity of the time series

import statsmodels

from statsmodels.tsa.stattools import adfuller # Decomposing the time series with Statsmodels Decompose Method

from statsmodels.tsa.seasonal import seasonal_decompose

sd_1 = seasonal_decompose(time_series_train["meantemp"])

sd_2 = seasonal_decompose(time_series_train["humidity"])

sd_3 = seasonal_decompose(time_series_train["wind_speed"])

sd_4 = seasonal_decompose(time_series_train["meanpressure"])

sd_1.plot()

sd_2.plot()

sd_3.plot()

sd_4.plot()

Seasonal Decompose for all columns | Image by Author

# From the above graph’s observations, it looks like everything other than meanpressure is already stationary

# To re-confirm stationarity, we will run all columns through the ad-fuller test adfuller(time_series_train["meantemp"])

adfuller(time_series_train["humidity"])

adfuller(time_series_train["wind_speed"])

adfuller(time_series_train["meanpressure"]) # Consolidate the ad-fuller tests to test from static data

temp_var = time_series_train.columns

print('significance level : 0.05')

for var in temp_var:

ad_full = adfuller(time_series_train[var])

print(f'For {var}')

print(f'Test static {ad_full[1]}',end='



') >>> significance level : 0.05

>>> For meantemp Test static 0.2774121372301611

>>> For humidity Test static 0.004470100478130758

>>> For wind_speed Test static 0.0025407221531464

>>> For meanpressure Test static 0.0

With the ad-fuller test, we can now conclude that all data is stationary since static tests are below significance levels. This also rejects the hypothesis that mean-pressure was non-static.

6. Autocorrelation and Partial Correlation

Autocorrelation: The correlation between the series and its lags is called autocorrelation. Like correlation that measures the magnitude to which a linear relationship is associated between two variables, autocorrelation does the same between lagged values of a time series. If the series is considerably autocorrelated, it means that the impact of lags on forecasting the time series is high. In more general terms, a correlation factor of 1 (Lag = 1) conveys the correlation between values that are one period apart from each other. Likewise, lag ‘k’ autocorrelation shows the association amongst values that are ‘k’ time periods separately from each other.

Partial Autocorrelation: The purpose of partial autocorrelation is also like autocorrelation as it conveys the information about the relationship between a variable and its lag. But partial autocorrelation only delivers details about the pure association between the lag and disregards correlations that occur from intermediate lags.

# Plotting the test data with auto correlation

from statsmodels.graphics.tsaplots import plot_acf # The next 6 periods of mean temperature (graph 1) and wind_speed (graph 2)

plot_acf(df_forecast["meantemp"])

plot_acf(df_forecast["wind_speed"])

Autocorrelation of Mean Temperature and Wind Speed | Image by Author

7. Granger Causality Tests

The Granger causality test helps in understanding the behavior of a time series by analyzing a similar time series.

The test assumes that if an event X causes the occurrence of another event Y, then the future predictions of Y based on the preceding values of Y and X combined should outdo the forecasting of Y that is based on Y individually.

Therefore, something to note here is that Granger Causality should ideally not be used in conditions where a lag of the event Y is causing Y.

The statsmodel package with PyPi implements the Granger Causality test. The method accepts a 2-dimensional array with two columns as its main argument. The first column contains the values, and the predictor (X) is contained in the second column. The null hypothesis here is that the series that belongs to the second column, does not cause the occurrence of the series that is part of the first column. The null hypothesis is rejected if the P-values are lesser than the predefined significance level of 0.05. This also concludes that the lag of X is useful. The second argument “maxlag” allows you to input the maximum number of lags of Y that need to be included in the test.

# Import Granger Causality module from the statsmodels package and use the Chi-Squared test metric

from statsmodels.tsa.stattools import grangercausalitytests

test_var = time_series.columns

lag_max = 12

test_type = 'ssr_chi2test' causal_val = DataFrame(np.zeros((len(test_var),len(test_var))),columns=test_var,index=test_var)

for a in test_var:

for b in test_var:

c = grangercausalitytests ( time_series [ [b,a] ], maxlag = lag_max, verbose = False)

pred_val = [round ( c [ i +1 ] [0] [test_type] [1], 5 ) for i in range (lag_max) ]

min_value = np.min (pred_val)

causal_val.loc[b,a] = min_value

causal_val

Image by Author

The results of the Granger Causality justify that the features are closely dependent on each other.

Conclusion

Time Series is a vast topic and includes various other singularities that were not discussed in this chapter, this should be considered a start for this area of study. The analysis starts with studying time series data, understanding stationarity, testing it for seasonality, building models of prediction and finally moving on to the forecasting of time. The aim of this story was to highlight the key constructs that can make a sustainable and robust Time Series Forecasting model. Please feel free to go through the References section down below for detailed explanations of individual topics, if needed. Also as a reminder, I would advise you to follow the article side-by-side with the code repository linked above.