0

    以风功率预测作为一个小栗子:未来三天共288个时刻

    2年前 | admin | 133次围观

    目前机器学习与气象数据的结合已经在实际生产中有了应用,比如风电场风功率预测、光伏功率预测和负荷预测。本文以风功率预测作为一个小栗子: 风功率预测是指以风电场的历史功率、历史风速、地形地貌、数值天气预报、风电机组运行状态等数据建立风电场输出功率的预测模型,以风速、功率或数值天气预报数据作为模型的输入,结合风电场机组的运行状态及运行工况,得到风电场未来的输出功率,预测时间尺度包括短期预测和超短期预测,目的是上报国家电网,利于国家电网调度。目前主流方案是结合数值天气预报和机器学习算法(LSTM、SVM等)对风功率进行时序预测,包含超短期预报(未来4个小时共16个时刻)和短期预报(未来三天共288个时刻)。 本文主要利用WRF的气象要素预报数据和LSTM算法进行风功率预测。

    下面对建模过程进行介绍。

    加载所需的Python库

    import pandas as  pd
    from datetime import datetime
    from math import sqrt
    from numpy import concatenate
    from matplotlib import pyplot
    from pandas import read_csv
    from pandas import DataFrame
    from pandas import concat
    from sklearn.preprocessing import MinMaxScaler
    from sklearn.preprocessing import LabelEncoder
    from sklearn.metrics import mean_squared_error
    from keras.models import Sequential
    from keras.layers import Dense
    from keras.layers import LSTM
    

    读取数据

    风机轮毂高度处风速、风向等来自WRF模式预报,实际功率来自风场实测。

    file_name='清洗完毕的风场数据.xls'
    need=pd.DataFrame(pd.read_excel(file_name))# 
    need.columns
    

    Index(['real power', 'wind speed', 'wind direction', 'pressure', 'temperature', 'humidity', 'air density'], dtype='object')

    定义函数风电场风速及风功率预测方法研究综述,将各列数据转换为监督学习形式

    #参数:
    #data:  list or NumPy array.
    #n_in: Number of lag observations as input (X).
    #n_out: Number of observations as output (y).
    #dropnan: Boolean whether or not to drop rows with NaN values.
    #Returns:
    #Pandas DataFrame of series framed for supervised learning.
    def series_to_supervised(data, n_in=, n_out=, dropnan=True):
        n_vars =  if type(data) is list else data.shape[]
        df = DataFrame(data)
        cols, names = list(), list()
        # input sequence (t-n, ... t-1)
        for i in range(n_in, , -1):
            cols.append(df.shift(i))
            names += [('var%d(t-%d)' % (j+, i)) for j in range(n_vars)]
        # forecast sequence (t, t+1, ... t+n)
        for i in range(, n_out):
            cols.append(df.shift(-i))
            if i == :
                names += [('var%d(t)' % (j+)) for j in range(n_vars)]
            else:
                names += [('var%d(t+%d)' % (j+, i)) for j in range(n_vars)]
        # put it all together
        agg = concat(cols, axis=)
        agg.columns = names
        # drop rows with NaN values
        if dropnan:
            agg.dropna(inplace=True)
        return agg
    

    数据归一化

    values = need.values 
    # 确保数据为32位浮点型
    values = values.astype('float32')
    #开始归一化
    scaler = MinMaxScaler(feature_range=(, ))
    scaled = scaler.fit_transform(values)
    

    将归一化后的数据使用series_to_supervised处理

    n_in=3
    n_out=2
    n_feature=need.columns.size #特征数量,包含实际风功率
    reframed = series_to_supervised(scaled,n_in, n_out)
    print(reframed.column)

    Index(['var1(t-3)', 'var2(t-3)', 'var3(t-3)', 'var4(t-3)', 'var5(t-3)', 'var6(t-3)', 'var7(t-3)', 'var1(t-2)', 'var2(t-2)', 'var3(t-2)', 'var4(t-2)', 'var5(t-2)', 'var6(t-2)', 'var7(t-2)', 'var1(t-1)', 'var2(t-1)', 'var3(t-1)', 'var4(t-1)', 'var5(t-1)', 'var6(t-1)', 'var7(t-1)', 'var1(t)', 'var2(t)', 'var3(t)', 'var4(t)', 'var5(t)', 'var6(t)', 'var7(t)', 'var1(t+1)', 'var2(t+1)', 'var3(t+1)', 'var4(t+1)', 'var5(t+1)', 'var6(t+1)', 'var7(t+1)'], dtype='object')

    根据实际需要,选取需要的变量,这里选取的预测目标为var1(t),即预测当前t时刻的风功率.

    reframed_selected=reframed [ ['var2(t-3)', 'var3(t-3)', 'var4(t-3)', 'var5(t-3)',
           'var6(t-3)', 'var7(t-3)', 'var2(t-2)', 'var3(t-2)',
           'var4(t-2)', 'var5(t-2)', 'var6(t-2)', 'var7(t-2)', 
           'var2(t-1)', 'var3(t-1)', 'var4(t-1)', 'var5(t-1)', 'var6(t-1)',
           'var7(t-1)',  'var2(t)', 'var3(t)', 'var4(t)', 'var5(t)',
           'var6(t)', 'var7(t)', 'var1(t)']]
    

    分割数据

    # 选取前90%的数据作为训练集,余下部分为测试集
    values = reframed_selected.values  #通过dataframs的values方法获取值
    n_train_15min=int(values.shape[0]*0.9)# 行数*90%得到索引位置
    train = values[:n_train_15min, :]
    test = values[n_train_15min:, :]
    # 再分别将测试集和训练集 按列分割为 test_X, test_y, tran_X, train_y
    train_X, train_y = train[:, :-1], train[:, -1]# 倒数第一列为预测目标y
    test_X, test_y = test[:, :-1], test[:, -1]
    

    将输入变形为三维 [样本量, 时间步长, 特征量]

    #将n_feature 减去1 是因为 tran_X 和test_X中没有包含var1,即没有包含实际功率这一特征
    #步长为n_in+1=4 ,包含t-1、t-2、t-3、t 共四步,也就是说,本文用t-1、t-2、t-3、t 时刻的气象预报数据来预测t时刻的风功率
    train_X = train_X.reshape(train_X.shape[], n_in+, n_feature-)
    test_X = test_X.reshape(test_X.shape[], n_in+, n_feature-)
    

    设计keras神经网络模型

    model = Sequential()#创建序贯模型
    #增添LSTM层,指定输入大小(train_X.shape[1], train_X.shape[2])
    model.add(LSTM(64, input_shape=(train_X.shape[1], train_X.shape[2]))) #n_units=64
    model.add(Dense(1))  # train_y ,test_y为一维,所以 Dense(1)
    model.compile(loss='mse', optimizer='adam')#编译,指定损失函数和优化器
    # 训练并拟合
    history = model.fit(train_X, train_y, epochs=30, batch_size=300, validation_data=(test_X, test_y), verbose=2, shuffle=False)
    #画出训练过程
    pyplot.plot(history.history['loss'], label='train')
    pyplot.plot(history.history['val_loss'], label='test')
    pyplot.legend()
    pyplot.show()
    

    结果如下:

    预测

    训练好模型后进行预测,运行此代码块若报错,可直接运行 yhat = model.predict(test_X)

    import tensorflow as tf
    global graph,model
    graph = tf.get_default_graph()
    with graph.as_default():
         yhat = model.predict(test_X)
    

    将三维数据再转变为二维

    test_X_2d= test_X.reshape((test_X.shape[],(n_in+)*(n_feature-)))
    

    将预测出的yhat与 test_x_2d的后六列合并,也就是 'var2(t)', 'var3(t)','var4(t)', 'var5(t)','var6(t)', 'var7(t)'合并 ,这样inv_yhat就成了7维,与当初归一化时values变量维度一样,且特征对应,从而能够顺利反归一化。也就是说归一化与反归一化时候,列数要保持一致,如果不一致则会报错。

    inv_yhat = concatenate((yhat, test_X_2d[:, -(n_feature-1):]), axis=)
    inv_yhat = scaler.inverse_transform(inv_yhat)
    inv_yhat = inv_yhat[:,]#挑选出预测出的风功率,即第一列
    

    这里也对测试集进行反归一化,只不过y是真实值,不是预测值

    test_y = test_y.reshape((len(test_y), 1))
    inv_y = concatenate((test_y, test_X_2d[:, -(n_feature-1):]), axis=1)
    inv_y = scaler.inverse_transform(inv_y)   #w
    inv_y = inv_y[:,0] #挑选出反归一化后真实的风功率
    

    评估

    #画出图像
    #rmse = sqrt(mean_squared_error(inv_y, inv_yhat))
    #print('Test RMSE: %.3f' % rmse)
    pyplot.plot(inv_y,label='actual')
    pyplot.plot(inv_yhat, label='model')  
    pyplot.legend()
    pyplot.show()

    此栗子只是一个线下的基线模型,大量参考了Jason Brownlee的博客开源代码,许多地方都可以改进,比如增加网络层数,改变网络结构(Bi-LSTM,CNN- LSTM),添加dropout层,使用earlystop,使用动态学习率等。在调参时,推荐使用调参库hyperopt或者talos,本文通过hyperopt对epoches、n_units、batch_size三个参数调参,选择出最优组合,提高了2%的合格率。另外,特征工程也至关重要,本文并没有对原始数据进行特征工程处理。 在上线的过程中风电场风速及风功率预测方法研究综述,若要及时预预报处多个风场的风功率,如何进行分布式运行等一系列问题需要去线上实验解决。

    ---------------------手动分割线------------------

    keras的LSTM运行过程中可能会产生报错: TypeError: while_loop() got an unexpected keyword argument 'maximum_iterations'解决方法 :使用 Keras 2.1.2, Tensorflow 1.4.1 版本, 可在window cmd中或者linux 命令行中输入:pip install keras==2.1.2pip install tensorflow==1.4.0

    本文代码主要参考了如下网络资源:

    发表评论