前言:
书接上回,通过把历年来的双色球蓝球数据爬取,可以看出,每期双色球蓝球之间并无任何关系,但仍存在问题:
决定蓝球数字可能并非取决于上一期蓝球的数据,可能取决于当期红球的数据,我们可能需要通盘考虑红球数据和蓝球数据。
那这期的任务就是:使用红球和蓝球数据作为训练集来训练神经网络,把上期双色球的数字来预测下期双色球的数字。
目标:
1、如果模型预测有效,(好家伙,发财了) 证明我们的搭建模型的方法存在问题。
2、如果模型预测无效,证明LSTM神经网络对于无规律数据的预测是无能为力的。
LSTM神经网络:
LSTM神经网络(长短时记忆神经网络)是RNN网络的一种变种,起初是为了解决RNN网络的很难有效利用历史记忆的问题而提出来的,在实践中证明,这一变种的神经网络能非常有效地利用历史数据来从中学习数据的规律。
LSTM网络的有三个门:记忆门、输出门、遗忘门。
其中,记忆门是由输入门(input gate)和tanh神经网络层和一个按位乘操作组成。作用是根据当前的输入和上面传递下来的信息来选择哪些信息需要被保留。
遗忘门的作用就是用来选择历史信息中哪些是有用的,哪些是需要被抛弃的。
输出门的作用就是把前面遗忘门与记忆门计算后的细胞状态, 与上一时刻的输出信号和当前时刻的输入信号整合到一起作为当前时刻的输出信号。传递给下一时刻。
绕晕了没关系,总之LSTM神经网络能很好地从历史数据中挖掘出需要的特征,所以关于时间序列的数据有不错的效果,在工业应用中的效果很好。
双色球预测:
1、数据爬取:
神经网络最重要的东西就是数据,没有数据,一切都是白搭,因此我们先把数据完整地从网站中用爬虫爬下来。
网站依旧是500彩票网。
期数一共是2668期。
爬虫代码根据上一次代码,修改了一点,加入了try语句,防止网络不好导致爬取失败,连续三次出错就会返回error。
import urllib.request
import pandas as pdbull_data = []def url_pachong():global test, bull_datablue_list = [89, 122, 153, 154, 153, 154, 154, 153, 154, 154, 154, 152, 154, 153, 154, 153, 151, 134, 24]for i in range(19):for j in range(blue_list[i]):attempts = 0success = Falsedata = []while attempts < 3 and success == False:try:if i < 7:response = urllib.request.urlopen("https://kaijiang.500.com/shtml/ssq/0" + str((i + 3) * 1000 + 1 + j) + ".shtml")print(str((i + 3) * 1000 + 1 + j))else:response = urllib.request.urlopen("https://kaijiang.500.com/shtml/ssq/" + str((i + 3) * 1000 + 1 + j) + ".shtml")print(str((i + 3) * 1000 + 1 + j))if (i + 3) * 1000 + 1 + j == 17001:success = Truecontinuehtml = response.read().decode("gbk", "ignore")a = 0for k in range(6):html_data = html.find('<li class="ball_red">', a + 10)a = html_datadata.append(int(html[html_data + 21] + html[html_data + 22]))html_data = html.find('<li class="ball_blue">')data.append(int(html[html_data + 22] + html[html_data + 23]))bull_data.append(list(data))success = Trueexcept:attempts += 1print('error')if attempts == 3:breakprint(bull_data)print("阶段%d完成" % int(i + 3))if __name__ == "__main__":url_pachong()test = pd.DataFrame(columns=['red1', 'red2', 'red3', 'red4', 'red5', 'red6', 'blue'], data=bull_data)test.to_csv('C:/Users/小幻月/Desktop/双色球数据爬取/bull_data2_c.csv')
爬取出来的数据保存到我自己桌面的文件夹里,需要的话可以自行更改。
爬取的数据如图所示。
2、LSTM神经网络训练
关于LSTM神经网络我们使用Tensorflow进行模型的搭建,Tensorflow可以很好地支持用Python进行模型的搭建。
但在使用模型进行预测前,我们需要对数据进行一些处理,一共需要做的有两步:
1、需要把原始数据划分成训练集和测试集,训练集用于对模型进行训练,测试集用于对模型效果的检验。
2、神经网络的输入需要我们构建一个三维的张量,目前的数据读取出来仅仅只是二维,需要对数据进行升维。
代码如下所示:
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from matplotlib import pyplot
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
from keras.layers import Dropoutdef series_to_supervised(data, n_in=1, n_out=1, dropnan=True):n_vars = 1 if type(data) is list else data.shape[1]df = DataFrame(data)cols, names = list(), list()# input sequence (t-n, ... t-1)for i in range(n_in, 0, -1):cols.append(df.shift(i))names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]# forecast sequence (t, t+1, ... t+n)for i in range(0, n_out):cols.append(df.shift(-i))if i == 0:names += [('var%d(t)' % (j+1)) for j in range(n_vars)]else:names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]# put it all togetheragg = concat(cols, axis=1)agg.columns = names# drop rows with NaN valuesif dropnan:agg.dropna(inplace=True)return aggif __name__ == "__main__":#数据的读取和处理dataset = read_csv('bull_data2_c.csv', index_col=0)dataset.index.name = 'data'values = dataset.valuesvalues = values.astype('float32')scaler = MinMaxScaler(feature_range=(0, 1)) #归一化scaled = scaler.fit_transform(values)reframed = series_to_supervised(scaled, 1, 1) #转变为监督学习values_ss = reframed.valuestrain_data = 2500 #训练集数目#划分训练集和测试集train = values_ss[:train_data, :]test = values_ss[train_data:, :]train_X = train[:, :7]train_Y = train[:, 7:]test_X = test[:, :7]test_Y = test[:, 7:]#升维成三维张量train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))#模型搭建model = Sequential()model.add(LSTM(50, input_shape=(train_X.shape[1], train_X.shape[2])))model.add(Dense(7))model.add(Dropout(0.25))model.compile(loss='mean_squared_error', optimizer='adam')model.fit(train_X, train_Y, epochs=50, batch_size=1, validation_data=(test_X, test_Y), verbose=1, shuffle=False)model.save("my_model.h5")#利用模型进行预测yhat = model.predict(test_X)yhat_change = scaler.inverse_transform(yhat)test_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))test_Y = scaler.inverse_transform(test_Y)for i in range(test_X.shape[0]):pyplot.plot(yhat_change[i])pyplot.plot(test_Y[i])pyplot.show()
由代码中可以看到,我们把前2500期作为训练数据,剩下的作为测试集。
其中有个子程序series_to_supervised
,这个程序的作用是把数据变为监督学习所用,效果就是会把下一行的数据当做上一行数据输入的结果,建立起因果关系去告诉模型按这个输入输出来学习。
具体可以参考文章:
浅笑古今:将时间序列预测问题转换为python中的监督学习问题
其输出结果是一个长2666宽14的矩阵,我们把前7列剪出来作为输入,后7列剪出来作为输出结果。
再把前2500行剪出来作为训练集,剩下的作为测试集。
划分成train_X(2500,7),train_Y(2500,7),test_X(166,7),test_X(166,7)四个矩阵。
注意:神经网络的输入需要是一个三维的张量,不能是二维的平面
因此,把其中的训练集输入train_X(2500,7)和test_X(166,7)升维成三维的(2500,1,7)和(166,1,7)。
至此,神经网络的数据处理部分完成了,接下来就是神经网络的搭建和参数的设置,还有使用神经网络进行预测。
model = Sequential()model.add(LSTM(50, input_shape=(train_X.shape[1], train_X.shape[2])))model.add(Dense(7))model.add(Dropout(0.25))model.compile(loss='mean_squared_error', optimizer='adam')model.fit(train_X, train_Y, epochs=50, batch_size=1, validation_data=(test_X, test_Y), verbose=1, shuffle=False)
以上代码是神经网络的搭建和参数的设置部分。
1、设置模型为序贯模型(从头到尾不分叉的线性堆叠模型)。
2、模型设置为LSTM,输入的形式设置为train_X的张量。
3、设置模型的全连接层,输出为7。
4、设置随机失活。
5、设置损失函数和优化器。
6、设置模型参数,包括训练输入、训练输出、神经元数目、优化步长、验证集、模式、不打乱。
以上,模型设置完成,model.fit语句后将自动开始模型的训练,当模型训练完成后,model.save语句会将训练好的模型保存下来,之后再调用模型时,将不再需要从头开始训练,直接使用:
model = load_model("my_model.h5")
加载模型,可以直接跳到下面的预测部分。
模型预测:
将测试集送入模型进行预测,主注意送入模型的数据必须为三维张量,模型输出为二维的数组。
将数组进行逆变换后,用matlab的包展示出来即可。
结论:
单组7个数据,前六个为红球数据,最后为蓝球数据,中间的直线(颜色最深的那一条)为预测数据,由于双色球红球数据为升序排列,实际期并不能预测出任何效果。
其实把数据打乱来预测才是正确的,但没必要了(懒了),能证明LSTM神经网络对于无规律数据是不起作用就行了。
PS:LSTM神经网络对于其他有规律的数据效果是极好的哦,比如轴承正常运转的振动数据、电机正常运转的振动数据等等。
结束语:
其实一开始我已经知道双色球数据是不可能预测出来的,但搞这么多的目标并非真的是为了找出双色球的数据顺序,只是将LSTM神经网络用在其他有规律的数据上时效果好到令我惊讶,甚至一度怀疑我是不是搞错了直接输出结果,所以我借助这个反例来证明我们搭建模型的方法是正确的,从中学习python和神经网络的使用方法、精进自己才是最终目的。(其实我还是有点想借双色球发财的)
小幻月
2021年3月29日