精细化电量预测是中长期电量预测发展的一个重要趋势。针对目前我国的中长期电量预测的预测对象主要是总电量,预测结果准确度难以进一步提高,且提供的信息十分有限的问题,本文开展了基于企业用电行业的中长期电量预测研究。
思路
(1)精细化电量预测是中长期电量预测的重要指标,特别是对核心用电大户的电量预测可以对长期的电力发展规划起到十分重要的作用。本研究主要侧重于“有色金属”和“橡胶”两大用点巨头的用电预测。
(2)用电预测本质上是一种时间序列的预测,类似的时间序列例子包括:股票债券等金融产品的价格趋势预测、网络流量预测、人口和经济增长预测等。
(3)企业用电预测和股票预测类似,主要会受到大环境和企业自身发展的影响,在时间上具有周期性、波动性。
代码地址:
https://github/shikanon/mypresentations/blob/master/machinelearning/aluminum_power.ipynb
ppt下载地址:
https://github/shikanon/mypresentations/blob/master/machinelearning/%e6%99%ba%e8%83%bd%e7%94%b5%e7%bd%91%ef%bc%9a%e4%bc%81%e4%b8%9a%e7%94%b5%e5%8a%9b%e5%a4%a7%e6%95%b0%e6%8d%ae%e9%a2%84%e6%b5%8b.pdf
in [1]:
%matplotlib inlineimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsimport timefrom sklearn.metrics import mean_squared_error, mean_squared_log_error
一、数据加载及预览
in [31]:
# 加载数据consumption = pd.read_excel('data/daliy_consumption.xlsx')consumption.head()
out[31]:
客户名称时间电量(kwh)
0昆明市官渡区荣宏塑料厂2015-09-011596.98
1昆明市官渡区荣宏塑料厂2015-09-021658.23
2昆明市官渡区荣宏塑料厂2015-09-031634.56
3昆明市官渡区荣宏塑料厂2015-09-041586.91
4昆明市官渡区荣宏塑料厂2015-09-051543.75
in [48]:
consumption[consumption['电量(kwh)']==min(consumption['电量(kwh)'])]
out[48]:
客户名称时间电量(kwh)
1081云南铝业股份有限公司2016-09-15-8.0
in [49]:
consumption['电量(kwh)'] = consumption['电量(kwh)'].apply(lambda x: 0 if x
in [50]:
# 股票数据yunnan_2015 = pd.read_csv('data/sz_hq_000807_2015_2017/sz_hq_000807_2015.csv',encoding='gbk')yunnan_2015.index = yunnan_2015['交易日期']yunnan_2016 = pd.read_csv('data/sz_hq_000807_2015_2017/sz_hq_000807_2016.csv',encoding='gbk')yunnan_2016.index = yunnan_2016['交易日期']yunnan_2017 = pd.read_csv('data/sz_hq_000807_2015_2017/sz_hq_000807_2017.csv',encoding='gbk')yunnan_2017.index = yunnan_2017['交易日期']stock = pd.concat([yunnan_2015,yunnan_2016,yunnan_2017])stock.head()
out[50]:
证券代码证券简称交易日期交易所昨日收盘今日开盘成交数量最高成交最低成交最近成交总笔数涨跌幅成交金额
交易日期
2015-01-05807云铝股份2015-01-05深交所5.525.50507922705.905.485.90182576.88412.927935e+08
2015-01-06807云铝股份2015-01-06深交所5.905.89573707136.165.805.8618195-0.67803.437802e+08
2015-01-07807云铝股份2015-01-07深交所5.865.80664848856.365.766.26235526.82594.058442e+08
2015-01-08807云铝股份2015-01-08深交所6.266.20573245526.466.016.26194100.00003.570538e+08
2015-01-09807云铝股份2015-01-09深交所6.266.50737261326.896.216.2128906-0.79874.799892e+08
in [51]:
# 天气和温度数据weather = pd.read_excel('data/weather.xlsx')weather.head()
out[51]:
时间温度湿度
02015/10/01 00:0016.088%
12015/10/01 01:0016.094%
22015/10/01 02:0016.094%
32015/10/01 02:0017.095%
42015/10/01 03:0016.094%
二、构建特征
特征主要包括三类:
一类:时间特征;即节假日对产量的影响
二类:经济特征;即经济状况对产量的影响
三类:天气特征;即极端天气对产量的影响
(1)时间特征构建
获取2016、2017节假日信息
2017
一、元旦:1月1日放假,1月2日(星期一)补休,与2016年12月31日(星期六)连休,共3天,12月30日上班。(12/31~1/2)
二、春节:1月27日至2月2日放假调休,共7天。1月22日(星期日)、2月4日(星期六)上班。(1/27~2/2)
三、清明节:4月2日至4日放假调休,共3天。4月1日(星期六)上班。(4/2~4/4)
四、劳动节:5月1日放假,与周末连休,共3天。(5/1)
五、端午节:5月28日至30日放假调休,共3天。5月27日(星期六)上班。(5/28~5/30)
六、国庆节、中秋节:10月1日至8日放假调休,共8天。9月30日(星期六)上班。(10/1~10/8)
2016
一、元旦:1月1日放假,与周末连休。(1/1)
二、春节:2月7日至13日放假调休,共7天。2月6日(星期六)、2月14日(星期日)上班。(2/7~2/13)
三、清明节:4月4日放假,与周末连休。(4/4)
四、劳动节:5月1日放假,5月2日(星期一)补休。(5/1~5/2)
五、端午节:6月9日至11日放假调休,共3天。6月12日(星期日)上班。(6/9~6/11)
六、中秋节:9月15日至17日放假调休,共3天。9月18日(星期日)上班。(9/15~9/17)
七、国庆节:10月1日至7日放假调休,共7天。10月8日(星期六)、10月9日(星期日)上班。(10/1~10/7)
2015
1、元旦:1月1日至3日放假调休,共3天。1月4日(星期日)上班。(1/1~1/3)
2、春节:2月18日至24日放假调休,共7天。2月15日(星期日)、2月28日(星期六)上班。(2/18~2/24)
3、清明节:4月4日放假,月6日(星期一)补休。(4/6)
4、劳动节:5月1日放假,与周末连休。(5/1)
5、端午节:6月20日放假,6月22日(星期一)补休。(6/22)
6、胜利日:9月3日~9月5日,9月4日调休、9月6日(星期日)上班。(9/3~9/5)
7、中秋节:9月27日放假。(9/27)
8、国庆节:10月1日至7日放假调休,共7天。10月10日(星期六)上班。(10/1~10/7)
in [52]:
#时间特征consumption['month'] = consumption['时间'].apply(lambda x: x.month)consumption['dayofweek'] = consumption['时间'].apply(lambda x: x.dayofweek)#星期consumption['day'] = consumption['时间'].apply(lambda x: x.day)
in [53]:
holidays = ['2016-12-31','2017-1-1','2017-1-2','2017-1-27','2017-1-28','2017-1-29','2017-1-30','2017-1-31','2017-2-1','2017-2-2','2017-4-2','2017-4-3','2017-4-4','2017-5-1','2017-5-28','2017-5-29','2017-5-30','2017-10-1','2017-10-2','2017-10-3','2017-10-4','2017-10-5','2017-10-6','2017-10-7','2017-10-8','2016-1-1','2016-2-7','2016-2-8','2016-2-9','2016-2-10','2016-2-11','2016-2-12','2016-2-13','2016-4-4','2016-5-1','2016-5-2','2016-6-9','2016-6-10','2016-6-11','2016-9-15','2016-9-16','2016-9-17','2016-10-1','2016-10-2','2016-10-3','2016-10-4','2016-10-5','2016-10-6','2016-10-7','2015-1-1','2015-1-2','2015-1-3','2015-2-18','2015-2-19','2015-2-20','2015-2-21','2015-2-22','2015-2-23','2015-2-24','2015-4-6','2015-5-1','2015-6-22','2015-9-3','2015-9-4','2015-9-5','2015-9-27','2015-10-1','2015-10-2','2015-10-3','2015-10-4','2015-10-5','2015-10-6','2015-10-7',]no_holidays = ['2016-12-30','2017-1-22','2017-2-4','2017-4-1','2017-5-27','2017-9-30','2016-2-6','2016-2-14','2016-6-12','2016-9-18','2016-10-8','2016-10-9','2015-1-4','2015-2-15','2015-2-28','2015-9-6','2015-10-10',]spring_holidays = ['2017-1-27','2017-1-28','2017-1-29','2017-1-30','2017-1-31','2017-2-1','2017-2-2','2016-2-7','2016-2-8','2016-2-9','2016-2-10','2016-2-11','2016-2-12','2016-2-13','2015-2-18','2015-2-19','2015-2-20','2015-2-21','2015-2-22','2015-2-23','2015-2-24',]def get_holiday(time):if time.strftime('%y-%m-%d') in holidays:return 1elif time.strftime('%y-%m-%d') in no_holidays:return 0elif time.dayofweek in [0, 6]:return 1else:return 0# 标准化noramlize_time = lambda x : time.strftime('%y-%m-%d',time.strptime(x, '%y-%m-%d'))holidays = list(map(noramlize_time, holidays))no_holidays = list(map(noramlize_time, no_holidays))spring_holidays = list(map(noramlize_time, spring_holidays))#节假日consumption['holiday'] = consumption['时间'].apply(get_holiday)consumption['holiday_without_weekly'] = consumption['时间'].apply(lambda x: 1 if x.strftime('%y-%m-%d') in holidays else 0)consumption['spring_holidays'] = consumption['时间'].apply(lambda x: 1 if x.strftime('%y-%m-%d') in spring_holidays else 0)
(4)切分数据
将“昆明市官渡区荣宏塑料厂”和“云南铝业股份有限公司”数据进行分离
in [54]:
cons_plastics = consumption[consumption[u'客户名称']=='昆明市官渡区荣宏塑料厂']cons_aluminum = consumption[consumption[u'客户名称']=='云南铝业股份有限公司']cons_plastics.index = cons_plastics['时间']cons_aluminum.index = cons_aluminum['时间']
(2)经济指标
in [55]:
stock.head()
out[55]:
证券代码证券简称交易日期交易所昨日收盘今日开盘成交数量最高成交最低成交最近成交总笔数涨跌幅成交金额
交易日期
2015-01-05807云铝股份2015-01-05深交所5.525.50507922705.905.485.90182576.88412.927935e+08
2015-01-06807云铝股份2015-01-06深交所5.905.89573707136.165.805.8618195-0.67803.437802e+08
2015-01-07807云铝股份2015-01-07深交所5.865.80664848856.365.766.26235526.82594.058442e+08
2015-01-08807云铝股份2015-01-08深交所6.266.20573245526.466.016.26194100.00003.570538e+08
2015-01-09807云铝股份2015-01-09深交所6.266.50737261326.896.216.2128906-0.79874.799892e+08
in [56]:
aluminum = cons_aluminum.join(stock)aluminum.columns
out[56]:
index(['客户名称', '时间', '电量(kwh)', 'month', 'dayofweek', 'day', 'holiday','holiday_without_weekly', 'spring_holidays', '证券代码', '证券简称', '交易日期','交易所', '昨日收盘', '今日开盘', '成交数量', '最高成交', '最低成交', '最近成交', '总笔数', '涨跌幅','成交金额'],dtype='object')
in [57]:
aluminum = aluminum[['时间', '电量(kwh)', 'month', 'dayofweek', 'day', 'holiday','holiday_without_weekly', 'spring_holidays','昨日收盘', '总笔数', '涨跌幅','成交金额']]aluminum.head()
out[57]:
时间电量(kwh)monthdayofweekdayholidayholiday_without_weeklyspring_holidays昨日收盘总笔数涨跌幅成交金额
时间
2015-09-012015-09-0111925600.09110004.959167.0-5.45451.089553e+08
2015-09-022015-09-0211851580.09220004.689106.0-4.91459.055035e+07
2015-09-032015-09-0311861600.0933110nannannannan
2015-09-042015-09-0411808600.0944110nannannannan
2015-09-052015-09-0511777120.0955110nannannannan
in [58]:
# 将缺省值用最后一个有效值的方法进行插值aluminum = aluminum.fillna(method='ffill')
in [59]:
# 画图fig = plt.figure(1,figsize=[15,10])#画图stock['今日开盘'].plot()#图标签plt.ylabel('electricity consumption')plt.xlabel('day')plt.title('electricity consumption forecast')plt.legend()plt.show()
(3)天气状况
in [60]:
weather.head()
out[60]:
时间温度湿度
02015/10/01 00:0016.088%
12015/10/01 01:0016.094%
22015/10/01 02:0016.094%
32015/10/01 02:0017.095%
42015/10/01 03:0016.094%
in [61]:
weather[时间] = weather[时间].str.replace('24:00', '00:00')
in [62]:
weather[时间] = weather[时间].str.replace('24:00', '00:00')weather[时间] = pd.to_datetime(weather[时间])weather.index = weather['时间']
in [63]:
weather['湿度'] = weather['湿度'].apply(lambda x: int(x.replace('%','')))
in [64]:
weather_with_days = weather.groupby(weather.index.date).mean()weather_with_days.index = pd.to_datetime(weather_with_days.index)
in [65]:
weather_with_days['时间'] = weather_with_days.index
in [66]:
aluminum = pd.merge_ordered(aluminum, weather_with_days, fill_method='ffill', left_by='时间')
/home/tensorflow/.pyenv/versions/3.5.3/lib/python3.5/site-packages/pandas/core/reshape/merge.py:85: futurewarning: '时间' is both a column name and an index level.defaulting to column but this will raise an ambiguity error in a future versionlby = left.groupby(by, sort=false)
in [67]:
aluminum = aluminum.fillna(method='bfill')
in [68]:
# 画图fig = plt.figure(1,figsize=[15,10])#画图aluminum['湿度'].plot()#图标签plt.ylabel('electricity consumption')plt.xlabel('day')plt.title('electricity consumption forecast')plt.legend()plt.show()
in [69]:
# 画图fig = plt.figure(1,figsize=[15,10])#画图aluminum['温度'].plot()#图标签plt.ylabel('electricity consumption')plt.xlabel('day')plt.title('electricity consumption forecast')plt.legend()plt.show()
(4)铝的期货数据
in [298]:
import abupy
in [299]:
abupy.env.g_market_source = abupy.emarketsourcetype.e_market_source_sn_futures
in [303]:
data = abupy.abusymbolpd.make_kl_df('al0')aluminum_futures = data.loc['20150102':'20170104','close']
in [304]:
aluminum_futures.plot()
out[304]:
二、探索性分析
in [70]:
# 画图fig = plt.figure(1,figsize=[15,10])#画图aluminum['电量(kwh)'].plot()#图标签plt.ylabel('electricity consumption')plt.xlabel('day')plt.title('electricity consumption forecast')plt.legend()plt.show()
绘制直方分布图
可以看出用电量直方图中,用电量主要集中在1500~200之间
in [71]:
sns.distplot(aluminum['电量(kwh)'])
out[71]:
in [72]:
aluminum.plot.scatter(x='成交金额', y='电量(kwh)')
out[72]:
时间特征可视化探索
对用电量的时间特征做分析,从月份到星期到日做可视化分析:
(1)各月用电量
in [73]:
aluminum_month = aluminum.groupby('month').mean()aluminum_month['电量(kwh)'].plot(kind='bar', alpha=0.5)
out[73]:
(2)星期的用电量平均值
in [74]:
aluminum_dayofweek = aluminum.groupby('dayofweek').mean()min_aluminum_dayofweek = min(aluminum_dayofweek['电量(kwh)'])max_aluminum_dayofweek = max(aluminum_dayofweek['电量(kwh)'])aluminum_dayofweek['电量(kwh)'].plot(kind='bar', alpha=0.5, ylim=(min_aluminum_dayofweek-200000,max_aluminum_dayofweek+200000))
out[74]:
(3)个月份天数的用电量平均值
in [75]:
aluminum_day = aluminum.groupby('day').mean()min_aluminum_day = min(aluminum_day['电量(kwh)'])max_aluminum_day = max(aluminum_day['电量(kwh)'])aluminum_day['电量(kwh)'].plot(kind='bar', alpha=0.5, ylim=(min_aluminum_day-200000,max_aluminum_day+200000))
out[75]:
(3)节假日用电量平均值<...