介绍预测股市的走势是最困难的事情之一。影响预测的因素很多 - 包括物理因素与心理因素,理性行为和非理性行为等。所有这些因素结合在一起共同导致股价波动,很难以高精度预测。 我们是否可以将机器学习作为该领域的游戏规则改变者吗?利用一些特性,比如关于一个组织的最新公告,他们的季度收入结果等功能,机器学习技术有可能发掘出我们以前没有看到的模式和见解,并且可以用来做出准确无误的预测。 在本文中,我们将使用有关上市公司股票价格的历史数据。我们将使用多种机器学习算法来预测该公司的未来股票价格,从平均算法和线性回归等简单的算法开始,然后转向Auto ARIMA和LSTM等高级技术。 本文背后的核心思想是展示如何实现这些算法。我将简要介绍该技术并提供相关链接,以便在必要时了解这些概念。 问题描述我们很快就会深入到本文的实现部分,但首先要确定我们要解决的问题。从广义上讲,股票市场分析分为两部分 - 基础分析和技术分析。
你可能已经猜到了,我们的重点将放在技术分析部分。我们将使用Quandl的数据集(你可以在这里查找各种股票的历史数据),对于这个特定的项目,我使用了“ 塔塔全球饮料 ” 的数据。是时候让我们动起来了! 注意:有关文章的数据集我将在文章最后放出 首先我们先加载数据集,定义问题的目标变量: 导入包import pandas as pd 在笔记本上绘图import matplotlib.pyplot as plt 设置图的大小from matplotlib.pylab import rcParams 规范数据from sklearn.preprocessing import MinMaxScaler 读取文件df = pd.read_csv('NSE-TATAGLOBAL(1).csv') 打印头部数据df.head() 数据集中有多个变量 - date,open,high,low,last,close,totaltradequantity和turnover。
另一个需要注意的重要事项是,市场在周末和公共假期关闭。再次注意上表,一些日期值缺失 - 2/10/201,6/10/201,7/10/201。在这些日期中,2号是法定假日,6号和7号是周末。 损益的计算通常由当天股票的收盘价确定,因此我们将收盘价视为目标变量。让我们绘制目标变量,以了解它在我们的数据中是如何形成的: 将索引设置为日期df['Date'] = pd.to_datetime(df.Date,format='%Y-%m-%d') 画图plt.figure(figsize=(16,8)) 在接下来的部分中,我们将探索这些变量,并使用不同的技术来预测股票的每日收盘价。 1.移动平均法介绍“平均”很容易成为我们日常生活中最常用的词汇之一。例如,计算平均分来确定整体性能,或者找出过去几天的平均温度以了解今天的温度 - 这些都是我们经常做的例行工作。因此,这是一个很好的起点,可以用于我们的数据集进行预测。 每天的预计收盘价将是一组先前观测值的平均值。我们将使用移动平均技术而不是使用简单平均值,该技术为每个预测使用最新的一组值。换句话说,对于每个后续步骤,在从集合中移除最老的观测值的同时考虑预测值。下面是一个简单的图形,可以帮助你更清晰地理解这一点。 我们将在我们的数据集上实现此技术。第一步是创建一个仅包含Date和Close price列的DataFrame,然后将其拆分为训练集和验证集以验证我们的预测。 Python代码使用日期和目标变量创建dataframedata = df.sort_index(ascending=True, axis=0) for i in range(0,len(data)): 在将数据拆分为训练集和验证集时,我们不能使用随机拆分,因为这会破坏时间组件。所以这里我把去年的数据和之前四年的数据进行了验证。 分隔为训练集和验证集train = new_data[:987] new_data.shape, train.shape, valid.shape train['Date'].min(), train['Date'].max(), valid['Date'].min(), valid['Date'].max() (Timestamp('2013-10-08 00:00:00'), 下一步是为验证集创建预测,并使用实际值检查RMSE。 做出预测preds = [] 结果计算 rmserms=np.sqrt(np.mean(np.power((np.array(valid['Close'])-preds),2))) 104.51415465984348 仅检查RMSE并不能帮助我们理解模型的执行方式。让我们把它形象化来获得更直观的理解。因此,这是预测值与实际值的关系图。 画图valid['Predictions'] = 0 推论RMSE值接近105,但结果不是很有希望(可以从图中看出)。预测值与验证集中的观测值具有相同的范围(最初存在增加趋势,然后缓慢减小)。 在下一节中,我们将介绍两种常用的机器学习技术 - 线性回归和kNN,并了解它们在我们股票市场数据上的表现。 2.线性回归介绍可以在此数据上实现的最基本的机器学习算法是线性回归。线性回归模型返回一个确定自变量和因变量之间关系的方程。 线性回归的方程可以写成: 这里,x1,x2,... .Xň代表独立变量,而系数θ1,θ2,...θÑ表示的权重。 对于我们的问题描述,我们没有一组自变量。我们只有日期而已。让我们使用日期列来提取诸如 - 日,月,年,星期一/星期五等特征,然后拟合线性回归模型。 Python代码我们将首先按升序对数据集进行排序,然后创建一个单独的数据集,以便创建的任何新要素都不会影响原始数据。 将索引设置为日期值df['Date'] = pd.to_datetime(df.Date,format='%Y-%m-%d') 排序data = df.sort_index(ascending=True, axis=0) 创建单独的数据集new_data = pd.DataFrame(index=range(0,len(df)),columns=['Date', 'Close']) for i in range(0,len(data)): 创建功能from fastai.structured import add_datepart 这会创建以下特征: ‘Year’, ‘Month’, ‘Week’, ‘Day’, ‘Dayofweek’, ‘Dayofyear’, ‘Ismonthend’, ‘Ismonthstart’, ‘Isquarterend’, ‘Isquarterstart’, ‘Isyearend’, and ‘Isyearstart’. 注意:我使用了fastai库中的add_datepart。如果你没有安装它,只需使用命令pip install fastai。或者,你可以在python中使用简单的for循环创建这个功能。我在下面展示了一个例子。 除此之外,我们可以添加我们自己认为与预测相关的特征。例如,我的假设是,本周的第一天和最后一天可能会影响股票的收盘价,并且远远超过其他日子。所以我创建了一个特征,可以确定某一天是周一/周五还是周二/周三/周四。这可以使用以下的代码行完成: new_data['mon_fri'] = 0 如果星期几等于0或4,则列值将为1,否则为0。同样的,你可以创建多个特征。如果你对可以帮助预测股票价格的功能有一些想法,请在评论区分享。 我们现在将数据拆分为训练集和验证集,以检查模型的性能。 拆分为训练集与验证集train = new_data[:987] x_train = train.drop('Close', axis=1) 实现线性回归from sklearn.linear_model import LinearRegression 结果做出预测并找rmsepreds = model.predict(x_valid) 121.16291596523156 RMSE值高于之前的技术,这清楚地表明线性回归表现不佳。让我们看一下图表,并理解为什么线性回归做的不好: 画图valid['Predictions'] = 0 valid.index = new_data[987:].index plt.plot(train['Close']) 推论线性回归是一种简单的技术,并且很容易解释,但有一些明显的缺点。使用回归算法的一个问题是模型与日期列和月份列过度匹配。模型将考虑一个月前的同一日期或一年前的同一日期/月的值,而不是从预测的角度考虑以前的值。 从上图可以看出,2016年1月和2017年1月,股价出现下跌。该模型已预测2018年1月的情况相同。线性回归技术可以很好地解决诸如大型超市的销售问题,在这些问题中独立特征对于确定目标值是有用的。 3.K-近邻介绍这里可以使用的另一个有趣的ML算法是KNN(K近邻)。KNN基于自变量找到新数据点和旧数据点之间的相似性。让我用一个简单的例子解释一下。 考虑11个人的身高和年龄。根据给定的特征('年龄Age'和'身高Height'),表格可以用图形格式表示,如下所示: 为了确定ID#11的权重,K-NN考虑该ID的最近邻的权重。ID#11的权重预计是其邻居的平均值。如果我们现在考虑三个邻居(k = 3),ID#11的权重将是=(77 + 72 + 60)/ 3 = 69.66千克。 PYthon代码导入库from sklearn import neighbors 使用上一节中相同的训练集和验证集: 尺度数据x_train_scaled = scaler.fit_transform(x_train) 使用gridsearch查找最佳参数params = {'n_neighbors':[2,3,4,5,6,7,8,9]} 拟合模型并做出预测model.fit(x_train,y_train) 结果查看RMSe值rms=np.sqrt(np.mean(np.power((np.array(y_valid)-np.array(preds)),2))) 115.17086550026721 RMSE值没有太大差异,但预测值和实际值的图应提供一个更清晰的理解。 画图valid['Predictions'] = 0 推论RMSE值几乎与线性回归模型类似,并且图表也显示了相同的模式。与线性回归一样,KNN也确定了2018年1月的下降,因为这是过去几年的形式。我们可以有把握地说,回归算法在这个数据集上表现不佳。 让我们继续看看一些时间序列预测技术,以了解它们在面对股票价格预测挑战时的表现。 4.Auto ARIMA介绍ARIMA是一种非常流行的时间序列预测统计方法。ARIMA模型考虑了过去的值来预测未来的价值。ARIMA有三个重要参数:
ARIMA的参数调整会消耗大量时间。因此,我们将使用auto ARIMA,它自动选择(p,q,d)提供最小错误的的最佳组合。 Python代码from pyramid.arima import auto_arima data = df.sort_index(ascending=True, axis=0) train = data[:987] training = train['Close'] model = auto_arima(training, start_p=1, start_q=1,max_p=3, max_q=3, m=12,start_P=0, seasonal=True,d=1, D=1, trace=True,error_action='ignore',suppress_warnings=True) forecast = model.predict(n_periods=248) 结果rms=np.sqrt(np.mean(np.power((np.array(valid['Close'])-np.array(forecast['Prediction'])),2))) 44.954584993246954 画图plt.plot(火车[ '关闭']) 推论如前所述,auto ARIMA模型使用过去的数据来理解时间序列中的模式。使用这些值,模型获得了该系列中的增长趋势。虽然使用这种技术的预测远比先前实现的机器学习模型的预测好,但这些预测仍然没有接近实际值。 从图中可以看出,该模型已经捕捉到了该系列中的一个趋势,但并没有关注季节性部分。在下一节中,我们将实现一个时间序列模型,而这个模型考虑了系列的趋势和季节性。 5.Prophet介绍有许多时间序列技术可以在股票预测数据集上实现,但是大多数这些技术在拟合模型之前需要大量的数据预处理。由Facebook设计和开创的Prophet是一个时间序列预测库,它不需要数据预处理,实现起来也非常简单。Prophet的输入是一个包含两列的数据框:date和target(ds和y)。 Prophet试图获取过去数据中的季节性,并在数据集很大时可以进行很好的工作。 Python代码导入 prophetfrom fbprophet import Prophet 创建 dataframenew_data = pd.DataFrame(index=range(0,len(df)),columns=['Date', 'Close']) for i in range(0,len(data)): new_data['Date'] = pd.to_datetime(new_data.Date,format='%Y-%m-%d') 准备数据new_data.rename(columns={'Close': 'y', 'Date': 'ds'}, inplace=True) 训练和验证train = new_data[:987] 使用合适的模型model = Prophet() 预测close_prices = model.make_future_dataframe(periods=len(valid)) 结果查看rmseforecast_valid = forecast['yhat'][987:] 57.494461930575149 画图valid['Predictions'] = 0 plt.plot(train['y']) 推论Prophet(与大多数时间序列预测技术一样)试图从过去的数据中获取趋势性和季节性。此模型通常在时间序列数据集上表现良好,但在这种情况下无法达到它的名誉。 事实证明,股票价格没有特定的趋势性或季节性。它在很大程度上取决于市场目前的情况,从而价格会上涨和下跌。因此,像ARIMA,SARIMA和Prophet这样的预测技术对于这个特定问题不会显示出良好的结果。 让我们继续尝试另一种先进技术 - 长短时记忆(LSTM)。 6.长短时记忆(LSTM)介绍LSTM广泛用于序列预测问题,并且已被证明是非常有效的。他们非常有效的原因是因为LSTM能够存储过去重要的信息,并忘记不重要的信息。LSTM有三个门:
现在,让我们将LSTM实现为一个黑盒子,并检查它在我们的特定数据上的性能。 Python代码导入所需要的库from sklearn.preprocessing import MinMaxScaler 创建dataframedata = df.sort_index(ascending=True, axis=0) 设置索引new_data.index = new_data.Date 创建训练集和测试集dataset = new_data.values train = dataset[0:987,:] 将数据集转换为X列和Y列scaler = MinMaxScaler(feature_range=(0, 1)) x_train, y_train = [], [] x_train = np.reshape(x_train, (x_train.shape[0],x_train.shape[1],1)) 创建并使用LSTM网络model = Sequential() model.compile(loss='mean_squared_error', optimizer='adam') 使用训练集中的过去的60个值预测246个值inputs = new_data[len(new_data) - len(valid) - 60:].values X_test = [] X_test = np.reshape(X_test, (X_test.shape[0],X_test.shape[1],1)) 结果rms=np.sqrt(np.mean(np.power((valid-closing_price),2))) 11.772259608962642 画图train = new_data[:987] 推论LSTM模型可以根据不同的参数进行调整,例如改变LSTM层的数量,添加dropout值或增加epoch的数量。但LSTM的预测是否足以确定股价是涨还是降?当然不是! 正如我在文章开头提到的那样,股票价格受到有关公司的新闻以及其他因素的影响,如公司的非货币化或合并/分拆。还有一些无形因素,往往是事先无法预测的。 结束笔记时间序列预测是一个非常有趣的领域,正如我在撰写这些文章时所认识到的那样。在社区中有一种看法,认为它是一个非常复杂的领域,虽然有些的确比较复杂,但是一旦掌握了基本技术,也就不那么困难了。 本文作者使用了六种方法来进行了对股票涨跌的预测,并从结果中分析了每个算法用于时间序列模型的优劣,并且从图中可以看出LSTM方法是拟合最好的一种方法,但是股票市场需要考虑的因素有很多,并不是只需要几个关键的特征就可以预测的,我们可以根据以前的数据,对算法进行验证,但使用算法去预测未来的股票的涨跌,还是有一些风险的,所以还是要谨慎的去使用这些算法。至少现在没有一种算法可以百分之百的去预测未来股票的时间序列模型算法,还是先暂时的用算法去不断的训练,直到未来技术成熟的一天。 Stock Prices Prediction Using Machine Learning and Deep Learning Techniques (with Python codes) |
|
来自: CDA数据分析师 > 《职场攻略·人能生规划·生活百态》