Is fashion predictable?
I know that with a title like that, I may receive some negative (or positive?) comments if designers or luxury brands come across my article. Anyway, I’m Etienne DAVID, research engineer at Heuritech and today, we will explore the complex subject of fashion forecasting through the lens of mathematics, machine learning and AI.
Fashion is a complex and ever-changing sector, especially in recent decades with the emergence of “Fast Fashion” and the consequent acceleration of trend cycles. To understand and predict fashion dynamics using mathematical approaches, the cornerstone will be the data: How can we translate the evolution of fashion into measurable values?
1) Translate fashion to time series
In response to this first question, Heuritech, a cutting-edge fashion technology company based in Paris, has proposed a surprising solution: analyse images on social media to illustrate the evolution of fashion. The following approach is used:
Here is an example of a Heuritech time series representing the appearance of Chunky Sneakers on social media in the United States from January 1, 2017, to January 1, 2023:
As social media data has several biases, we normalise the raw time series above to more accurately represent the fashion evolution of Chunky Sneakers. For instance, if you look at the raw time series at the beginning of 2020, you’ll notice a sudden decrease that may be due to COVID “stay-at-home” quarantines (resulting in fewer outdoor pictures on social media). This effect has been completely removed from the normalised signal shown below:
2) Fashion time series forecasting
Now that we successfully translated the evolution of fashion into time series, building mathematical predictions is straightforward. Let’s start with two simple statistical models: the seasonal naïve method and the exponential smoothing method (Holt-Winters’ additive version). See this great online book for a complete description of these models.
Get Etienne David’s stories in your inbox
Join Medium for free to get updates from this writer.
We provide below Python classes implementing the two models:
import pandas as pd
from statsmodels.tsa.api import ExponentialSmoothing
from pydantic import BaseModel
WEEKS_IN_YEAR = 52
HORIZON = 52
class EtsForecastModel(BaseModel):
"""Class defining an ETS (exponential smoothing) model.
Args:
season: define the seasonality length.
horizon: define the forecast horizon of the Ets model.
"""
season: int = WEEKS_IN_YEAR
horizon: int = HORIZON
def fit_predict_single_ts(self, ts_signal: pd.Series) -> pd.Series:
""" Fit ETS models and return its prediction.
Args:
ts_signal: A pd.Series gathering a single time series signal.
Returns:
single_forecast: A pd.Series gathering the ETS prediction.
"""
model = ExponentialSmoothing(
ts_signal, seasonal_periods=self.season, seasonal="add", trend="add"
)
fitted_model = model.fit()
single_forecast = fitted_model.forecast(self.horizon)
single_forecast.name = ts_signal.name
return single_forecast
class SnaiveForecastModel(BaseModel):
"""Class defining a seasonal naive model that repeats the values of the past year as its prediction.
Args:
horizon: define the forecast horizon of the Naive model.
"""
season: int = WEEKS_IN_YEAR
horizon: int = HORIZON
def predict(self, ts_signal: pd.Series) -> pd.Series:
""" Compute prediction of a Naive model.
Args:
ts_signal: A pd.Series gathering a single time series signal.
Returns:
single_forecast: A pd.Series gathering the seasonal Naive prediction.
"""
historical_data_past_year = ts_signal.tail(52)
nb_repeat, part_repeat = divmod(52, 52)
naive_forecast = [historical_data_past_year] * nb_repeat + [
historical_data_past_year[:part_repeat]
]
single_forecast = pd.concat(naive_forecast, axis=0, ignore_index=True)
forecast_index = pd.date_range(
start=ts_signal.index[-1], periods=52 + 1, freq=ts_signal.index.freq
)[1:]
single_forecast.index = forecast_index
return single_forecastThus, here is a simple code base that we can use to compute a one-year prediction for Chunky Sneakers in 2024.
def load_time_series_csv(filepath: str) -> pd.DataFrame:
df = pd.read_csv(filepath, index_col=0)
df.index = pd.to_datetime(df.index)
df.index.freq = df.index.inferred_freq
return df
fashion_ts = load_time_series_csv('chunky_sneakers.csv')
fashion_ts_train = fashion_ts.loc[:"2023-01-01"]
ets_model = EtsForecastModel()
ets_prediction = pd.DataFrame(ets_model.fit_predict_single_ts(fashion_ts_train["chunky_sneakers"]))
snaive_model = SnaiveForecastModel()
snaive_prediction = pd.DataFrame(snaive_model.predict(fashion_ts_train["chunky_sneakers"]))Here are the resulting predictions:
3) Forecast evaluation
When comparing the predictions with what actually happened in 2024, we can see that both models are quite accurate. The exponential smoothing model effectively captures seasonality and accurately predicts the increase in 2024, unlike the seasonal naïve model, which simply reproduces the previous year’s data. However, this increase appears to be slightly underestimated, as both models fail to fully match the growth at the end of 2023.
Several error metrics can be used to assess the performance of our two predictions and confirm what we observe in the graph above. Below, we provide the code for three of these metrics:
- Mean Absolute Scaled Error (MASE)
def mase(y_true: pd.DataFrame, y_pred: pd.DataFrame, seasonality: int) -> np.ndarray:
"""
NOTE: y_true must contain at least `seasonality` time steps before the first time index
of y_pred, plus the number of time steps in y_pred.
"""
time_split = y_pred.index[0]
index_y_pred = y_true.index.get_loc(time_split)
assert index_y_pred > seasonality + 1, (
f"To compute the MASE, you need {seasonality} time steps of history"
f" before timestamp {time_split}."
)
numerator = np.mean(
np.abs(y_true.values[index_y_pred:index_y_pred + len(y_pred)] - y_pred.values), axis=0
)
gt = y_true.values[seasonality:index_y_pred - 1]
gt_shifted = y_true.values[:index_y_pred - 1 - seasonality]
denominator = np.mean(np.abs(gt - gt_shifted), axis=0)
return numerator / denominator- Mean Absolute Percentage Error (MAPE)
def mape(y_true: pd.DataFrame, y_pred: pd.DataFrame) -> np.ndarray:
time_split = y_pred.index[0]
index_y_pred = y_true.index.get_loc(time_split)
numerator = y_true.values[index_y_pred:index_y_pred + len(y_pred)] - y_pred.values
denominator = y_true.values[index_y_pred:index_y_pred + len(y_pred)]
mape = np.abs(numerator / denominator)
mape[mape == np.inf] = np.nan
return np.nanmean(mape, axis=0)- Symmetric Mean Absolute Percentage Error (SMAPE)
def smape(y_true: pd.DataFrame, y_pred: pd.DataFrame) -> np.ndarray:
time_split = y_pred.index[0]
index_y_pred = y_true.index.get_loc(time_split)
numerator = np.abs(y_true.values[index_y_pred:index_y_pred + len(y_pred)] - y_pred.values)
denominator = 0.5 * (
np.abs(y_true.values[index_y_pred:index_y_pred + len(y_pred)]) + np.abs(y_pred.values)
)
smape = np.abs(numerator / denominator)
smape[smape == np.inf] = np.nan
return np.nanmean(smape, axis=0)Now that we have these three metrics, we can compute the accuracy of the two predictions made in the previous part. All the values are small, confirming that both predictions are accurate, with the exponential smoothing model outperforming the seasonal naïve method.
4) Is fashion predictable?
Looking back at the previous sections, it seems we’ve our answer to the question: “is fashion predictable?”. By analysing social media and using simple statistical approaches, we can make accurate predictions of the future evolution of fashion.
However, the Chunky Sneakers trend remains relatively stable, with slow changes and clear seasonality. It doesn’t fully capture the complexity of the fashion world, where simple forecasting models may no longer suffice. In upcoming articles, we will continue our journey into fashion time series forecasting, working on new fashion time series, testing more powerful forecasting algorithms and assessing their performance.
If you’d like to replicate the graphs and results presented in this article, you can access the linked code repository here.
I leave you with a final graph displaying the evolution of Retro Football Sneakers in The United States along with the prediction from the exponential smoothing model for the year 2024. We’ll cover it in a later post !









