This PHP 5 class forecasts future values from past data. It takes into account the growth trend, seasonality and irregularity (noise) in input data. This class uses an external class: linear regression analysis
/** compute the n-season moving average */
function computeSMA() {
$vSMA = array();
for ($i=0;$imPastDatas);$i++) {
if ($i+$this->mNumSeasons-1>=count($this->mPastDatas)) { // out of bound, done
break;
} // fi
$vSum = 0;
for ($j=0;$j<$this->mNumSeasons;$j++) {
$vSum += $this->mPastDatas[$i+$j];
} // rof
$vSMA[] = $vSum/$this->mNumSeasons;
} // rof
return $vSMA;
}
/** compute centered moving average from the n-season moving average */
function computeCMA($pSMA) {
$vCMA = array();
for ($i=0;$i
if ($i+1>=count($pSMA)) { // out of bound, done
break;
} // fi
$vCMA[] = ($pSMA[$i]+$pSMA[$i+1])/2;
} // rof
return $vCMA;
}
/** season irregularity */
function computeNoises($pCMA) {
$vNoises = array();
for ($i=0;$i
$vStarting = floor($this->mNumSeasons/2);
$vNoises[] = $this->mPastDatas[$i+$vStarting]/$pCMA[$i];
} // rof
return $vNoises;
}
/** comment */
function computeSeasonIndices($pNoises) {
$vIndices = array();
for ($i=0;$i<$this->mNumSeasons;$i++) {
$vSum = array();
for ($j=$i;$jmNumSeasons) {
$vSum[] = $pNoises[$j];
} // rof
$vStarting = (floor($this->mNumSeasons/2)+$i)%$this->mNumSeasons;
$vIndices[$vStarting] = array_sum($vSum)/count($vSum);
} // rof
ksort($vIndices);
// also adjust these season indices
$vSum = array_sum($vIndices);
for ($i=0;$i
$vIndices[$i] = $vIndices[$i]*$this->mNumSeasons/$vSum;
} // rof
return $vIndices;
}
/** comment */
function computeDeSeasonalized($pSeasonIndex) {
$vDatas = array();
for ($i=0;$imPastDatas);$i++) {
$vDatas[] = $this->mPastDatas[$i]/$pSeasonIndex[$i%$this->mNumSeasons];
} // rof
return $vDatas;
}
/** how many future periods to predict */
function predict($pNumFuturePeriods) {
$vSMA = $this->computeSMA();
if ($this->mNumSeasons%2==0) { // even
$vCMA = $this->computeCMA($vSMA);
} else { // odd, nSMA=CMA
$vCMA = $vSMA;
} // fi
$vNoises = $this->computeNoises($vCMA);
$vIndices = $this->computeSeasonIndices($vNoises);
$vDeSeasonalized = $this->computeDeSeasonalized($vIndices);
// perform regression to get the trend line
$vRegression = new CRegressionLinear($vDeSeasonalized);
list($vXVar,$vIntercept) = $vRegression->calculate();
$vForecast = array();
for ($i=0;$i<$pNumFuturePeriods;$i++) {
$vForecast[] = $vIntercept + $vXVar*(count($this->mPastDatas)+$i);
} // rof
// have to re-seasonalized these values
for ($i=0;$i
$vForecast[$i] = $vForecast[$i]*$vIndices[(count($this->mPastDatas)+$i)%$this->mNumSeasons];
} // rof
return $vForecast;
}
}
?>
Sample Usage
// Example #1: daily sales number for the past 30 days
$vSales = array(
637381,700986,641305,660285,604474,565316,598734,688690,723406,697358,
669910,605636,526655,555165,625800,579405,588317,634433,628443,570597,
662584,763516,742150,703209,669883,586504,489240,648875,692212,586509
);
$vForecast = new CMathForecasting($vSales,7); // sales pattern is weekly
$vResult = $vForecast->predict(7); // predict the next 7 days
var_dump($vResult);
// Example #2: quarterly demand number (x1000 units)
$vSales = array(
3,9,6,2,
4,11,8,3,
5,15,11,3
);
$vForecast = new CMathForecasting($vSales,4); // sales pattern is quarterly
$vResult = $vForecast->predict(4); // predict the next 4 quarters
var_dump($vResult);
?>