Time series forecasting is one of the most in-demand data science skills — used in finance, supply chain, energy, and healthcare. This guide covers the three most practical approaches: classical ARIMA for stationary data, Facebook Prophet for business time series, and LSTM for complex non-linear patterns.
Understanding Time Series Data
A time series is a sequence of observations indexed by time. Key components include trend (long-term direction), seasonality (repeating patterns), and noise (random fluctuations). Before choosing a model you need to understand your data’s structure.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
# Load sample data
df = pd.read_csv('sales.csv', parse_dates=['date'], index_col='date')
df = df.asfreq('D').fillna(method='ffill') # daily frequency
# Decompose into trend + seasonal + residual
from statsmodels.tsa.seasonal import seasonal_decompose
result = seasonal_decompose(df['sales'], model='additive', period=30)
result.plot()
plt.tight_layout()
plt.show()
# Test for stationarity (ADF test)
adf_result = adfuller(df['sales'].dropna())
print(f'ADF Statistic: {adf_result[0]:.4f}')
print(f'p-value: {adf_result[1]:.4f}')
print('Stationary' if adf_result[1] < 0.05 else 'Non-stationary — need differencing')
ARIMA for Classical Forecasting
ARIMA (AutoRegressive Integrated Moving Average) works well for stationary time series. The three parameters p, d, q represent AR order, differencing, and MA order respectively.
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
# Plot ACF/PACF to choose p and q
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
plot_acf(df['sales'].diff().dropna(), ax=axes[0], lags=40)
plot_pacf(df['sales'].diff().dropna(), ax=axes[1], lags=40)
plt.show()
# Fit ARIMA(1,1,1)
model = ARIMA(df['sales'], order=(1, 1, 1))
result = model.fit()
print(result.summary())
# Forecast next 30 days
forecast = result.get_forecast(steps=30)
mean_fc = forecast.predicted_mean
conf_int = forecast.conf_int()
plt.figure(figsize=(12, 5))
plt.plot(df['sales'][-90:], label='Actual')
plt.plot(mean_fc, label='Forecast', color='red')
plt.fill_between(conf_int.index,
conf_int.iloc[:, 0],
conf_int.iloc[:, 1], alpha=0.2, color='red')
plt.legend()
plt.title('ARIMA Forecast')
plt.show()
# Auto-select parameters with pmdarima
from pmdarima import auto_arima
auto_model = auto_arima(df['sales'], seasonal=True, m=7,
stepwise=True, suppress_warnings=True)
print(auto_model.summary())
Facebook Prophet for Business Data
Prophet handles missing data, outliers, and multiple seasonalities automatically. It is ideal for business metrics like daily/weekly/yearly sales patterns.
from prophet import Prophet
# Prophet requires columns named 'ds' and 'y'
prophet_df = df.reset_index().rename(columns={'date': 'ds', 'sales': 'y'})
# Add holidays
from prophet.make_holidays import make_holidays_df
holidays = make_holidays_df(year_list=[2024, 2025, 2026], country='IN')
model = Prophet(
yearly_seasonality=True,
weekly_seasonality=True,
daily_seasonality=False,
holidays=holidays,
seasonality_mode='multiplicative', # use 'additive' if no growth trend
changepoint_prior_scale=0.05 # flexibility of trend — lower = smoother
)
model.fit(prophet_df)
# Create future dataframe and predict
future = model.make_future_dataframe(periods=90)
forecast = model.predict(future)
fig1 = model.plot(forecast)
fig2 = model.plot_components(forecast)
plt.show()
print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail(10))
LSTM for Deep Learning Forecasting
LSTMs capture complex, non-linear, long-range dependencies that ARIMA and Prophet miss. Use them when classical models underperform.
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
from tensorflow.keras.callbacks import EarlyStopping
# Scale data
scaler = MinMaxScaler(feature_range=(0, 1))
scaled = scaler.fit_transform(df[['sales']])
# Create sequences
def create_sequences(data, seq_len=60):
X, y = [], []
for i in range(seq_len, len(data)):
X.append(data[i-seq_len:i, 0])
y.append(data[i, 0])
return np.array(X), np.array(y)
SEQ_LEN = 60
X, y = create_sequences(scaled, SEQ_LEN)
X = X.reshape(X.shape[0], X.shape[1], 1)
# Train/test split (80/20)
split = int(len(X) * 0.8)
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]
# Build LSTM model
model = Sequential([
LSTM(64, return_sequences=True, input_shape=(SEQ_LEN, 1)),
Dropout(0.2),
LSTM(32, return_sequences=False),
Dropout(0.2),
Dense(1)
])
model.compile(optimizer='adam', loss='mse')
es = EarlyStopping(patience=10, restore_best_weights=True)
model.fit(X_train, y_train, epochs=100, batch_size=32,
validation_split=0.1, callbacks=[es], verbose=1)
# Predict and inverse transform
preds = scaler.inverse_transform(model.predict(X_test))
actual = scaler.inverse_transform(y_test.reshape(-1, 1))
from sklearn.metrics import mean_absolute_error, mean_squared_error
mae = mean_absolute_error(actual, preds)
rmse = np.sqrt(mean_squared_error(actual, preds))
print(f'MAE: {mae:.2f} | RMSE: {rmse:.2f}')
Choosing the Right Model
Use ARIMA when data is stationary and you have limited training data (under 2 years). Use Prophet when you have business time series with holidays and multiple seasonalities and need interpretable components. Use LSTM when you have large datasets (3+ years daily), multiple input features, or when classical models fail to capture the pattern. For production, always ensemble: combine Prophet and LSTM predictions with a weighted average for best accuracy.
Model Evaluation Metrics
from sklearn.metrics import mean_absolute_error, mean_squared_error
import numpy as np
def evaluate_forecast(actual, predicted, model_name):
mae = mean_absolute_error(actual, predicted)
rmse = np.sqrt(mean_squared_error(actual, predicted))
mape = np.mean(np.abs((actual - predicted) / actual)) * 100
print(f'{model_name}: MAE={mae:.2f} | RMSE={rmse:.2f} | MAPE={mape:.2f}%')
evaluate_forecast(actual, preds, 'LSTM')
Conclusion
Time series forecasting in Python has never been more accessible. Start with Prophet for quick wins on business data, add ARIMA when you need statistical rigor, and graduate to LSTM when your data is complex and plentiful. The key is always to understand your data's structure before selecting a model — decompose it, test for stationarity, and validate on a held-out test set before deploying to production.



