时间序列预测11:用电量预测 01 数据分析与建模
【時間序列預測/分類】 全系列60篇由淺入深的博文匯總:傳送門
寫在前面
通過之前有關LSTM的8遍基礎教程和10篇處理時間序列預測任務的教程介紹,使用簡單的序列數據示例,已經把LSTM的原理,數據處理流程,模型架構,Keras實現都講清楚了。從這篇文章開始,將介紹有關時間序列預測和時間序列分類任務在真實數據集上的應用,你可以以此為模板,針對自己的業務需求進行二次開發。在本系列文章的最后會嘗試通過自動調參腳本來輔助優化模型。
代碼環境:
- python 3.7.6
- tensorflow 2.1.0
- keras 2.3.1
本文所有代碼在 jupyter notebook 中編寫。
文章目錄
- 寫在前面
- 1. 家庭用電量預測--數據分析
- 1.1 數據集介紹
- 1.2 數據加載與處理
- 1.3 數據隨時間變化規律
- 1.4 時間序列數據分布
- 2 建模建議
- 2.1 業務需求
- 2.2 數據準備
- 2.3 建模方法
- 2.3.1 樸素方法
- 2.3.2 經典線性方法
- 2.3.3 機器學習方法
- 2.3.4 深度學習方法
1. 家庭用電量預測–數據分析
其實家庭用電量預測僅僅是個“引子”,如果有電網數據的話,可以開發適合業務需求的模型,比如通過預測各時段各區域的用電量來協助電網更好地實現電能調度;除此之外,還可以用于發電量預測,比如光伏電站、風力發電站、水電站發電量預測…等等。模型一般不是問題,關鍵在數據和數據處理。
本文將介紹使用Pandas和Matplotlib對UCI上的家庭用電量數據集進行可視化,針對用電量預測問題,探究不同的網絡架構、數據準備方式以及建模方法。
Lincoln, United States, photo by American Public Power Association
Niksic, Montenegro, photo by Appolinary Kalashnikova
1.1 數據集介紹
數據集名稱為:Individual household electric power consumption Data Set(點擊跳轉數據集下載頁面),該數據集是一個多變量時間序列數據集,采集了法國巴黎一個家庭近四年(2006年12月至2010年11月)的用電量,采樣周期為1分鐘。數據集的屬性信息如下:
為了避免翻譯錯誤引起歧義,現貼出數據集屬性的英文介紹如下文所示:
以上九個屬性中,可以作為特征的有七個,去掉的兩個是日期和時間,因為序列化數據已經包含先后順序了,所以不需要時間和日期數據,因此可以使用的數據為一個由七個變量(特征)組成的多元序列。
最后三個屬性統計的電能消耗并不是家里所有的電路電能消耗。其它的電能消耗可以通過下式計算:
remainder=global_active_power×100060?(sub_metering_1+sub_metering_2+sub_metering_3)remainder = \frac {global\_active\_power \times 1000}{60}? (sub\_metering\_1 + sub\_metering\_2 + sub\_metering\_3)remainder=60global_active_power×1000??(sub_metering_1+sub_metering_2+sub_metering_3)
這里注意:有功功率單位為 KWKWKW,有功電能的單位為瓦時(watt?hourwatt-hourwatt?hour),以上數據都是間隔一分鐘測得的,因此公式的前半部分就是通過有功率乘以時間(1/60小時,也就是一分鐘)計算得到總的有功電能消耗,單位是瓦時。減去公式的后半部分(后三個屬性的加和),得到了家庭中其他電路的電能消耗。
該數據集已成為評估時間序列預測和多步預測(特別是預測有功功率)的機器學習方法的標準,接下來我們來探究該數據集。
1.2 數據加載與處理
在加載之前,先查看數據詳情信息:
查看是否有異常數據:
使用Pandas中的 read_csv() 函數加載數據,如果是excel或者csv文件通常不用考慮分隔方式,用默認的配置就可以加載;但是對于 txt 文件則需要考慮,可以看到數據集是用 ; 來分隔數據的,下面加載數據:
read_csv() 參數說明:
- seq 參數:指定列之間的分隔符為 ';',字符串格式,默認為 ‘,’;
- header 參數:指定哪一行作為列名,header=0 表示第一行數據作為列名,而不是文件的第一行作為列名;
- low_memory:在內部對文件進行分塊處理,從而在解析時減少了內存使用,但可能是混合類型推斷。默認為 True,設置為 False 確保沒有混合類型;
- infer_datetime_format:設置該參數為 True 和 parse_dates 參數,pandas會推斷列中日期時間字符串的格式,如果可以推斷出,則切換到更快方法來解析它們。在某些情況下,這可以使解析速度提高5-10倍;
- engine:要使用的解析器引擎。C引擎速度更快,而python引擎當前功能更完善;
- parse_dates:{'datetime':[0,1]} 將原數據中的第1、2列作為新的列名為 ‘datatime’ 的列,即將原來的日期列、時間列合并為日期時間一列;
- index_col:指定’datetime’列為索引列;
更多參數配置,請查看官方文檔:👉點開它帶走我
1. 查看數據的shape:
dataset.shape輸出:
(2075259, 7)2. 查看數據前10行:
dataset.head(10)輸出:
3. 查看缺失值:
輸出:
Global_active_power 0 Global_reactive_power 0 Voltage 0 Global_intensity 0 Sub_metering_1 0 Sub_metering_2 0 Sub_metering_3 25979 dtype: int644. 查看有默認標記的異常值:
dataset.iloc[dataset.values == '?'].count()輸出:
Global_active_power 155874 Global_reactive_power 155874 Voltage 155874 Global_intensity 155874 Sub_metering_1 155874 Sub_metering_2 155874 Sub_metering_3 0 dtype: int645. 有默認標記的異常值處理
為了提高數據處理效率,將所有標記為’?'的異常值用 np.nan 替換,將數據作為一個浮點值數組來處理。
再查看異常值:
dataset.iloc[dataset.values == '?'].count()輸出:
Global_active_power 0 Global_reactive_power 0 Voltage 0 Global_intensity 0 Sub_metering_1 0 Sub_metering_2 0 Sub_metering_3 0 dtype: int64再查看缺失值:
dataset.isna().sum()輸出:
Global_active_power 25979 Global_reactive_power 25979 Voltage 25979 Global_intensity 25979 Sub_metering_1 25979 Sub_metering_2 25979 Sub_metering_3 25979 dtype: int646. 添加新列
使用上一節中計算剩余用電量的計算公式,添加新列作為新的特征序列:
查看新的數據shape:
dataset.shape輸出:
(2075259, 8)查看數據前十行:
dataset.head(10)輸出:
7. 保存為新的文件:
dataset.to_csv('household_power_consumption.csv')1.3 數據隨時間變化規律
1. 首先讀取新保存的數據:
dataset = pd.read_csv('household_power_consumption.csv', header=0, infer_datetime_format=True, engine='c',parse_dates=['datetime'], index_col=['datetime'])2.繪制不同特征的子圖:
創建一個包含八個子圖的圖像,每個子圖對應一個變量。完整代碼如下:
輸出:
3. 每年的有功功率變化圖
為每一年創建一個有功功率圖,觀察是否有相同的模式。因為2006年只有不到一個月的數據,所以不繪制該年的子圖。完整代碼如下:
輸出:
因為設置了 infer_datetime_format 參數,所以可直接使用年份索引進行截取數據。通過對以上數據進行分析可知,每年2月和8月內的某段時間耗電量有明顯下降。我們似乎也看到夏季(6、7、8月)的用電量呈下降趨勢,我們還可以在第以、第三和第四個圖中有一些缺失的數據。
接下來,進一步查看每個月的用電情況。比如查看2008年每個月的有功功率,可能有助于梳理出幾個月的變化規律,如每日和每周用電狀況規律。完整代碼如下:
def plot_month_gap(dataset, year, months_list):plt.figure(figsize=(16,12), dpi=150)for i in range(len(months_list)):ax = plt.subplot(len(months_list), 1, i+1)ax.set_ylabel(r'$KW$')month = str(year) + '-' + str(months_list[i])month_data = dataset[month]plt.plot(month_data['Global_active_power'])plt.title(month, y=0, loc='left')plt.grid(linestyle='--', alpha=0.5)plt.xticks(rotation=0)plt.tight_layout()plt.show()year = 2008 months = [i for i in range(1, 13)] plot_month_gap(dataset, year, months)輸出:
接下來進一步查看每日的用電情況。完整代碼如下:
def plot_day_gap(dataset, year, month, days_list):plt.figure(figsize=(20,24), dpi=150)for i in range(len(days_list)):ax = plt.subplot(len(days_list), 1, i+1)ax.set_ylabel(r'$KW$',size=6)day = str(year) + '-0' + str(month) + '-' + str(days_list[i])day_data = dataset[day]gcp_data = day_data['Global_active_power']plt.plot(gcp_data)plt.title(day, y=0, loc='left', size=6)plt.grid(linestyle='--', alpha=0.5)plt.xticks(rotation=0)plt.show()year = 2008 month = 8 days = [i for i in range(1, 32)] plot_day_gap(dataset, year, month, days)輸出:
1.4 時間序列數據分布
另一個需要考慮的重要方面是變量的分布。例如,了解觀測值的分布是高斯分布還是其他分布??梢酝ㄟ^為每個特征創建一個直方圖來研究數據分布。完整代碼如下:
def dataset_distribution(dataset):plt.figure(figsize=(16,12), dpi=150)for i in range(len(dataset.columns)):ax = plt.subplot(len(dataset.columns), 1, i+1)ax.set_ylabel(r'$numbers$',size=10)feature_name = dataset.columns[i]dataset[feature_name].hist(bins=100)plt.title(feature_name, y=0, loc='right', size=20)plt.grid(linestyle='--', alpha=0.5)plt.xticks(rotation=0)plt.tight_layout()plt.show()dataset_distribution(dataset)輸出:
可以看到有功和無功功率、強度以及分表功率都是向瓦時或千瓦傾斜的分布,電壓數據呈高斯分布。有功功率的分布似乎是雙峰的,這意味著它看起來有兩組觀測值??梢酝ㄟ^查看四年來的數據的有功功率分布來驗證,完整代碼如下:
輸出:
可以看到,有功功率分布看起來非常相似。這種分布確實是雙峰的,一個峰值約為0.3kw,另一個峰值約為1.3kw。隨著有功功率(x軸)的增加,高功率用電時間點的數量越來越少。
所確定的群體可能在一年中的不同季節有所不同??梢酝ㄟ^查看一年中每個月的有功功率分布來對此進行調查。完整代碼如下:
def plot_month_dist(dataset, year, months_list):plt.figure(figsize=(16,12), dpi=150)for i in range(len(months_list)):ax = plt.subplot(len(months_list), 1, i+1)ax.set_ylabel(r'$KW$')ax.set_xlim(0, 5)month = str(year) + '-' + str(months_list[i])month_data = dataset[month]month_data['Global_active_power'].hist(bins=100, histtype='bar')plt.title(month, y=0, loc='right', size=10)plt.grid(linestyle='--', alpha=0.5)plt.xticks(rotation=0)plt.tight_layout()plt.show()year = 2008 months = [i for i in range(1, 13)] plot_month_dist(dataset, year, months)輸出:
可以看到,在北半球較暖的月份(法國巴黎),有功功率比較大的點少,而在較冷的月份,有功功率比較大的點多。在12月到3月的較冷月份,可以看到有更大的千瓦值(大約 3.7?4KW3.7-4KW3.7?4KW)。
2 建模建議
2.1 業務需求
對于我們使用的家庭用電量數據集來說,可以提出很多建模問題,比如:
- 預測一天內每小時的耗電量;
- 預測一周內每天的耗電量;
- 預測一月內每天的耗電量;
- 預測一年內每天的耗電量。
以上四類預測問題稱為多步預測。利用所有特征進行預測的模型稱為多變量多步預測模型。每個模型都不局限于日期的大小,還可以根據需求對更細粒度的問題進行建模,比如一天內某各時段每分鐘的耗電量預測問題。這有助于電力公司進行電能調度,是一個廣泛研究的重要問題。
2.2 數據準備
在為建模準備這些數據時有很大的靈活性。具體的數據準備方法及其效益實際上取決于問題的框架選擇和建模方法。然而,以下是可能有用的一般數據準備方法的列表:
- 每日差異可能有用,以調整數據中的每日周期。
- 年度差異可能有助于調整數據中的任何年度周期。
- 標準化可能有助于將不同單位的變量減少到相同的比例
有許多簡單的人為因素可能有助于從數據中提取工程特征,從而使特定日期更易于預測。一些例子包括:
- 表示一天中的時間,以說明人們是否有可能在家。
- 指示一天是工作日還是周末。
- 表示一天是否為北美公共假日。這些因素對預測月度數據的重要性可能會大大降低,在一定程度上對周數據的重要性可能也會降低。
- 更一般的特征可能包括:表示季節,這可能導致使用的環境控制系統的類型或數量。
2.3 建模方法
對于這個問題,可能有四類方法值得探討:
2.3.1 樸素方法
樸素的方法包括一些非常簡單但通常非常有效的假設。例如:
- 明天和今天一樣;
- 明天和去年的今天一樣;
- 明天是過去幾天的平均值;
2.3.2 經典線性方法
經典的線性方法適用于單變量時間序列預測問題。常用的方法有:
- SARIMA(季節自回歸綜合移動平均)
- ETS(三重指數平滑)
2.3.3 機器學習方法
機器學習方法要求將問題構造為有監督學習問題。這將要求將序列的滯后觀測值作為輸入特征,丟棄數據中的時間關系。常用的非線性和集成方法有:
- k近鄰算法
- SVM
- 決策樹
- 隨機森林
- GBM(Gradient Boosting Machines)
為了確保模型擬合和評估,要保留數據中的時間結構,需要做大量的特征工程,來增加特征,專業程度較高。當有多個特征時,可能變得對業務需求不適用。
2.3.4 深度學習方法
一般來說,神經網絡在自回歸型問題上并沒有被證明是非常有效的。然而,卷積神經網絡等技術能夠從原始數據(包括一維信號數據)中自動學習復雜特征。而遞歸神經網絡,例如LSTM,能夠直接在多個輸入數據的并行序列中學習。此外,這些方法的組合如CNN-LSTM和ConvLSTM等方法,在時間序列分類任務中被證明是有效的。這些方法可以處理大量數據和多個輸入變量(特征)任務。
之后文章會介紹以上提到的的建模方法。
參考:
https://matplotlib.org/index.html
https://matplotlib.org/api/_as_gen/matplotlib.pyplot.tight_layout.html#matplotlib.pyplot.tight_layout
https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplot.html?highlight=subplot#matplotlib.pyplot.subplot
http://www.imooc.com/wenda/detail/574859
https://machinelearningmastery.com/how-to-load-and-explore-household-electricity-usage-data/
總結
以上是生活随笔為你收集整理的时间序列预测11:用电量预测 01 数据分析与建模的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ps 滤镜制作花朵
- 下一篇: 技术创新是协同OA产品的生命力