Contrairement au lissage exponentiel simple qui ne s’applique qu’aux séries temporelles sans tendance, le lissage exponentiel double (LED) permet d’établir une prévision lorsque la série présente une tendance.

Cet article a pour objectif de présenter une implémentation possible du lissage exponentiel double en Javascript. Il fait suite au post sur le lissage exponentiel simple, et portera les mêmes points :

  • Implémentation du LED en Javascript;
  • Calcul de la valeur optimale d'alpha;
  • Utilisation de la librairie HighchartJs pour générer un graphique.

Nos données

Nous utiliserons les données suivantes :

Mois CA(k€)
Janvier 112
Février 108
Mars 117
Avril 122
Mai 119
Juin 127
Juillet 132
Août 131
Septembre 139
Octobre 145
Novembre 148
Décembre 150
Janvier ?
Février ?

L'objectif du lissage exponentiel double sera de déterminer la valeur du chiffre d'affaires pour le dernier mois de Janvier et de Février. La valeur de cette prédiction dépend du paramètre alpha. Nous expliquerons donc également comment sélectionner la valeur optimale d'alpha.

Lissage exponentiel double

Comme son nom l’indique, nous allons effectuer deux lissages : le premier sur les données d’origines, le second portant sur les données issues du premier lissage.

Une fois les deux lissages effectués, nous calculons les valeurs de deux coefficients (a et b). La valeur de a correspond au coefficient directeur et est égale à (alpha/(1-alpha))*(premier_lissage - second_lissage).

B correspond à une sorte d’ordonnée à l’origine locale et est égale à 2*premier_lissage - second_lissage.

Concernant l’initialisation, plusieurs solutions sont possibles (moyenne, valeur initiale etc.). Pour plus d’informations, n’hésitez pas à consulter l’excellent site www.jybaudot.fr

function led(data, alpha, horizon)
{
	var lissage = Object();
	//on initialise la premiere valeur du lissage avec la moyenne des deux premiers
	//éléments de la série
	lissage.premier = Array();
	lissage.second = Array();

	lissage.premier[0] = data[0];
	lissage.premier[1] = data[1];

	for(var i = 2; i < data.length; ++i)
	{
		lissage.premier[i] = alpha*data[i] + (1-alpha)*lissage.premier[i-1];
	}

	lissage.second[0] = lissage.premier[0];
	for(var i = 1; i < data.length; ++i)
	{
		lissage.second[i] = alpha*lissage.premier[i] + (1-alpha)*lissage.second[i-1];
	}

	lissage.a = Array();
	lissage.b = Array();
	for(var i = 1; i < data.length; ++i)
	{
		lissage.a[i] = (alpha/(1-alpha))*(lissage.premier[i] - lissage.second[i]);
		lissage.b[i] = 2*lissage.premier[i] - lissage.second[i];
	}

	var previsions = Array();
	previsions[0] = null;
	previsions[1] = null;
	for(var i = 2; i <= data.length; ++i)
	{
		previsions[i] = lissage.a[i-1] + lissage.b[i-1];
	}

	for(var i = data.length +1; i < data.length + horizon; ++i)
	{
		previsions[i] = previsions[i-1] + lissage.a[data.length-1];
	}

	return previsions;
}

Trouver la valeur optimale d'alpha

Pour trouver la meilleure valeur du paramètre alpha, nous cherchons à minimiser l’erreur quadratique. Celle-ci est égale à 1/(n-1)*(valeur[1]-prediction[1] + valeur[2]-prediction[2] + … + valeur[n]-prediction[n]).

En Javascript cela donne :

function computeMeanSquaredError(data, forecast)
{
	var error = 0.0;
	for(var i = 1; i < data.length; ++i)
	{
		error += Math.pow(data[i] - forecast[i], 2);
	}
	return 1/(data.length-1)*error;
}

Pour trouver la meilleure valeur de alpha, on itère entre 0 et 1 avec un pas passé en paramètre à notre fonction. L’objectif est de garder la valeur d’alpha permettant de minimiser l’erreur quadratique.

function findBestAlpha(data, nbIter)
{
	var incr = 1/nbIter;
	var bestAlpha = 0.0;
	var bestError = -1;
	var alpha = bestAlpha;

	while(alpha < 1)
	{
		var forecast = les(data, alpha);
		var error = computeMeanSquaredError(data, forecast);
		if(error < bestError || bestError == -1)
		{
			bestAlpha = alpha;
			bestError = error;
		}
		alpha += incr;
	}
	return bestAlpha;
}

Une fois la valeur optimale de alpha trouvée, il suffit de générer les prédictions :

var bestAlpha = findBestAlpha(data, 20);
var forecast = led(data, bestAlpha, 2); //Prévision à t+2

Représentation graphique avec HighchartJs

Nous allons utiliser la librairie HighchartJs afin de tracer nos deux séries (celle réalisée et celle prédite). Pour cela il suffit d’inclure Jquery, ainsi que le fichier Highcharts.js. Ensuite, nous insérons le code suivant, en modifiant les différents champs en fonction de nos besoins :

<script type="text/javascript">
    $(function () {
        $('#container').highcharts({
            title: {
                text: 'Chiffre d\'affaires mensuel',
                x: -20 //center
            },
            subtitle: {
                text: 'Source: fakeSource.com',
                x: -20
            },
            xAxis: {
                categories: ['Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Juin',
                    'Juil', 'Aout', 'Sept', 'Oct', 'Nov', 'Dec', 'Jan', 'Feb']
            },
            yAxis: {
                title: {
                    text: 'CA (k€)'
                },
                plotLines: [{
                    value: 0,
                    width: 1,
                    color: '#808080'
                }]
            },
            tooltip: {
                valueSuffix: 'k€'
            },
            legend: {
                layout: 'vertical',
                align: 'right',
                verticalAlign: 'middle',
                borderWidth: 0
            },
            series: [{
                name: 'Réalisé',
                data: data
            }, {
                name: 'Prévisions',
                data: forecast
            }]
        });
    });
</script>

<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>


Nous obtenons le résultat ci-dessous :


Antoine Vastel

Head of research at Datadome.