中心移動平均

中心移動平均主要用於時間序列分解,特別是在估計趨勢-週期成分時。它的核心特點是“對稱性”。
核心思想:將移動平均窗口置於數據的“中心”,使得平均值能夠對齊到窗口的時間中點,從而最大限度地減少滯後性。

計算方法
對於一個時間序列,其 N 期中心移動平均值是將窗口置於當前點的兩側。

  • 如果 N 是奇數(例如 N=3, 5),則直接計算對稱窗口的平均值。數據平滑處理算法03——中心移動平均_#算法其中數據平滑處理算法03——中心移動平均_#算法_02,這樣平均值就對應着窗口正中央的時刻 t
  • 如果 N 是偶數(例如 N=4),計算一次平均後,其值會落在兩個時間點之間(例如,落在 t=2.5),因此需要進行一次“居中調整”,即對相鄰的兩個移動平均值再取一次平均,使其回到整數時間點上。

優缺點
優點

  • 無滯後性(理想情況下):因為是對稱加權,所以得到的趨勢線能很好地與原始數據的趨勢中心對齊,不會像SMA或EMA那樣產生相位滯後。
  • 能更好地保留信號的原始形狀,不會扭曲峯值和谷值。

缺點

  • 在序列兩端會丟失數據。例如,一個3期中心移動平均,在序列的開始和結束處各會有1個數據點無法計算。
  • 計算比SMA複雜。

適用場景:時間序列分解、季節調整(如在美國人口調查局的X-13A-S季節性調整程序中廣泛使用)、需要無偏估計長期趨勢的場合。


示例

數據:[2, 4, 6, 8, 10], N=3(中心)
第一個平均值(對應第2個數據點):(2+4+6)/3 = 4
第二個平均值(對應第3個數據點):(4+6+8)/3 = 6
第三個平均值(對應第4個數據點):(6+8+10)/3 = 8
平滑後的數據為:[4, 6, 8],但請注意,這些值分別對應原始數據的第2、3、4個位置,首尾各損失一個點。


C語言代碼實現

// 中心移動平均
void centered_moving_average(const double input[], double output[], int data_size, int window_size) {
    if (window_size > data_size || window_size <= 0) {
        printf("Error: Invalid window size\n");
        return;
    }
    
    if (window_size % 2 == 0) { //取餘數
        printf("Error: Window size must be odd for centered moving average\n");
        return;
    }
    
    int offset = window_size / 2;
    
    // 填充開頭無法計算的部分
    for (int i = 0; i < offset; i++) {
        output[i] = 0.0;
    }
    
    // 計算中心移動平均
    for (int i = offset; i < data_size - offset; i++) {
        double sum = 0.0;
        for (int j = -offset; j <= offset; j++) {
            sum += input[i + j];
        }
        output[i] = sum / window_size;
    }
    
    // 填充結尾無法計算的部分
    for (int i = data_size - offset; i < data_size; i++) {
        output[i] = 0.0;
    }
}

算法測試:

int main(){
	//測試數據
	double data[] = {2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0};
  	int data_size = sizeof(data) / sizeof(data[0]);
  	double cma_result[10] = {0};
  
  	printf("原始數據: \n");
  	for(int i = 0; i < data_size; i++)
		printf("%.1f ",data[i]);
  	printf("\n");

  	// 測試中心移動平均 (窗口大小=3)
  	centered_moving_average(data, cma_result, data_size, 3);
  	printf("中心移動平均 (窗口大小=3):\n");
  	for(int i = 0; i < data_size; i++)
		printf("%.1f ",sma_result[i]);
  	printf("説明: 中間 %d 個值是有效結果,首尾是填充的0\n\n", data_size - 2);
}

測試結果:

數據平滑處理算法03——中心移動平均_數據_03