數據平滑處理-均值|中值|Savitzky-Golay濾波器
均值濾波器
均值濾波器是一種使用頻次較高的線性濾波器。它的實現原理很簡單,就是指定一個長度大小為奇數的窗口,使用窗口中所有數據的平均值來替換中間位置的值,然後平移該窗口,平移步長為 1,繼續重複上述操作,直至滑動到時序數據的末尾,如此一來,對時序數據的過濾操作就結束了。均值濾波器的思路簡單,計算速度快,但是它容易被窗口中的極值點或者峰值所左右,不能很好地保留序列的邊緣資訊,在去噪的同時也對數據訊號的細節特徵產生了一定的破壞,不能很好地去除雜訊點,這極大地影響了模型的預測精度。
均值濾波的公式

其中,m表示窗口大小,xi表示窗口中的第 i個數據,x表示窗口中所有數據的均值。
python程式碼實現均值濾波
# 1. 均值濾波函數
def moving_average(data, window=5):
size = window - 1
arr_value = list(data.values)
fill_left = arr_value[0]
for i in range(size):
arr_value.insert(0, fill_left)
dat = pd.Series(arr_value)
dat_roll = dat.rolling(window).mean()
return dat_roll.dropna().reset_index(drop=True)
具體應用到數據上:高頻數據未完全擬合,其他數據也與源數據擬合程度一般
中值濾波器
中值濾波是一種非線性的濾波演算法,它是將指定長度大小為奇數的窗口中的所有數據按從小到大的順序進行排列,並將排好序的數據的中值取代窗口中間的值。中值濾波克服了均值濾波所存在的問題,對窗口中的極端值不敏感,從而可以有效保留區域中的邊緣資訊,並且能有效抑制椒鹽雜訊和脈衝雜訊,避免細節特徵的丟失。但是,在面對均勻分布的高斯雜訊時,它表現很差。
中值濾波的公式見式

具體的python實現程式碼如下:
# 2. 中值濾波函數
def median_filter(data: pd.Series, window=5):
return pd.Series(scipy.signal.medfilt(data, window))
應用到數據上:中值濾波將高頻擬合,其他數據也與源數據擬合程度一般
SG濾波器
對曲線進行平滑處理,通過Savitzky-Golay 濾波器,可以在scipy庫
里直接調用,不需要再定義函數。
python程式碼實現:
from scipy.signal import savgol_filter
# 3. Savitzky-Golay濾波函數
newans = savgol_filter(data, 5, 3, mode= 'nearest')
plt.plot(index,data,label='源網路流量',color='r',linestyle='-',marker='*')
plt.plot(index,newans,label='SG濾波網路流量',color='b')#添加linestyle設置線條類型
plt.legend()
plt.show()
# 備註:
data:代表曲線點坐標(x,y)中的y值數組
window_length:窗口長度,該值需為正奇整數。例如:此處取值5
k值:polyorder為對窗口內的數據點進行k階多項式擬合,k的值需要小於window_length。例如:此處取值3
mode:確定了要應用濾波器的填充訊號的擴展類型。(This determines the type of extension to use for the padded signal to which the filter is applied. )
python原理手寫程式碼實現:
# 3. Savitzky-Golay濾波函數
"""
data - list格式的1×n緯數據
window_size - 擬合的窗口大小
rank - 擬合多項式階次
ndata - 修正後的值
"""
def savgol(data: list, window_size: int, rank: int):
m = int((window_size - 1) / 2)
odata = data[:]
# 處理邊緣數據,首尾增加m個首尾項
for i in range(m):
odata.insert(0, odata[0])
odata.insert(len(odata), odata[len(odata)-1])
# 創建X矩陣
x = create_x(m, rank)
# 計算加權係數矩陣B
b = (x * (x.T * x).I) * x.T
a0 = b[m]
a0 = a0.T
# 計算平滑修正後的值
ndata = []
for i in range(len(data)):
y = [odata[i + j] for j in range(window_size)]
y1 = np.mat(y) * a0
y1 = float(y1)
ndata.append(y1)
return ndata
"""
創建係數矩陣X
size - 2×size+1 = window_size
rank - 擬合多項式階次
x - 創建的係數矩陣
"""
def create_x(size, rank):
x = []
for i in range(2 * size + 1):
m = i - size
row = [m**j for j in range(rank)]
x.append(row)
x = np.mat(x)
return x
newans = savgol(list(data), 5, 3)
plt.plot(index,data,label='源網路流量',color='r',linestyle='-',marker='*')
plt.plot(index,newans,label='SG濾波網路流量',color='b')#添加linestyle設置線條類型
plt.legend()
plt.show()
應用到數據上效果:此圖更加接近源曲線,並且將高頻部分進行平滑處理,擬合低頻部分