2012-10-31 57 views
0

霍爾特 - 溫特斯在這裏介紹:如何使用Holt-Winters季節性衰減方法計算PHP中的兩個月銷售預測?

http://en.wikipedia.org/wiki/Holt-Winters

它的季節性挫傷版本在這裏討論(向下滾動頁面):

http://otexts.com/fpp/7/5/

簡而言之,它基本上看起來at 3 things:

  • 長期趨勢
  • 短期走勢
  • 季節性趨勢

它也不會平均那些在一起,因爲你真正需要的是加權平均,其中,季節性和短期比長期趨勢更爲顯著,自然與財務數據趨勢。

給定$ anYear1和$ anYear2,如何應用Holt-Winters季節性抑制方法預測$ anYear2結束後的2個月?假設$ anYear1是12個數字的數組。假設$ anYear2是一個0到12數字範圍的數組。

所以,我可以用隨機數據填充它,像這樣:

<?php 

$anYear1 = array(); 
$anYear2 = array(); 
$nStop = 10; // so we need 11 and 12 of the year 
for ($i = 1; $i <= 12; $i++) { 
    $anYear1[$i] = rand(200,500); 
    if ($i <= $nStop) { 
    // give it a natural lift like real financial data 
    $anYear2[$i] = rand(400,700); 
    } 
} 
$nSeasonRange = 4; // 4 months in a business quarter 

Therefore, I want to create a function like so: 

function forecastHoltWinters($anYear1, $anYear2, $nSeasonRange = 4) { 
    /////////////////// 
    // DO MAGIC HERE // 
    /////////////////// 

    // an array with 2 numbers, indicating 2 months forward from end of $anYear2 
    return $anForecast; 
} 

$anForecast = forecastHoltWinters($anYear1, $anYear2, $nSeasonRange); 
echo "YEAR 1\n"; 
print_r($anYear1); 
echo "\n\nYEAR 2\n" 
print_r($anYear2); 
echo "\n\nTWO MONTHS FORECAST\n"; 
print_r($anForecast); 

注:我已經找到了Github的例子here,但它並沒有說明如何做一個投影。它也被討論here

+0

踢我自己,我沒有在大學裏拿微積分! – Volomike

回答

0

我找到了一種方法來改編Ian Barber's函數來做我所需要的。

<?php 

error_reporting(E_ALL); 
ini_set('display_errors','On'); 

$anYear1 = array(); 
$anYear2 = array(); 
$nStop = 10; 
for($i = 1; $i <= 12; $i++) { 
    $anYear1[$i] = rand(100,400); 
    if ($i <= $nStop) { 
     $anYear2[$i+12] = rand(200,600); 
    } 
} 

print_r($anYear1); 
print_r($anYear2); 
$anData = array_merge($anYear1,$anYear2); 
print_r(forecastHoltWinters($anData)); 

function forecastHoltWinters($anData, $nForecast = 2, $nSeasonLength = 4, $nAlpha = 0.2, $nBeta = 0.01, $nGamma = 0.01, $nDevGamma = 0.1) { 

    // Calculate an initial trend level 
    $nTrend1 = 0; 
    for($i = 0; $i < $nSeasonLength; $i++) { 
     $nTrend1 += $anData[$i]; 
    } 
    $nTrend1 /= $nSeasonLength; 

    $nTrend2 = 0; 
    for($i = $nSeasonLength; $i < 2*$nSeasonLength; $i++) { 
     $nTrend2 += $anData[$i]; 
    } 
    $nTrend2 /= $nSeasonLength; 

    $nInitialTrend = ($nTrend2 - $nTrend1)/$nSeasonLength; 

    // Take the first value as the initial level 
    $nInitialLevel = $anData[0]; 

    // Build index 
    $anIndex = array(); 
    foreach($anData as $nKey => $nVal) { 
     $anIndex[$nKey] = $nVal/($nInitialLevel + ($nKey + 1) * $nInitialTrend); 
    } 

    // Build season buffer 
    $anSeason = array_fill(0, count($anData), 0); 
    for($i = 0; $i < $nSeasonLength; $i++) { 
     $anSeason[$i] = ($anIndex[$i] + $anIndex[$i+$nSeasonLength])/2; 
    } 

    // Normalise season 
    $nSeasonFactor = $nSeasonLength/array_sum($anSeason); 
    foreach($anSeason as $nKey => $nVal) { 
     $anSeason[$nKey] *= $nSeasonFactor; 
    } 

    $anHoltWinters = array(); 
    $anDeviations = array(); 
    $nAlphaLevel = $nInitialLevel; 
    $nBetaTrend = $nInitialTrend; 
    foreach($anData as $nKey => $nVal) { 
     $nTempLevel = $nAlphaLevel; 
     $nTempTrend = $nBetaTrend; 

     $nAlphaLevel = $nAlpha * $nVal/$anSeason[$nKey] + (1.0 - $nAlpha) * ($nTempLevel + $nTempTrend); 
     $nBetaTrend = $nBeta * ($nAlphaLevel - $nTempLevel) + (1.0 - $nBeta) * $nTempTrend; 

     $anSeason[$nKey + $nSeasonLength] = $nGamma * $nVal/$nAlphaLevel + (1.0 - $nGamma) * $anSeason[$nKey]; 

     $anHoltWinters[$nKey] = ($nAlphaLevel + $nBetaTrend * ($nKey + 1)) * $anSeason[$nKey]; 
     $anDeviations[$nKey] = $nDevGamma * abs($nVal - $anHoltWinters[$nKey]) + (1-$nDevGamma) 
        * (isset($anDeviations[$nKey - $nSeasonLength]) ? $anDeviations[$nKey - $nSeasonLength] : 0); 
    } 

    $anForecast = array(); 
    $nLast = end($anData); 
    for($i = 1; $i <= $nForecast; $i++) { 
     $nComputed = round($nAlphaLevel + $nBetaTrend * $anSeason[$nKey + $i]); 
     if ($nComputed < 0) { // wildly off due to outliers 
     $nComputed = $nLast; 
     } 
     $anForecast[] = $nComputed; 
    } 

    return $anForecast; 
}