如何用插值法補齊缺失的資料
在我做的大氣汙染報表系統中,由於原始資料缺失,經常出現一些負數或者0的大氣濃度,導致最後生成的曲線很醜,會畫到水平軸以下。將這些錯誤的資料當錯缺失資料處理,需要採取一定的手段填充。缺失的資料採取插值法填充,這一點早就確定下來,但在如何實現上卻困擾很久。
將原始問題簡化一下。比如有這樣一組資料。
ID so co1
1 0.1 0.1
2 0 0.2
3 0.2 0
4 0 0
5 0 0.4
6 0.1 0.5
插值法計算方法如下:(也可以不使用這兩個步驟,只要最後的結果一致就行)
步驟一:計算缺失值上下的已知值間的斜率:
k = (b2 - b1)/(n + 1) n 為缺失資料的個數
步驟二:計算對應的缺失值
a(i) = b1 + k * i
經過處理後,得到的資料是這樣的:
1 0.10 0.10
2 0.15 0.20
3 0.20 0.27
4 0.17 0.33
5 0.13 0.40
6 0.10 0.50
我最初的想法是:在sql語句中用for迴圈來做。逐條地檢查每個數值,如果是0,那麼獲取它的前一個記錄的值b1,然後再繼續向後遍歷,獲取後面一個非0的值b2,計算這兩個非0資料之間的距離n,之後再用插值法將缺失的資料計算出來,並update到b1和b2之間的每一個值。按照這個思路,很麻煩,比如遍歷過程中如何獲取前一個數值?出現0的時候,如何記錄出現多少個0?for迴圈經過後,再如何update之前的數值? 被這些問題困擾很久!
在論壇上發帖解決,解決的辦法很受啟發。
1. 建立一個函式
ALTER FUNCTION FUN_CO(@ID INT) RETURNS DECIMAL(18, 3) AS BEGIN DECLARE @NUM1 NUMERIC(19,2),@ID1 INT,@NUM2 NUMERIC(19,2),@ID2 INT SELECT TOP 1 @ID1=ID , @NUM1=CO FROM APRECORD WHERE ID<[email protected] AND CO<>0 ORDER BY ID DESC SELECT TOP 1 @ID2=ID , @NUM2=CO FROM APRECORD
WHERE ID>
2. 更新資料庫
UPDATE APRECORD SET CO=DBO.FUN_CO(ID) WHERE DAYTIME >= @BDT AND DAYTIME < @EDT
在這個解決方案中,首先查詢到缺失的資料,也就是值為0的資料,然後向前查詢非0資料@NUM1,以及它的編號@ID1,向後查詢非0的資料@NUM2. 以及編號@ID2。也就是步驟一。然後用公式計算出填充的資料。將上述過程儲存在一個函式中,在儲存過程中呼叫。甚至不用for迴圈之類。
---------------------------------------------------------------------------------------
啟示:
1. 明確問題,記錄下來,逐步地尋求解決方案。而不是全憑腦袋空想。腦袋很容易遺漏一些因素,而且大多數時候沒什麼條理,跳躍性太強。解決問題需要方法學。
2. 在sql下思考。用for迴圈什麼的,還處於靜態語言的思維模式之下。sql是一門藝術!思維轉換,才能發揮出語言的最大功能。當然這需要長時間的鍛鍊。