您是否應該刪除、插入或估算?
世界上沒有完美的數據集。每個數據科學家在數據探索過程中都會有這樣的感覺:
df.info()
看到類似這樣的內容:
大多數 ML 模型無法處理 NaN 或空值,因此如果您的特征或目標包含這些值,則在嘗試將模型擬合到數據之前對它們進行適當處理非常重要。
在本文中,我將探討處理時間序列數據集中的空值/缺失數據的 3 種簡單方法。
1. 刪除空值
這可能是處理缺失數據最簡單、最直接的方法:將其刪除。
# 刪除所有列中的所有空值
df.dropna(inplace=True)
默認情況下,pandas 的dropna
函數會全面搜索(所有列)空值,并刪除任何列中存在空值的行**。**但是,可以使用各種參數進行修改。
在本數據集中,請注意 NMHC(GT) 列只有 914 個非空值。因此,如果我們刪除所有空值,我們的模型最終最多只能得到 914 行(可能更少)。這與原來的 9,357 行相比大幅下降!
通過指定列的子集 ,pandas 將僅刪除數據框中特定列為空的行。
df.dropna(subset=['CO(GT)','PT08.S1(CO)'], inplace=True)
這樣,我們可以對方法進行混合和搭配,在某些列中刪除空值,并以不同的方式處理其他列。
您還可以通過將參數how設置為“all”來指定是否僅刪除所有列都為空的行。how 的默認值為“any”。
2. 插值空值
填充空值的另一種簡單方法是通過插值。Pandas 的 interpolate
方法默認使用線性插值。
線性插值基本上取空值前后的兩個值,并在兩者之間創建一條線。然后使用這條線來估計缺失數據點的值。Pandas**的插值方法假設每個數據點的間距相等。**如果您沒有針對每個可能的時間戳設置一行,只要您有日期時間索引,就可以將插值方法設置為“時間”。這樣,如果您有兩行相隔 >1 個間隔(例如 >1 天或 1 小時),插值將考慮這個距離。
如果這是第一個索引,由于空值前面沒有值,因此不會進行插值。
在這種情況下,插值很簡單,因為在兩個已知值的中間正好有 1 個空值。所有值都以 1 小時為間隔。索引 10 處的空值將只是前后值的平均值 (0.65)。
如果存在 2 個或更多連續的 NaN,則將根據它們與已知值之間的距離對它們進行插值。
**您可以通過limit
**關鍵字參數設置要插入的連續 NaN 數量限制。如果有大量連續 NaN,您可能希望在某個插值點之后刪除它們,因為*每次插值都會給算法帶來不確定性。*插值越多 = 不確定性越大,尤其是在時間序列的情況下。
3. 歸納空值
我要介紹的最后一種方法是歸納法。歸納法本質上意味著用數據的平均值或中位數填充空值。
最簡單的方法是使用 pandas 的 fillna
并取整列的中值。
df.fillna(df['CO(GT)'].median())
但對于時間序列,整個數據集的中值通常并不準確。時間序列數據通常具有季節性模式,使用情況會根據一天中的小時、星期幾、月份等而變化。
對于這個例子,我決定使用該小時的中位數來估算 CO(GT) 列**。**
為了能夠用中位數進行估算,我想出了自己的解決方案,因為沒有直接的方法或庫可以做到這一點(據我所知)。 我必須首先創建一個數據框,其中包含各個小時的所有中位數。
# 創建包含按小時分組的每列中位數的數據框
hour_df = pd.DataFrame(df.groupby([df.index.hour]).median())
hour_df.reset_index(inplace=True)
接下來,我創建了一個名為 get_hour_median
的函數。雖然我僅針對 CO(GT) 列展示了該函數,但我使該函數足夠靈活,以便它可以處理任何列名。
def get_hour_median(hour,col_name):median = hour_df[hour_df['Datetime']==hour][col_name].values[0]return median
然后我使用 apply 和另一個自定義函數將此函數應用于 CO(GT) 列。
# 重置日期時間索引以便在下面的函數中更輕松地處理
df.reset_index(inplace=True)# 獲取數據框行并返回中值(如果行為空),否則返回原始值。
def fill_with_hourly_median(row,col_name):if pd.isnull(row[col_name]):return get_hour_median(row['Datetime'].hour,col_name)else:return row[col_name]# 將 fill_with_hourly_median 應用于 CO(GT) 列
df['CO(GT)'] = df.apply(fill_with_hourly_median, axis=1, col_name='CO(GT)')
CO(GT) 列現在應該填寫相應小時的中值而不是 NaN。
選擇哪一個?
很多時候,您會針對不同的列使用不同方法的組合。例如,由于線性插值不會填充列中的第一個值,因此如果數據框開頭有空行,則可以在數據框中間的行被插值后刪除這些行。
如果您有大量數據,且空值不多,則刪除幾行不會產生太大影響。在這種情況下,刪除通常是我的首選方法,因為我將輸入模型的所有數據都是實際數據。
對于數據集中偶爾出現的小間隙(1-2 行缺失),我通常會使用插值法。但是,如果間隙較大,且存在大量連續的空值,我會考慮使用中位數,直到達到某個閾值(>6-10,但可能取決于數據的粒度和模式的一致性),之后我會開始刪除行。
如您所見,雖然處理缺失數據是一種常見現象,但處理方法有很多考慮因素。我提到的方法絕不是唯一的方法,但僅使用這 3 種方法就可以做很多事情。
我建議 徹底探索您的時間序列數據,方法是繪制圖表并確定零點在哪里、差距是大還是小以及存在哪些類型的季節性模式。隨著時間和實踐,您將對如何最好地處理數據中的差距有更好的直覺。
參考
- Vito,Saverio. (2016). Air Quality. UCI Machine Learning Repository. https://doi.org/10.24432/C59K5F.