情感数据对LSTM股票预测模型的影响研究

情感数据对LSTM股票预测模型的影响研究

作者:丁纪翔

发布时间:06/28/2021

摘要:探究了情感结构化特征数据在LSTM股票预测模型中的影响。利用Pandas对所给数据进行预处理(数据载入、清洗与准备、规整、时间序列处理、数据聚合等)。[1] 借助NLTK和LM金融词库,对非结构化文本信息进行情感分析,并将所得结构化数据融入纯技术指标的股票数据中。分析各股票指标的相关性,实现数据降维。基于Keras的以MSE为误差评价方法的LSTM模型,实现对股票收盘价Close的预测。最终得出当训练样本充足时,融入了情感特征数据,使得预测精度适当增加的结论。

实验说明

设计一个预测股票价格的方法,并用实例证明此方法的有效性

所给的数据,要求全部都要使用,注意数据需清洗、特征综合使用,可自己额外补充资源或数据。

提供的数据说明

  1. 全标题

    a) 这是股票平台上发布的对各公司的分析文章

    b) 标题:文章的标题

    c) 字段1_链接_链接:原文章所在的URL

    d) ABOUT:文章针对的公司,都为缩写形式,多个公司以逗号隔开

    e) TIME:文章发布的时间

    f) AUTHOR:作者

    g) COMMENTS:采集时,文章的被评论次数

  2. 摘要

    a) 这是股票平台上发布的对各公司的分析文章的摘要部分,和“全标题”中的内容对应

    b) 标题:文章的标题

    c) 字段2:文章发布的时间

    d) 字段5:文章针对的公司及提及的公司;

    ​ i. About为针对公司,都提取缩写的大写模型,多个公司以逗号隔开

    ​ ii. include为提及的其它公司,都提取缩写的大写模型,多个公司以逗号隔开

    e) 字段1:摘要的全文字内容

  3. 回帖

    a) 这是网友在各文章下的回复内容

    b) Title:各文章的标题;空标题的,用最靠近的有内容的下方标题

    c) Content:回复的全文字内容

  4. 论坛

    a) 这是网友在各公司的论坛页面下,对之进行评论的发帖内容

    b) 字段1:作者

    c) 字段2:发帖日期

    d) 字段3:帖子内容

    e) 字段4_链接:具体的各公司的页面URL

  5. 股票价格

    a) 为各公司工作日股票的价格

    b) PERMNO:公司编号

    c) Date:日期

    d) TICKER:公司简写

    e) COMNAM:公司全写

    f) BIDLO:最低价

    g) ASKHI:最高价

    h) PRC: 收盘价

    i) VOL:成交量

    j) OPENPRC: 开盘价

文章目录

  • 情感数据对LSTM股票预测模型的影响研究
    • 1 LSTM
      • 1.1 LSTM是什么?
      • 1.2 为什么决定使用LSTM?
    • 2 深度学习名词概念解释
      • 2.1 为什么要使用多于一个epoch?
      • 2.2 Batch 和 Batch_Size
      • 2.3 Iterations
      • 2.4 为什么不要shuffle?
    • 3 实验过程
      • 3.1 库导入
      • 3.2 pandas核心设置
      • 3.3 数据载入、数据清洗与准备、数据规整、时间序列处理
        • 3.3.1 股票价格.csv
        • 3.3.2 论坛.csv
        • 3.3.3 全标题.xlsx
        • 3.3.4 摘要.xlsx
        • 3.3.5 回帖
      • 3.4 情感分析
        • 3.4.1 情感分析思路
        • 3.4.2 词库导入和添加停用词
        • 3.4.3 函数定义
        • 3.4.4 情感分析处理
        • 3.4.5 情感特征数据聚合
      • 3.5 \* 融入情感数据的股票指标相关性分析
        • 3.5.1 数据联合
        • 3.5.2 pairplot绘图
        • 3.5.3 股票指标相关性分析
      • 3.6 LSTM预测融合情感特征的股票数据
        • 3.6.1 时间序列转有监督函数定义
        • 3.6.2 融合情感的股票数据归一化
        • 3.6.3 时间序列构建有监督数据集
        • 3.6.4 训练集验证集划分
        • 3.6.5 基于Keras的LSTM模型搭建
          • 3.6.5 (一)、重塑LSTM的输入X
          • 3.6.5 (二)、搭建LSTM模型并绘制损失图
        • 3.6.6 预测结果并反归一化
        • 3.6.7 模型评估
      • 3.7 对比实验:预测纯技术指标的股票数据
        • 3.7.1 对比实验流程(通用函数构造)
        • 3.7.2 对比实验结果分析
        • 3.7.3 对比实验结论
      • 3.8 补充对比实验:补充AAPL股票技术指标样本量进行预测
        • 3.8.1 数据获取
        • 3.8.2 数据处理
        • 3.8.3 预测分析
        • 3.8.4 结果分析
      • 3.9 2018全年含情感特征的股票数据预测实验
        • 3.9.1 情感特征数据聚合
        • 3.9.2 预测分析
        • 3.9.3 结果分析
    • 4. 结论与总结
    • 5. 参考文献

核心思想:使用LSTM模型解决股票数据的时间序列预测问题和使用NLTK库对文本情感进行分析。

根本观点:历史会不断重演。本次作业均基于如下假设,股票规律并不是完全随机的,而是受人类心理学中某些规律的制约,在面对相似的情境时,会根据以往的经验和规律作出相似的反应。因此,可以根据历史资料的数据来预测未来股票的波动趋势。在股票的技术指标中,收盘价是一天结束时的价格,又是第二天的开盘价,联系前后两天,因此最为重要。[2]

影响因素:影响股票价格的因素除了基本的股票技术指标外,股票价格还和股民的情绪和相关股票分析文章的情感密切相关。

分析方法:将股票的技术指标和股民大众的情感评价相结合[3],选择AAPL个股,对股票价格,即收盘价进行预测。分别对只含有技术指标和含有技术指标和情感评价的样本进行LSTM建模,使用MSE(均方误差)作为损失函数,对二者预测结果进行评价。

1 LSTM

1.1 LSTM是什么?

LSTM Networks(Long Short-Term Memory)- Hochreiter 1997,长短期记忆神经网络,是一种特殊的RNN,能够学习长的依赖关系,记住较长的历史信息。

1.2 为什么决定使用LSTM?

Deep Neural Networks (DNN),深度神经网络,有若干输入和一个输出,在输出和输入间学习得到一个线性关系,接着通过一个神经元激活函数得到结果1或-1. 但DNN不能较好地处理时间序列数据。Recurrent Neural Networks (RNN),循环神经网络,可以更好地处理序列信息,但其缺点是不能记忆较长时期的时间序列,而且 Standard RNN Shortcomings 难以训练,给定初值条件下,收敛难度大。

LSTM解决了RNN的缺陷。LSTM相较于RNN模型增加了Forget Gate Layer(遗忘门),可以对上一个节点传进的输入进行选择性忘记。接着,选择需要记忆的重要输入信息。也就是“忘记不重要的,记住重要的”。这样,就解决了RNN在长序列训练过程中的梯度消失和梯度爆炸问题,在长序列训练中有更佳的表现。因此,我选用LSTM作为股票时间序列数据的训练模型。

2 深度学习名词概念解释

WrodsDefinitions
Epoch使用训练集的全部数据对模型进行一次完整的训练,被称之为“一代训练”。包括一次正向传播和一次反向传播
Batch使用训练集中的一小部分样本对模型权重进行一次反向传播的参数更新,这一小部分样本被称为“一批数据
Iteration使用一个Batch数据对模型进行一次参数更新的过程,被称之为“一次迭代

[Source1] https://www.jianshu.com/p/22c50ded4cf7?from=groupmessage

2.1 为什么要使用多于一个epoch?

只传递一次完整数据集是不够的,需要在神经网络中传递多次。随着epoch数量的增加,神经网络中的权重更新次数也在增加,这就导致了拟合曲线从欠拟合变为过拟合。

每次epoch之后,需要对总样本shuffle,再进入下一轮训练。(本次实验不用shuffle)

对不同数据集,epoch个数不同。

2.2 Batch 和 Batch_Size

目前绝大部分深度学习框架使用Mini-batch Gradient Decent 小批梯度下降,把数据分为若干批(Batch),每批有Batch_Size个数据,按批更新权重,一个Batch中的一组数据共同决定本次梯度的下降方向。
NumberofBatches=TrainingSetSizeBatchSizeNumber of Batches = \frac{Training Set Size}{Batch Size} NumberofBatches=BatchSizeTrainingSetSize

小批梯度下降克服了在数据量较大的情况下时,Batch Gradient Decent 的计算开销大、速度慢 和 Stochastic Gradient Decent 的随机性、收敛效果不佳的缺点。

[Source2] https://blog.csdn.net/dancing_power/article/details/97015723

2.3 Iterations

一次iteration进行一次前向传播和反向传播。前向传播,基于属性X,得到预测结果y。反向传播根据给定的损失函数,求解参数(权重)。
NumbersofIterations=NumberofBatchedNumbers of Iterations = Number of Batched NumbersofIterations=NumberofBatched

2.4 为什么不要shuffle?

避免数据投入的顺序对网络训练造成影响,增加训练的随机性,提高网络的泛化性能。

但是针对本次股票价格的预测,使用LSTM模型,考虑时间因素,因此,需要设置shuffle=False,按时序顺序依次使用Batch更新参数。

3 实验过程

以下实验均基于对Apple, Inc.(AAPL)苹果公司的股票进行预测分析。

CORPORATIONABBR = 'AAPL'

3.1 库导入

# 数据分析的核心库
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
# 时间序列处理
from datetime import datetime
from dateutil.parser import parse as dt_parse
# 正则库
import re
# os库
from os import listdir
# NLTK自然语言处理库
import nltk
from nltk.corpus import stopwords
# seaborn成对图矩阵生成
from seaborn import pairplot
# sklearn库的归一化、训练集测试集划分
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
# Keras LSTM
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
# sklearn MSE
from sklearn.metrics import mean_squared_error

3.2 pandas核心设置

# 设置pandas的最大显示行数、列数和输出宽度
pd.set_option('display.max_rows', 6)
pd.set_option('display.max_columns', 999)
pd.set_option('display.max_colwidth', 50)

3.3 数据载入、数据清洗与准备、数据规整、时间序列处理

3.3.1 股票价格.csv

sharePrices = pd.read_csv('股票价格.csv')
sharePrices
PERMNOdateTICKERCOMNAMBIDLOASKHIPRCVOLOPENPRC
01002620180702JJSFJ & J SNACK FOODS CORP150.70000153.27499152.92000100388.0152.17999
11002620180703JJSFJ & J SNACK FOODS CORP151.35001153.73000153.3200155547.0153.67000
21002620180705JJSFJ & J SNACK FOODS CORP152.46001156.00000155.81000199370.0153.95000
..............................
9415159343620181227TSLATESLA INC301.50000322.17169316.130008575133.0319.84000
9415169343620181228TSLATESLA INC318.41000336.23999333.870009938992.0323.10001
9415179343620181231TSLATESLA INC325.26001339.20999332.799996302338.0337.79001

941518 rows × 9 columns

索引过滤:索引过滤出TICKER(公司简写)为AAPL的数据行。

sharePricesAAPL = sharePrices[sharePrices['TICKER']==CORPORATIONABBR]

DataFrame降维:不需要PERMNO(公司编号)、COMNAM(公司全写)、TICKER(公司简写)这三列数据,删除列。

sharePricesAAPL.drop(['PERMNO', 'COMNAM', 'TICKER'], axis=1, inplace=True)

索引数据类型检测:确保相应索引的数据类型为float。

sharePricesAAPL.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 126 entries, 163028 to 163153
Data columns (total 6 columns):#   Column   Non-Null Count  Dtype  
---  ------   --------------  -----  0   date     126 non-null    int64  1   BIDLO    126 non-null    float642   ASKHI    126 non-null    float643   PRC      126 non-null    float644   VOL      126 non-null    float645   OPENPRC  126 non-null    float64
dtypes: float64(5), int64(1)
memory usage: 6.9 KB

索引检查:检查date索引是否存在重复。

sharePricesAAPL['date'].is_unique
True

时间序列:将date(日期)转化为时间序列索引,并按此时间序列以升序排序。

# date列转化为datetime类
sharePricesAAPL['date'] = sharePricesAAPL['date'].apply(lambda dt: datetime.strptime(str(dt), '%Y%m%d'))
# 设date列为索引
sharePricesAAPL.set_index('date', inplace=True)
# 按date升序排列
sharePricesAAPL.sort_values(by='date', inplace=True, ascending=True)
BIDLOASKHIPRCVOLOPENPRC
date
2018-07-02183.42000187.30187.1799917612113.0183.82001
2018-07-03183.53999187.95183.9200013909764.0187.78999
2018-07-05184.28000186.41185.3999916592763.0185.25999
..................
2018-12-27150.07001156.77156.1499953117005.0155.84000
2018-12-28154.55000158.52156.2300042291347.0157.50000
2018-12-31156.48000159.36157.7400135003466.0158.53000

126 rows × 5 columns

缺失值处理:检查AAPL股票技术指标数据每列缺失比,发现无缺失。若有,则可对BIDLO(最低价)、ASKHI(最高价)、PRC收盘价、VOL(成交量)有缺失的数据行直接删除。对OPENPRC(开盘价)有缺失的使用拉格朗日插值法进行填充。

其实之后对股票价格.csv分析可知,缺失项的分布都在同一行,故只要使用df.dropna()删除存在任意数目缺失项的行即可。

sharePricesAAPL.isnull().mean()
BIDLO      0.0
ASKHI      0.0
PRC        0.0
VOL        0.0
OPENPRC    0.0
dtype: float64

重建索引:重命名索引,方便后期使用,映射为BIDLO-low、ASKHI-high、PRC-close、VOL-vol、OPENPRC-open。改变索引顺序为open、high、low、vol、close。

# rename
AAPL_newIndex = {'BIDLO': 'low','ASKHI': 'high','PRC': 'close','VOL': 'vol','OPENPRC': 'open'}
sharePricesAAPL.rename(columns=AAPL_newIndex, inplace=True)
# reindex
AAPL_newColOrder = ['open', 'high', 'low', 'vol', 'close']
sharePricesAAPL = sharePricesAAPL.reindex(columns=AAPL_newColOrder)

检测过滤异常值:无异常。

sharePricesAAPL.describe()
openhighlowvolclose
count126.000000126.000000126.0000001.260000e+02126.000000
mean201.247420203.380885198.8933443.510172e+07201.106033
std21.36852421.49993221.5969661.577876e+0721.663971
..................
50%207.320000209.375000205.7851503.234006e+07207.760005
75%219.155000222.172503216.7981754.188390e+07219.602500
max230.780000233.470000229.7800009.624355e+07232.070010

8 rows × 5 columns

数据存储:存储处理好的数据为AAPL股票价格.csv,存至补充数据1925102007文件夹。方便后续读取使用。

sharePricesAAPL.to_csv('补充数据1925102007/AAPL股票价格.csv')

3.3.2 论坛.csv

字段1字段2字段3字段4_链接
0ComputerBlue31-Dec-18Let's create a small spec POS portfolio $COTY ...https://seekingalpha.com/symbol/COTY
1Darren McCammon31-Dec-18$RICK "Now that we've reported results, we'll ...https://seekingalpha.com/symbol/RICK
2Jonathan Cooper31-Dec-18Do any $APHA shareholders support the $GGB tak...https://seekingalpha.com/symbol/APHA
...............
25114Power Hedge1-Jan-18USD Expected to Collapse in 2018 https://goo.g...https://goo.gl/RG1CDd
25115Norman Tweed1-Jan-18Happy New Year everyone! I'm adding to $MORL @...https://seekingalpha.com/symbol/MORL
25116User 409863051-Jan-18Jamie Diamond says Trump is most pro business ...NaN

25117 rows × 4 columns

缺失值处理:删除字段4(各公司页面的URL)缺失的数据行。

forum = pd.read_csv('论坛.csv')
forum.dropna(inplace=True)

字符串操作和正则:观察字段4(URL),seekingalpha.com/symbol/网址后的内容为公司简称,使用pandas字符串操作和正则对公司简称进行提取,提取失败则删除该数据行。将字段4的数据内容替换为公司简称。

forum_regExp = re.compile(r'seekingalpha\.com/symbol/([A-Z]+)')
def forumAbbr(link):# 成功查找公司简称则返回简称,否则以缺失值填补res = forum_regExp.search(link)return np.NAN if res is None else res.group(1)
forum['字段4_链接'] = forum['字段4_链接'].apply(forumAbbr)

索引过滤:提取所有公司简称为AAPL的评论。

降维处理:字段1(作者名称)无用,可以删除。

索引重构:重命名索引,字段3(帖子内容)-remark。

时间序列:将字段2转化为时间序列索引,命名为date,并按此索引升序排列。

# 索引过滤
forum = forum[forum['字段4_链接']==CORPORATIONABBR]
# 降维处理
forum.drop(['字段1', '字段4_链接'], axis=1, inplace=True)
# 索引重构
AAPL_newIndex_forum = {'字段2': 'date', '字段3': 'remark'}
forum.rename(columns=AAPL_newIndex_forum, inplace=True)
# 时间序列
forum['date'] = forum['date'].apply(lambda dt: datetime.strptime(str(dt), '%d-%b-%y'))

正则过滤评论网址:观察评论不难发现,部分评论内有网址,使用正则表达式过滤之,防止对后续情感分析产生影响。

forum_regExp_linkFilter = re.compile(r'(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?')
forum['remark'] = forum['remark'].apply(lambda x: forum_regExp_linkFilter.sub('', x))
forum
dateremark
2042018-12-26Many Chinese companies are encouraging their e...
4182018-12-21This Week in Germany 🇩🇪 | Apple Smashed 📱 $AAP...
4712018-12-21$AAPL gets hit with another partial ban in Ger...
.........
247022018-01-05$AAPL. Claims by GHH is 200 billion repatriati...
249022018-01-03$AAPL Barclays says battery replacement could ...
250832018-01-022018 will be the year for $AAPL to hit the 1 t...

330 rows × 2 columns

同时,在进行情感分析时,应增加停用词AAPL.

数据存储:存储为补充数据1925102007/AAPL论坛.csv

# 数据储存
forum.to_csv('补充数据1925102007/AAPL论坛.csv', index=False)

3.3.3 全标题.xlsx

标题字段1_链接_链接ABOUTTIMEAUTHORCOMMENTSUnnamed: 6
0Micron Technology: Insanely Cheap Stock Given ...https://seekingalpha.com/article/4230920-micro...MUDec. 31, 2018, 7:57 PMRuerd Heeg75 CommentsNaN
1Molson Coors Seems Attractive At These Valuationshttps://seekingalpha.com/article/4230922-molso...TAPDec. 31, 2018, 7:44 PMSanjit Deepalam16 CommentsNaN
2Gerdau: The Brazilian Play On U.S. Steelhttps://seekingalpha.com/article/4230917-gerda...GGBDec. 31, 2018, 7:10 PMShannon Bruce1 CommentNaN
........................
17925Big Changes For Centurylink, AT&T And Verizon ...https://seekingalpha.com/article/4134687-big-c...CTL, T, VZJan. 1, 2018, 5:38 AMEconDad32 CommentsNaN
17926UPS: If The Founders Were Alive Todayhttps://seekingalpha.com/article/4134684-ups-f...UPSJan. 1, 2018, 5:11 AMRoger Gaebel15 CommentsNaN
17927U.S. Silica - Buying The Dip Of This Booming C...https://seekingalpha.com/article/4134664-u-s-s...SLCAJan. 1, 2018, 12:20 AMThe Value Investor27 CommentsNaN

17928 rows × 7 columns

索引过滤:提取所有ABOUT为AAPL的标题数据行。

降维处理:字段1_链接_链接、ABOUT、AUTHOR、COMMENTS、Unnamed: 6列删除。

索引重构:重命名索引,标题-title、ABOUT-abbr、TIME-date。

时间序列:将date转化为时间序列索引,并按此索引升序排列。

数据存储:存储为补充数据1925102007/AAPL全标题.csv

allTitles = pd.read_excel('全标题.xlsx')
# 索引过滤
allTitles = allTitles[allTitles['ABOUT']==CORPORATIONABBR]
# 降维
allTitles.drop(['字段1_链接_链接','ABOUT','AUTHOR','COMMENTS','Unnamed: 6'], axis=1, inplace=True)
# 索引重构
AAPL_newIndex_allTitles = {'标题': 'title', 'TIME': 'date'}
allTitles.rename(columns=AAPL_newIndex_allTitles, inplace=True)
# 时间序列处理
# 因时间日期格式非统一,故选用dateutil包对parser.parse方法识别多变时间格式
allTitles['date'] = allTitles['date'].apply(lambda dt: dt_parse(dt))
# 设date列为索引
allTitles.set_index('date', inplace=True)
# 按date升序排列
allTitles.sort_values(by='date', inplace=True, ascending=True)
# 数据储存
allTitles.to_csv('补充数据1925102007/AAPL全标题.csv')
allTitles
title
date
2018-01-04 10:12:00Apple Ia Above A 'Golden Cross' And Has A Posi...
2018-01-08 10:59:00Apple Cash: What Would Warren Buffett Say?
2018-01-16 06:34:00Apple's iPhone Battery Replacement Could Consu...
......
2018-12-31 08:52:00Will Apple Beat Its Guidance?
2018-12-31 17:12:00How Much Stock Could Apple Have Repurchased In...
2018-12-31 17:36:00Will Apple Get Its Mojo Back?

204 rows × 1 columns

3.3.4 摘要.xlsx

标题字段2字段5字段1
0HealthEquity: Strong Growth May Be Slowing Hea...Apr. 1, 2019 10:46 PM ET| About: HealthEquity, Inc. (HQY)SummaryHealthEquity’s revenue and earnings hav...
1Valero May Rally Up To 40% Within The Next 12 ...Apr. 1, 2019 10:38 PM ET| About: Valero Energy Corporation (VLO)SummaryValero is ideally positioned to benefit...
2Apple Makes A China MoveApr. 1, 2019 7:21 PM ET| About: Apple Inc. (AAPL)SummaryCompany cuts prices on many key product...
...............
10128Rubicon Technology: A Promising Net-Net Cash-B...Jul. 24, 2018 2:16 PM ET| About: Rubicon Technology, Inc. (RBCN)SummaryRubicon is trading well below likely li...
10129Stamps.com: A Cash MachineJul. 24, 2018 1:57 PM ET| About: Stamps.com Inc. (STMP)SummaryThe Momentum Growth Quotient for the co...
10130Can Heineken Turn The 'Mallya Drama' In Its Ow...Jul. 24, 2018 1:24 PM ET| About: Heineken N.V. (HEINY), Includes: BUD,...SummaryMallya, United Breweries' chairman, can...

10131 rows × 4 columns

经检查,摘要.xlsx无缺失值,我们只需要标题和字段1(摘要的全文字内容),其余数据列删去。将索引映射为:标题-title、字段1-abstract.

abstracts = pd.read_excel('摘要.xlsx')
abstracts.drop(['字段2', '字段5'], axis=1, inplace=True)
newIndex_abstracts = {'标题': 'title', '字段1': 'abstract'}
abstracts.rename(columns=newIndex_abstracts, inplace=True)

求交集:和AAPL全标题.csv中title相对应的数据行是针对AAPL股票公司文章的摘要,只需要对AAPL文章的摘要即可。

abstracts = abstracts.merge(allTitles, on=['title'], how='inner')

保存:存储为补充数据1925102007/AAPL摘要.csv

abstracts.to_csv('补充数据1925102007/AAPL摘要.csv', index=False)
abstracts
titleabstract
0Will Apple Get Its Mojo Back?SummaryApple has been resting on a reputation ...
1How Much Stock Could Apple Have Repurchased In...SummaryApple's stock plummeted from $227.26 to...
2Will Apple Beat Its Guidance?SummaryApple has sold fewer iPhones, which gen...
.........
83Apple: Still The Ultimate Value Growth Stock T...SummaryApple reported superb earnings on Tuesd...
84Apple In 2023SummaryWhere can the iPhone go from here?The A...
85Apple's Real Value TodaySummaryApple has reached new highs this week.W...

86 rows × 2 columns

3.3.5 回帖

pd.read_excel('回帖/SA_Comment_Page131-153.xlsx')
字段标题1
0you should all switch to instagramNaN
1Long Facebook and Instagram. They will recover...NaN
2Personally, I think people will be buying FB a...NaN
.........
19968Thank you for the article.If you really think ...Qiwi: The Current Sell-Off Was Too Emotional
19969Isn't WRK much better investment than PKG? ThanksNaN
19970GuruFocus is also showing a Priotroski score o...Packaging Corporation Of America: Target Retur...

19971 rows × 2 columns

pd.read_csv('回帖/SA_Comment_Page181-255(1).csv')
字段1标题
0I bought at $95 and holding strong. Glad I did...NaN
1The price rally you are referring to is not be...Michael Kors: Potential For Further Upside Ahead
2only a concern if you own it....NaN
.........
19997What can Enron Musk do legally to boost balan...NaN
19998The last two weeks feels like a short squeeze....NaN
19999" Tesla is no longer a growth or value proposi...NaN

20000 rows × 2 columns

索引重命名:字段1(回帖内容)-content、标题-title.(注意.csv和.xlsx不同)

缺失值处理:对于回帖中标题1(各文章标题)的定义空标题的,用最靠近的有内容的下方标题,故采取用下一个非缺失值填充前缺失值的方法df.fillna(method='bfill')

数据文件读取:使用os.listdir()返回指定文件夹下包含的文件名列表,以.xlsx或.csv结尾的文件均为数据文件,读入后进行上述缺失值处理和索引重命名。

回帖过滤:遍历所有数据文件,找出所有title在AAPL全标题.csv中的回帖行数据,检查是否有缺失,存至补充数据1925102007/AAPL回帖.csv

# 数据文件读取
repliesFiles = listdir('回帖')
allAALPReplies = []
newIndex_replies_csv = {'字段1': 'content', '标题': 'title'}
newIndex_replies_xlsx = {'字段': 'content', '标题1': 'title'}
# 遍历回帖目录下所有回帖数据找出和AAPL相关的回帖
for file in repliesFiles:path = '回帖/'+fileif file.endswith('.csv'):replies = pd.read_csv(path)newIndex_replies = newIndex_replies_csvelif file.endswith('.xlsx'):replies = pd.read_excel(path)newIndex_replies = newIndex_replies_xlsxelse:print('Wrong file format,', file)break# 索引重命名replies.rename(columns=newIndex_replies, inplace=True)# 缺失值填充replies.fillna(method='bfill', inplace=True)# 回帖过滤allAALPReplies.extend(replies.merge(allTitles, on=['title'], how='inner').values)
# 所有和AAPL文章标题所对应的回帖
allAALPReplies = pd.DataFrame(allAALPReplies, columns=['content', 'title'])
# 保存
allAALPReplies.to_csv('补充数据1925102007/AAPL回帖.csv', index=False)
# 展示
allAALPReplies
contenttitle
0Understood. But let me ask you. 64GB of pics i...iPhone XR And XS May Be Apple's Most Profitabl...
1Just upgraded from 6 to XS, 256G. Love it. I'l...iPhone XR And XS May Be Apple's Most Profitabl...
2Yup, AAPL will grow profits 20% per year despi...iPhone XR And XS May Be Apple's Most Profitabl...
.........
4503With all due respect, never have paid for and ...Gain Exposure To Apple Through Berkshire Hathaway
4504This one's easy - own both!Gain Exposure To Apple Through Berkshire Hathaway
4505No Thanks! I like my divys,and splits too much...Gain Exposure To Apple Through Berkshire Hathaway

4506 rows × 2 columns

3.4 情感分析

使用第三方NLP库:NLTK (Natural Language Toolkit)

NLTK is a leading platform for building Python programs to work with human language data. It provides easy-to-use interfaces such as WordNet, along with a suite of text processing libraries for classification, tokenization, stemming, tagging, parsing, and semantic reasoning, wrappers for industrial-strength NLP libraries.

安装完nltk库以后,需要使用nltk.download()命令下载相应语料库。因为速度太慢,我选择直接装nltk_data数据包,核心数据包放在补充文件夹内。

为提高情感分析效率和精度,停用词还需增加['!', ',' ,'.' ,'?' ,'-s' ,'-ly' ,'</s> ', 's', 'AAPL', 'apple', '$', '%']. 使用stopwords.add()添加停用词。

[Source3] http://www.nltk.org

金融情感词库:LM (LoughranMcDonald) sentiment word lists 2018

[Loughran-McDonald Sentiment Word Lists](https://sraf.nd.edu/textual-analysis/resources/#LM Sentiment Word Lists) is an Excel file containing each of the LM sentiment words by category (Negative, Positive, Uncertainty, Litigious, Strong Modal, Weak Modal, Constraining).

词库路径:/补充数据1925102007/LoughranMcDonald_SentimentWordLists_2018.xlsx

[Source4] https://sraf.nd.edu/textual-analysis/resources

3.4.1 情感分析思路

  • 分词处理:使用NLTK对文本(这里指评论数据)进行分词处理(tokenize)
  • 停用词处理:去除停用词(stopwords)
  • 结构化:利用LM金融情感词库中的Positive和Negative表单词库,计算posneg值作为非结构化文本数据的结构化特征。(即以评论中posWords和negWords的占比作为文本数据的特征
  • 数据聚合:对上述数据进行聚合操作,并按工作日(股票的交易时间是Business Day)为单位进行重采样

pos=NumofPosWrodsTotalWordspos = \frac{Num of PosWrods}{Total Words} pos=TotalWordsNumofPosWrods

neg=NumofNegWrodsTotalWordsneg = \frac{Num of NegWrods}{Total Words} neg=TotalWordsNumofNegWrods

3.4.2 词库导入和添加停用词

# 词库导入
wordListsPath = '补充数据1925102007/LoughranMcDonald_SentimentWordLists_2018.xlsx'
posWords = pd.read_excel(wordListsPath, header=None, sheet_name='Positive').iloc[:,0].values
negWords = pd.read_excel(wordListsPath, header=None, sheet_name='Negative').iloc[:,0].values# 添加停用词
extraStopwords = ['!', ',' ,'.' ,'?' ,'-s' ,'-ly' ,'</s> ', 's', 'AAPL', 'apple', '$', '%']
stopWs = stopwords.words('english') + extraStopwords

3.4.3 函数定义

def structComment(sentence, posW, negW, stopW):"""结构化句子:param sentence: 待结构化的评论:param posW: 正词性:param negW: 负词性:param stopW: 停用词:return: 去除停用词后的评论中posWords和negWords的占比(pos, neg)"""# 分词tokenizer = nltk.word_tokenize(sentence)# 停用词过滤tokenizer = [w.upper() for w in tokenizer if w.lower() not in stopW]# 正词提取posWs = [w for w in tokenizer if w in posW]# 负词提取negWs = [w for w in tokenizer if w in negW]# tokenizer长度len_token = len(tokenizer)# 句子长度为0,即分母为0时if len_token<=0:return 0, 0else:return len(posWs)/len_token, len(negWs)/len_token
def NLProcessing(fileName, colName):"""自然语言处理方法:将传入的fileName(.csv)对应的数据中的colName列文本数据结构化,并保存:param fileName: 文件名,在文件夹 补充数据1925102007/ 下查找对应文件:param colName: 需要结构化的文本数据列:return: 新增pos和neg列的DataFrame"""pathNLP = '补充数据1925102007/'+fileName+'.csv'data = pd.read_csv(pathNLP)# pos和neg结构化数据列构造posAndneg = [ structComment(st, posWords, negWords, stopWs) for st in data[colName].values]# 构造posAndneg的DataFrameposAndneg = pd.DataFrame(posAndneg, columns=['pos', 'neg'])# 轴向连接data = pd.concat([data, posAndneg], axis=1)# 删除文本数据列data.drop([colName], axis=1, inplace=True)# 保存结构化的数据data.to_csv(pathNLP)return data

3.4.4 情感分析处理

# AAPL论坛.csv
forum = NLProcessing('AAPL论坛', 'remark')
# AAPL摘要.csv
abstracts = NLProcessing('AAPL摘要', 'abstract')
# AAPL回帖.csv
allAALPReplies = NLProcessing('AAPL回帖', 'content')

3.4.5 情感特征数据聚合

上述操作得到带有title列的结构化数据(AAPL回帖.csv和AAPL摘要.csv)后,先将回帖和摘要用concat函数沿纵轴连接,再以title为索引,与AAPL全标题.csv(allTitles)进行外联合并(Outer Merge),删除无用的title列。forum结构化数据和上一步所得数据进行concat轴相连接(沿纵轴)。最后,以时间天为单位进行重采样,得出每日的pos和neg特征的平均值。

# 轴相连接abstracts和allAALPReplies
allEssaysComment = pd.concat([abstracts,allAALPReplies], ignore_index=True)
# 联表
allEssaysComment = allTitles.merge(allEssaysComment, how='outer', on='title')
# 删除缺失行
allEssaysComment.dropna(inplace=True)
# 删除title列
allEssaysComment.drop('title', axis=1, inplace=True)
# 和forum情感数据进行轴向连接
allEssaysComment = pd.concat([allEssaysComment,forum], ignore_index=True)
# 删除pos和neg均为0的无用数据行
allEssaysComment = allEssaysComment[(allEssaysComment['pos']+allEssaysComment['neg'])>0]# 设date为时间序列索引
allEssaysComment['date'] = pd.to_datetime(allEssaysComment['date'])
allEssaysComment.set_index('date', inplace=True)
# 按"工作日"重采样,求pos和neg的均值,不存在的天以0填充
allEssaysComment = allEssaysComment.resample('B').mean()
allEssaysComment.fillna(0, inplace=True)
# 储存
allEssaysComment.to_csv('补充数据1925102007/allPosAndNeg.csv')
# 展示
allEssaysComment
posneg
date
2018-01-050.0416670.043478
2018-01-080.0000000.000000
2018-01-090.0000000.090909
.........
2018-12-240.0000000.000000
2018-12-250.0000000.000000
2018-12-260.0909090.090909

254 rows × 2 columns

3.5 * 融入情感数据的股票指标相关性分析

方法:希望借助seaborn的pairplot函数绘制AAPL股票价格.csv(sharePricesAAPL)的各项指标数据两两关联的散点图(对角线为变量的直方图),从而探究不同指标间的关系。

目的:分析股票各指标间的关系。以及是否找出线性相关程度高的指标,删除之,以减少LSTM的训练时间成本。

pairplot函数文档:http://seaborn.pydata.org/generated/seaborn.pairplot.html

3.5.1 数据联合

将2.2所得时间序列情感分析数据(allPosAndNeg.csv)和AAPL股票价格.csv(sharePricesAAPL)以date为索引合并。

联合时可以发现,评论数据的时间跨度足以覆盖AAPL股票价格数据,所以不用担心缺失值的问题。 [Jump to relative contents]

# 文件读取
sharePricesAAPL = pd.read_csv('补充数据1925102007/AAPL股票价格.csv')
allPosAndNeg = pd.read_csv('补充数据1925102007/allPosAndNeg.csv')
# 合并
sharePricesAAPLwithEmotion = sharePricesAAPL.merge(allPosAndNeg, how='inner', on='date')
# 序列化时间索引date
sharePricesAAPLwithEmotion['date'] = pd.DatetimeIndex(sharePricesAAPLwithEmotion['date'])
sharePricesAAPLwithEmotion.set_index('date', inplace=True)
# reindex
AAPL_newColOrder_emotionPrices = ['open', 'high', 'low', 'vol', 'pos', 'neg', 'close']
sharePricesAAPLwithEmotion = sharePricesAAPLwithEmotion.reindex(columns=AAPL_newColOrder_emotionPrices)
# 保存
sharePricesAAPLwithEmotion.to_csv('补充数据1925102007/AAPL股票价格融合情感.csv')

3.5.2 pairplot绘图

留下必要的OHLC技术指标,对剩余的vol、pos、neg进行相关性分析绘图

实验时,我也绘制了OHLC技术指标的轴线网格图,可以发现,其两两间具有较高的线性相关性。

# Parameters:
# data: pandas.DataFrame [Tidy (long-form) dataframe where each column is a variable and each row is an observation.]
# diag_kind: {‘auto’, ‘hist’, ‘kde’, None} [Kind of plot for the diagonal subplots.]
# kind: {‘scatter’, ‘kde’, ‘hist’, ‘reg’} [Kind of plot to make.]
fig1 = pairplot(sharePricesAAPLwithEmotion[['vol', 'pos', 'neg']], diag_kind='hist', kind='reg')
# save the fig1 to 补充数据1925102007/
fig1.savefig('补充数据1925102007/fig1_a_Grid_of_Axes.png')

fig1_a_Grid_of_Axes.png

3.5.3 股票指标相关性分析

观察所得Fig1: a Grid of Axes不难发现,指标vol、pos、neg之间线性相关性较弱,所以均保留,作为LSTM预测指标。

3.6 LSTM预测融合情感特征的股票数据

依赖的库:Keras、Sklearn、Tensorflow [4]

预测目标close(收盘价)

引用函数series_to_supervised(data, n_in=1, n_out=1, dropnan=True)

来源:Time Series Forecasting With Python

用途:Frame a time series as a supervised learning dataset. 将输入的单变量或多变量时间序列转化为有监督学习数据集。

参数(Arguments):

data: Sequence of observations as a 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.

# 因为LSTM已经具有记忆功能了,所以我的n_in和n_out参数直接使用默认的1即可(也就是构造[t-1]现态列和[t]次态列)。

返回值(Returns):

Pandas DataFrame of series framed for supervised learning.

3.6.1 时间序列转有监督函数定义

def series_to_supervised(data, n_in=1):# 默认参数n_out=1dropnan=True# 对该函数进行微调,注意data为以close列(需要预测的列)结尾的DataFrame时间序列股票数据n_vars = 1 if type(data) is list else data.shape[1]df = pd.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 = pd.concat(cols, axis=1)agg.columns = names# 删除无关的次态[t]列,只留下需要预测的close[t]列和上一时刻状态特征[t-1]列agg.drop(agg.columns[[x for x in range(data.shape[1], 2*data.shape[1]-1)]], axis=1, inplace=True)# drop rows with NaN valuesif dropnan:agg.dropna(inplace=True)return agg

3.6.2 融合情感的股票数据归一化

# 读取数据
sharePricesAAPLwithEmotion = pd.read_csv('补充数据1925102007/AAPL股票价格融合情感.csv', parse_dates=['date'], index_col='date').values
# 生成归一化容器
# feature_range参数沿用默认(0,1)
scaler = MinMaxScaler()
# 训练模型
scaler = scaler.fit(sharePricesAAPLwithEmotion)
# 归一化
sharePricesAAPLwithEmotion = scaler.fit_transform(sharePricesAAPLwithEmotion)
# 部分结果展示
sharePricesAAPLwithEmotion[:5,:]
array([[0.4316836 , 0.43640137, 0.44272148, 0.06118638, 0.        ,0.        , 0.47336914],[0.47972885, 0.44433594, 0.44416384, 0.01698249, 0.        ,0.        , 0.4351243 ],[0.44911044, 0.42553711, 0.45305926, 0.04901593, 0.        ,0.        , 0.45248692],[0.4510469 , 0.45024426, 0.46411828, 0.05954544, 0.        ,0.        , 0.4826372 ],[0.50042364, 0.47766101, 0.51340305, 0.08659896, 0.        ,0.        , 0.51325663]])

3.6.3 时间序列构建有监督数据集

# 使用series_to_supervised函数构建有监督数据集
sharePricesAAPLwithEmotion = series_to_supervised(sharePricesAAPLwithEmotion)
sharePricesAAPLwithEmotion
var1(t-1)var2(t-1)var3(t-1)var4(t-1)var5(t-1)var6(t-1)var7(t-1)var7(t)
10.4316840.4364010.4427210.0611860.00.00.4733690.435124
20.4797290.4443360.4441640.0169820.00.00.4351240.452487
30.4491100.4255370.4530590.0490160.00.00.4524870.482637
...........................
1200.1482510.1289060.1047000.6242520.00.00.1173160.045753
1210.1054100.0806880.0365430.9940590.00.00.0457530.000000
1220.0000000.0000000.0000000.2956430.00.00.0000000.121305

122 rows × 8 columns

3.6.4 训练集验证集划分

# 必须规定ndarray的dtype为float32(默认float64),否则后续输入LSTM模型报错
sharePricesAAPLwithEmotion = sharePricesAAPLwithEmotion.values.astype(np.float32)
# 训练集:验证集=7:3
X_train, X_test, y_train, y_test = train_test_split(sharePricesAAPLwithEmotion[:,:-1], sharePricesAAPLwithEmotion[:,-1], test_size=0.3, shuffle=False)

3.6.5 基于Keras的LSTM模型搭建

参考文档:

Keras core: Dense and Dropout

Keras Activation relu

Keras Losses mean_squared_error

Keras Optimizer adam

Keras LSTM Layers

Keras Sequential Model

3.6.5 (一)、重塑LSTM的输入X

LSTM的输入格式为**shape = [samples,timesteps,features]**:

samples:样本数量

timesteps:时间步长

features (input_dim):每一个时间步上的维度

重塑X_trainX_test

# reshape input to be 3D [samples, timesteps, features]
X_train = X_train.reshape((X_train.shape[0], 1, X_train.shape[1]))
X_test = X_test.reshape((X_test.shape[0], 1, X_test.shape[1]))
3.6.5 (二)、搭建LSTM模型并绘制损失图
  • 建立Sequential模型
  • 添加LSTM层(64个隐藏层神经元,1个输出层神经元,指定多层LSTM模型第一层的input_shape参数)回归模型
  • 设定Dropout在每次训练时的丢弃比(rate)为0.4
  • 设定Dense全连接层的输出空间维度(units)为1,激活函数(activation)为relu(整流线性单元)
  • 设定Sequential的损失函数(loss)为MSE(Mean-Square Error)均方误差,优化器(optimizer)为adam
  • 模型训练设置epochs=50; batch_size=30
def LSTMModelGenerate(Xtrain, Xtest, ytrain, ytest):"""LSTM模型搭建函数:param Xtrain: 训练集属性:param Xtest: 测试集属性:param ytrain: 训练集标签:param ytest: 测试集标签:return: history,model(模型编译记录和模型)"""# 搭建LSTM模型_model = Sequential()_model.add(LSTM(64, input_shape=(Xtrain.shape[1], Xtrain.shape[2])))_model.add(Dropout(0.4))_model.add(Dense(1, activation='relu'))# 模型编译_model.compile(loss='mse', optimizer='adam')# 模型训练_history = _model.fit(Xtrain, ytrain, epochs=50, batch_size=30, validation_data=(Xtest, ytest), shuffle=False, verbose=0)return _history,_modelhistory, model = LSTMModelGenerate(X_train, X_test, y_train, y_test)
  • 损失图绘制
def drawLossGraph(_history, title, num):"""损失图绘制,寻找最优epochs:param _history: 训练历史:param title: 图表标题:param num: 图表编号:return: 无"""plt.plot(_history.history['loss'], color='g', label='train')plt.plot(_history.history['val_loss'], color='r', label='test')plt.title('Fig'+num+'. '+title)plt.xlabel('epochs')plt.ylabel('loss')plt.legend()# 保存于 补充数据1925102007/savingPath = '补充数据1925102007/fig'+num+'_'+title.replace(' ', '_')+'.png'plt.savefig(savingPath, dpi=400, bbox_inches='tight')# 展示plt.show()drawLossGraph(history, title='LSTM Loss Graph for Stock Prices with Emotions', num='2')

fig2_LSTM_Loss_Graph_for_Stock_Prices_with_Emotions

  • 损失图分析

    由Fig2含情感的股票价格LSTM损失图可以看出,MSE随迭代次数增加而减小,在大约30次迭代后,其趋于稳定(收敛)。

3.6.6 预测结果并反归一化

# 因为只要对结果列进行反归一化操作,
# 故不用inverse_transform函数,
# 这里自定义对某列的反归一化函数 inverse_transform_col
def inverse_transform_col(_scaler, y, n_col):"""对某个列进行反归一化处理的函数:param _scaler: sklearn归一化模型:param y: 需要反归一化的数据列:param n_col: y在归一化时所属的列编号:return: y的反归一化结果"""y = y.copy()y -= _scaler.min_[n_col]y /= _scaler.scale_[n_col]return y
# 模型预测结果绘图函数
def predictGraph(yTrain, yPredict, yTest, timelabels, title, num):"""预测结果图像绘制函数:param yTrain: 训练集结果:param yPredict: 验证集的预测结果:param yTest: 验证集的真实结果:param timelabels: x轴刻度标签:param title: 图表标题:param num: 图标编号:return: 无"""len_yTrain = yTrain.shape[0]len_y = len_yTrain+yPredict.shape[0]# 真实曲线绘制plt.plot(np.concatenate([yTrain,yTest]), color='r', label='sample')# 预测曲线绘制plt.plot([x for x in range(len_yTrain,len_y)],yPredict, color='g', label='predict')# 标题和轴标签plt.title('Fig'+num+'. '+title)plt.xlabel('date')plt.ylabel('close')plt.legend()# 刻度和刻度标签xticks = [0,len_yTrain,len_y-1]xtick_labels = [timelabels[x] for x in xticks]plt.xticks(ticks=xticks, labels=xtick_labels, rotation=30)# 保存于 补充数据1925102007/savingPath = '补充数据1925102007/fig'+num+'_'+title.replace(' ', '_')+'.png'plt.savefig(savingPath, dpi=400, bbox_inches='tight')# 展示plt.show()
# 由X_test前日股票指标预测当天股票close值
# 注:predict生成的array需降维成 shape=(n_samples, )
y_predict = model.predict(X_test)[:,0]# 反归一化
# 重新读取 AAPL股票价格融合情感.csv
sharePricesAAPLwithEmotion = pd.read_csv('补充数据1925102007/AAPL股票价格融合情感.csv')
col_n = sharePricesAAPLwithEmotion.shape[1]-2
# 预测结果反归一化
inv_yPredict = inverse_transform_col(scaler, y_predict, col_n)
# 真实结果反归一化
inv_yTest = inverse_transform_col(scaler, y_test, col_n)
# 训练集结果反归一化(以绘制完整图像)
inv_yTrain = inverse_transform_col(scaler, y_train, col_n)
# 绘图
predictGraph(inv_yTrain, inv_yPredict, inv_yTest, timelabels=sharePricesAAPLwithEmotion['date'].values, title='Prediction Graph of Stock Prices with Emotions', num='3')

fig3_Prediction_Graph_of_Stock_Prices_with_Emotions

3.6.7 模型评估

误差评价方法MSE

# sklearn.metrics.mean_squared_error(y_true, y_pred)
mse = mean_squared_error(inv_yTest, inv_yPredict)
print('带有情感特征的股票数据预测结果的均方误差(MSE)为 ', mse)
带有情感特征的股票数据预测结果的均方误差(MSE)为  160.42007

分析

观察Fig3可知,用含有情感特征的股票数据训练的LSTM模型预测结果(绿色曲线)和真实结果(红色曲线的后段)总体变化趋势一致,即真实值下降或上升时,预测值跟着下降或上升。在模型预测的开始阶段,拟合效果较好,但随着时间推移,预测值和真实值的结果差距愈发增大。

3.7 对比实验:预测纯技术指标的股票数据

作为对比,导入补充数据1925102007/AAPL股票价格.csv,具体操作和上述一致,对不含情感特征的纯技术指标股票数据进行预测分析。

(操作基本一致,故不作详细注释)

3.7.1 对比实验流程(通用函数构造)

def formatData(sharePricesData):"""模式化样本数据的函数:param sharePricesData: 样本数据的DataFrame:return: X_train, X_test, y_train, y_test, scaler"""# 归一化_scaler = MinMaxScaler()_scaler = _scaler.fit(sharePricesData)sharePricesData = _scaler.fit_transform(sharePricesData)# 构建有监督数据集sharePricesData = series_to_supervised(sharePricesData)# dtype为float32sharePricesData = sharePricesData.values.astype(np.float32)# 训练集和验证集的划分_X_train, _X_test, _y_train, _y_test = train_test_split(sharePricesData[:,:-1], sharePricesData[:,-1], test_size=0.3, shuffle=False)# reshape input_X_train = _X_train.reshape((_X_train.shape[0], 1, _X_train.shape[1]))_X_test = _X_test.reshape((_X_test.shape[0], 1, _X_test.shape[1]))return _X_train, _X_test, _y_train, _y_test, _scaler
def invTransformMulti(_scaler, _y_predict, _y_test, _y_train, _col_n):# 批量反归一化_inv_yPredict = inverse_transform_col(_scaler, _y_predict, _col_n)_inv_yTest = inverse_transform_col(_scaler, _y_test, _col_n)_inv_yTrain = inverse_transform_col(_scaler, _y_train, _col_n)return _inv_yPredict, _inv_yTest, _inv_yTrain
# 读取数据
sharePricesAAPL = pd.read_csv('补充数据1925102007/AAPL股票价格.csv', parse_dates=['date'], index_col='date').values
# 标准化数据输入
X_train, X_test, y_train, y_test, scaler = formatData(sharePricesAAPL)
# 建模
history, model = LSTMModelGenerate(X_train, X_test, y_train, y_test)
# 损失函数绘图
drawLossGraph(history, title='LSTM Loss Graph for Stock Prices without Emotions', num='4')

fig4_LSTM_Loss_Graph_for_Stock_Prices_without_Emotions

# 预测
y_predict = model.predict(X_test)[:,0]
# 反归一化
sharePricesAAPL = pd.read_csv('补充数据1925102007/AAPL股票价格.csv')
col_n = sharePricesAAPL.shape[1]-2
inv_yPredict, inv_yTest, inv_yTrain = invTransformMulti(scaler, y_predict, y_test, y_train, col_n)
# 绘图
predictGraph(inv_yTrain, inv_yPredict, inv_yTest, timelabels=sharePricesAAPL['date'].values, title='Prediction Graph of Stock Prices without Emotions', num='5')

fig5_Prediction_Graph_of_Stock_Prices_without_Emotions

# 均方误差
mse = mean_squared_error(inv_yTest, inv_yPredict)
print('无情感特征的纯技术指标股票数据预测结果的均方误差(MSE)为 ', mse)
无情感特征的纯技术指标股票数据预测结果的均方误差(MSE)为  142.50227

3.7.2 对比实验结果分析

对比Fig3和Fig5(含情感和不含情感)

  • 均方误差:通过去除情感信息,用LSTM模型得出的纯技术指标的股票close预测结果单就误差来看要优于含情感特征的股票数据预测结果,纯技术指标预测的精度更高,总体上更接近于真值

    MSE (含情感特征) = 160.42007

    MSE (纯技术指标) = 142.50227

  • 曲线特征:显然,含有情感数据信息的预测结果曲线较无情感的预测曲线更灵敏。Fig3(含情感特征)的预测曲线随真值曲线的升降而涨跌,真值曲线的变化(突变)趋势较为完整地体现在预测曲线中,而Fig5(纯技术指标)的预测曲线随真值曲线的波动并不明显。

    Fig3. Prediction Graph of Stock Prices with Emotions

    Fig5. Prediction Graph of Stock Prices without Emotions

3.7.3 对比实验结论

在现有数据下,从总体上来看,纯技术指标的股票数据预测精度更高,但从局部来看,融入了情感特征的股票数据则更加灵敏。实验结果基本和预期一致。

结果表明,股票的价格涨跌并非无规律的随机游走,而是和股民的情感息息相关。在对股票数据的预测中,融入互联网论坛上股民大众的情感数据信息,能够更好地判断出未来一段时间内股票的涨跌情况,从而帮助判断股票的最佳购入点和卖出点、分析股票投资风险。情感数据信息有助于在量化投资中辅助股民和数据分析师做出最优决策。

3.8 补充对比实验:补充AAPL股票技术指标样本量进行预测

数据联合 步骤时,发现所给补充数据1925102007/AAPL股票价格.csv数据并不能覆盖所有的评论数据(allPosAndNeg.csv)。

此外,该数据样本量较少,按训练集和验证集7:3比例划分后,导致训练集样本数只有88条。

因此决定使用英为财情股票行情网站所提供的2018年全年AAPL股票工作日纯技术指标数据,使用上述方法对收盘价(close)进行预测,和2.5 对比实验进行对比。

事实上,

AAPL股票价格.csv覆盖时间为2018-07-02至2018-12-31,

allPosAndNeg.csv覆盖时间为2018-01-05至2018-12-31.

3.8.1 数据获取

从英为财情AAPL个股页面下载近五年AAPL纯技术指标股票数据,储存于补充数据1925102007\AAPLHistoricalData_5years.csv.

3.8.2 数据处理

# 读取数据
allYearAAPL = pd.read_csv('补充数据1925102007/AAPLHistoricalData_5years.csv', parse_dates=['Date'], index_col='Date')
# 时间序列索引切片
allYearAAPL = allYearAAPL['2018-12-31':'2018-01-01']
# 排序
allYearAAPL.sort_index(inplace=True)
# 展示
allYearAAPL
Close/LastVolumeOpenHighLow
Date
2018-01-02$43.065101602160$42.54$43.075$42.315
2018-01-03$43.0575117844160$43.1325$43.6375$42.99
2018-01-04$43.257589370600$43.135$43.3675$43.02
..................
2018-12-27$39.0375206435400$38.96$39.1925$37.5175
2018-12-28$39.0575166962400$39.375$39.63$38.6375
2018-12-31$39.435137997560$39.6325$39.84$39.12

251 rows × 5 columns

# pandas字符串切割、Series类型修改(去除$)
allYearAAPL[['Close/Last', 'Open', 'High', 'Low']] = allYearAAPL[['Close/Last', 'Open', 'High', 'Low']].apply(lambda x: (x.str[1:]).astype(np.float32))
# reindex
allAAPL_newColOrder = ['Open', 'High', 'Low', 'Volume', 'Close/Last']
allYearAAPL = allYearAAPL.reindex(columns=allAAPL_newColOrder)
# 保存为AAPL2018allYearData.csv
allYearAAPL.to_csv('补充数据1925102007/AAPL2018allYearData.csv')
# 展示
allYearAAPL
OpenHighLowVolumeClose/Last
Date
2018-01-0242.54000143.07500142.31499910160216043.064999
2018-01-0343.13250043.63750142.99000211784416043.057499
2018-01-0443.13499843.36750043.0200008937060043.257500
..................
2018-12-2738.95999939.19250137.51750220643540039.037498
2018-12-2839.37500039.63000138.63750116696240039.057499
2018-12-3139.63250039.84000039.11999913799756039.435001

251 rows × 5 columns

3.8.3 预测分析

# 标准化数据输入
X_train, X_test, y_train, y_test, scaler = formatData(allYearAAPL)
# 建模
history, model = LSTMModelGenerate(X_train, X_test, y_train, y_test)
# 损失函数绘图
drawLossGraph(history, title='LSTM Loss Graph for 2018 All Year AAPL Stock Prices', num='6')

fig6_LSTM_Loss_Graph_for_2018_All_Year_AAPL_Stock_Prices

# 预测
y_predict = model.predict(X_test)[:,0]
# 反归一化
allYearAAPL = pd.read_csv('补充数据1925102007/AAPL2018allYearData.csv')
col_n = allYearAAPL.shape[1]-2
inv_yPredict, inv_yTest, inv_yTrain = invTransformMulti(scaler, y_predict, y_test, y_train, col_n)
# 绘图
predictGraph(inv_yTrain, inv_yPredict, inv_yTest, timelabels=allYearAAPL['Date'].values, title='Prediction Graph of 2018 All Year AAPL Stock Prices', num='7')

fig7_Prediction_Graph_of_2018_All_Year_AAPL_Stock_Prices

# 均方误差
mse = mean_squared_error(inv_yTest, inv_yPredict)
print('2018全年纯技术指标AAPL股票数据预测结果的均方误差(MSE)为 ', mse)

3.8.4 结果分析

Fig7. Prediction Graph of 2018 All Year AAPL Stock Prices2018全年纯技术指标AAPL股票数据预测结果的均方误差2.5 不含情感特征的AAPL股票数据预测的对比实验比较得知,在增加股票的时间序列数据后,即由原本2018-07-02~2018-12-31扩充至2018-01-01~2018-12-31纯技术指标预测的精度大幅提升,LSTM模型的拟合效果极佳

由此推断Fig3.Fig5.(即未增添数据前的AAPL含情感特征预测图和纯技术指标预测图)的预测结果精度低,且随时间推移,预测结果严重偏离真值的原因在于样本数目不足,导致LSTM模型训练不到位。接下来,将添加补充数据后的2018全年AAPL股票数据融合情感特征,进行含情感特征的股票数据预测,以验证这一推断。

3.9 2018全年含情感特征的股票数据预测实验

3.9.1 情感特征数据聚合

# 文件读取
allYearAAPL_withEmos = pd.read_csv('补充数据1925102007/AAPL2018allYearData.csv')
allPosAndNeg = pd.read_csv('补充数据1925102007/allPosAndNeg.csv')
# 合并
allYearAAPL_withEmos = allYearAAPL_withEmos.merge(allPosAndNeg, how='inner', left_on='Date', right_on='date').drop('date', axis=1)
# 序列化时间索引date
allYearAAPL_withEmos['Date'] = pd.DatetimeIndex(allYearAAPL_withEmos['Date'])
allYearAAPL_withEmos.set_index('Date', inplace=True)
# reindex
allYearAAPLwithEmos_newColOrder = ['Open','High','Low','Volume','pos','neg','Close/Last']
allYearAAPL_withEmos = allYearAAPL_withEmos.reindex(columns=allYearAAPLwithEmos_newColOrder)
# 保存
allYearAAPL_withEmos.to_csv('补充数据1925102007/AAPL2018allYearData_withEmos.csv')
# 展示
allYearAAPL_withEmos
OpenHighLowVolumeposnegClose/Last
Date
2018-01-0543.360043.842543.2625943597200.0416670.04347843.7500
2018-01-0843.587543.902543.4825820954800.0000000.00000043.5875
2018-01-0943.637543.765043.3525861288000.0000000.09090943.5825
........................
2018-12-2139.215039.540037.40753819916000.0000000.00000037.6825
2018-12-2437.037537.887536.64751486769200.0000000.00000036.7075
2018-12-2637.075039.307536.68002325354000.0909090.09090939.2925

245 rows × 7 columns

3.9.2 预测分析

# 标准化数据输入
X_train, X_test, y_train, y_test, scaler = formatData(allYearAAPL_withEmos)
# 建模
history, model = LSTMModelGenerate(X_train, X_test, y_train, y_test)
# 损失函数绘图
drawLossGraph(history, title='LSTM Loss Graph for 2018 All Year AAPL Stock Prices with Emotions', num='8')

fig8_LSTM_Loss_Graph_for_2018_All_Year_AAPL_Stock_Prices_with_Emotions

# 预测
y_predict = model.predict(X_test)[:,0]
# 反归一化
allYearAAPL_withEmos = pd.read_csv('补充数据1925102007/AAPL2018allYearData_withEmos.csv')
col_n = allYearAAPL_withEmos.shape[1]-2
inv_yPredict, inv_yTest, inv_yTrain = invTransformMulti(scaler, y_predict, y_test, y_train, col_n)
# 绘图
predictGraph(inv_yTrain, inv_yPredict, inv_yTest, timelabels=allYearAAPL_withEmos['Date'].values, title='Prediction Graph of 2018 All Year AAPL Stock Prices with Emotions', num='9')

fig9_Prediction_Graph_of_2018_All_Year_AAPL_Stock_Prices_with_Emotions

# 均方误差
mse = mean_squared_error(inv_yTest, inv_yPredict)
print('2018全年含情感特征的AAPL股票数据预测结果的均方误差(MSE)为 ', mse)
2018全年含情感特征的AAPL股票数据预测结果的均方误差(MSE)为  1.5526791

3.9.3 结果分析

模型训练损失图:对比Fig2. LSTM Loss Graph for Stock Prices with EmotionsFig8. LSTM Loss Graph for 2018 All Year AAPL Stock Prices with Emotions,发现使用2018全年AAPL含情感特征的股票数据训练LSTM模型,在约10次左右epochs时收敛,而部分AAPL含情感特征的股票数据训练则需要约20次左右epochs才能收敛。表明,随训练样本的增加,LSTM模型使损失函数收敛所需的迭代次数更少,且拟合效果更佳

预测结果图:对比Fig7. Prediction Graph of 2018 All Year AAPL Stock PricesFig9. Prediction Graph of 2018 All Year AAPL Stock Prices with Emotions(即只含纯技术指标的和加入情感特征后的2018全年AAPL股票数据预测结果图),发现二者差异甚微。但通过二者MSE值不难发现,MSE (2018全年含情感特征的AAPL股票数据) < MSE (2018全年纯技术指标AAPL股票数据),表明在总体样本量扩大,让评论情感特征数据的时间能够覆盖所有股票技术指标的情况下,向纯技术指标的股票数据中添加情感特征数据后,能够增加对股票收盘价close的预测精度

MSE (2018全年含情感特征的AAPL股票数据) = 1.5526791

MSE (2018全年纯技术指标AAPL股票数据) = 1.7402486

4. 结论与总结

本实验探究了情感结构化特征数据在LSTM股票预测模型中的影响。利用Pandas对所给数据进行预处理(数据载入、清洗与准备、规整、时间序列处理、数据聚合等),确保数据的可用性。再借助NLTK和LM金融词库,对非结构化文本信息进行情感分析,并将所得结构化数据融入纯技术指标的股票数据中。分析各股票指标的相关性,实现数据降维,提升模型训练速度。基于Keras的以MSE为误差评价方法的LSTM模型,分别使用含有情感和不含情感的部分股票数据和2018全年股票数据实现对股票收盘价Close的预测。

实验结果表明,LSTM模型预测股票收盘价Close时,在训练样本量较少的情况下,无论有无情感数据的融入,预测值随时间的推移严重偏离真值,即预测精度较低,而情感数据的融入让预测值变得更加灵敏,涨跌情况更符合真值,但预测精度有所下降。然而,当训练样本充足时,不仅预测精度大幅提升,而且因融入了情感特征数据,使得预测灵敏度适当增加,导致总体预测精度再次增长。

5. 参考文献

[1] Wes McKinney. 利用Python进行数据分析[M]. 机械工业出版社. 2013

[2] 洪志令, 吴梅红. 股票大数据挖掘实战——股票分析篇[M]. 清华大学出版社. 2020

[3] 杨妥, 李万龙, 郑山红. 融合情感分析与SVM_LSTM模型的股票指数预测. 软件导刊, 2020(8):14-18.

[4] Francesca Lazzeri. Machine Learning for Time Series Forecasting with Python[M]. Wiley. 2020


数据集下载:

百度云- https://pan.baidu.com/s/1tC1AFx0kMHPUGobvqf47pg

华大云盘- https://pan.hqu.edu.cn/share/a474d56c6b6557f7a7fd0e0eb7

密码- ued8

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/484776.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI芯片发展现状及前景分析

来源&#xff1a;专知1. AI芯片定义及技术架构1.1 AI芯片定义广义上所有面向AI应用的芯片都可以称为AI芯片。目前一般认为是针对AI算法做了特殊加速设计的芯片。现阶段&#xff0c;这些人工智能算法一般以深度学习算法为主&#xff0c;也可以包括其他浅层机器学习算法[7-8]。1.…

Tableau数据分析:NC Retail Order Data(英)Data Science Program Lab#1(GTI)

Tableau数据分析&#xff1a;NC Retail Order Data&#xff08;英&#xff09; NCSU 2021 Summer Online Data Science Author&#xff1a;©Sylvan Ding

解读:欧盟委员会2021年《人工智能法》提案

来源&#xff1a;图灵人工智能文&#xff1a;吴沈括&#xff08;北京师范大学网络法治国际中心执行主任、博导中国互联网协会研究中心副主任&#xff09;文&#xff1a;胡然&#xff08;北京师范大学网络法治国际中心研究助理&#xff09;2021年4月21日&#xff0c;为了将欧洲变…

《2021人脸识别行业白皮书》发布 拥挤安防还有多少空间?

来源&#xff1a;帮尼资讯图片来源&#xff1a;网络人脸识别在内的人工智能技术需求较大&#xff0c;这对传统安防产业带来了巨大的冲击和变革。近日&#xff0c;智慧芽联合罗思咨询&#xff0c;共同发布《2021人脸识别行业白皮书》。白皮书从人脸识别行业现状、企业聚焦和技术…

第一章 计算机系统概述 1.1 计算机发展史 [计算机组成原理笔记]

第一章 计算机系统概述 1.1 计算机发展史 本笔记参考书目&#xff1a; 计算机组成原理&#xff08;第六版.立体化教材&#xff09;白中英、戴志涛2021王道计算机组成原理视频公开课 本节重点&#xff1a; 计算机硬件的发展史 转载请注明文章来源&#xff01; 什么是计算机系…

我国工业互联网 技术路线与发展趋势研究

来源&#xff1a;中国工业和信息化本文发表于《中国工业和信息化》杂志2021年4月刊总第33期作者&#xff1a;许雪荷 中国工业互联网研究院自2017年《国务院关于深化“互联网先进制造业”发展工业互联网的指导意见》发布以来&#xff0c;国家高度重视工业互联网创新发展&#…

【创新应用】小图像,大图景:AI彻底改变了显微镜技术

来源&#xff1a;智能研究院20 年前&#xff0c;计算机生物学家 Anne Carpenter 在读博士时第一次意识到她需要学习计算机编程。Carpenter 说&#xff1a;「在麻省理工学院和哈佛大学的博德研究所 (Broad Institute of MIT and Harvard in Cambridge) 管理实验室的时候。她记得…

历史上12篇最著名的博士论文欣赏

来源 &#xff1a; 学位与写作Ali Gajani在mrgreek网站分享了12篇著名学者的博士论文&#xff0c;分别是居里夫人的博士论文、香浓的博士论文、纳什的博士论文、德布罗意的博士论文、费曼的博士论文、爱因斯坦的博士论文、马克思的博士论文、韦伯的博士论文、萨特兰的博士论文、…

Exalogic硬件架构

1、硬件配置见如下图表。 组件名称满配半配1/4配1/8配Sun Rack II 12421111计算节点 X2-2、X3-2、X4-2、X5-2、X6-2301684存储设备 X2-2和X3-2: Dual controller Sun ZFS Storage 7320 appliance (60 TB) X4-2和X5-2: Oracle ZS3-ES storage appliance X6-2: Oracle ZS5–ES st…

AI领域五年引用量最高的10大论文:Adam登顶,AlphaGo、Transfromer上榜

来源&#xff1a;图灵人工智能编译&#xff1a;琰琰近五年来&#xff0c;AI学术论文的投稿量和接收量都在不断攀升&#xff0c;包括NeurIPS、AAAI、ACL&#xff0c;ICML、EMNLP等国际顶会。根据权威数据统计&#xff0c;NeurIPS论文收录量在2019年呈指数级增长&#xff0c;领先…

64 求1+2+3+...+n(发散思维能力 )

题目描述&#xff1a; 求123...n&#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句&#xff08;A?B:C&#xff09;。 解题思路&#xff1a; 1&#xff09;利用&&的短路特性 2) 利用sizeof特性&#xff0c;使用公式n(n1)/2 …

Cell Reports:黄梓芮等揭示大脑皮层中通往意识的“大门”

来源&#xff1a;小柯生命北京时间2021年5月4日晚23时&#xff0c;Cell Reports在线发表美国密歇根大学一项关于前脑岛在大脑网络切换和意识通达中关键门控作用的研究——“Anterior insula regulates brain network transitions that gate conscious access”。此研究由密歇根…

DeepMind强化学习新研究:更快的知识学习,更强的环境适应

来源&#xff1a;AI科技评论编译&#xff1a;Mr Bear校对&#xff1a;维克多DeepMind官方博客在一篇文章“Fast reinforcement learning through the composition of behaviours”中&#xff0c;针对强化学习中的“从头学习”问题给予了解决方案。文章中表示&#xff0c;人类处…

为什么AI无法解决一般智能问题?

来源&#xff1a;学术头条我们什么时候才能拥有在各方面能够模仿人脑的人工智能&#xff1f;专家们对这个问题意见不一。但大家都同意的是&#xff0c;目前的人工智能系统与人类的智力相去甚远。直接表现是&#xff1a;AI只在特定任务中表现优异&#xff0c;无法将其能力扩展到…

ADT操作实例

ps.1.put(rank,value) 把当前rank的元素的数值修改 2.get(rank)获取rank的元素 3.remove(value)把向量中value剔除掉 4.size()返回元素个数 5.disordered()检测向量的有序性&#xff0c;是否存在紧邻的逆序对&#xff0c;只要返回的数值不是0&#xff0c;说明它尚未构成有序的序…

群雄逐鹿,谁会赢得自动驾驶之战?

来源&#xff1a;AI前线作者 | Timothy B.Lee译者 | 王强策划 | 刘燕自动驾驶技术行业今天正处于一种奇怪的状态。过去多年来&#xff0c;整个行业已经在自动驾驶技术上投入了庞大的资金&#xff0c;其中许多公司都拥有了看起来跑得不错的自动驾驶汽车原型。但据我所知&#xf…

ActiveMQ反序列化漏洞(CVE-2015-5254)复现

0x00 漏洞前言 Apache ActiveMQ是美国阿帕奇&#xff08;Apache&#xff09;软件基金会所研发的一套开源的消息中间件&#xff0c;它支持Java消息服务&#xff0c;集群&#xff0c;Spring Framework等。Apache ActiveMQ 5.13.0之前5.x版本中存在安全漏洞&#xff0c;该漏洞源于…

阿里最新研究试用因果推理方法让视觉AI更智能,入选CVPR 2021

来源:AI前线学过人类照片和鱼类照片的 AI&#xff0c;第一次见到美人鱼的照片会作何反应&#xff1f;人脸和鱼身它都很熟悉&#xff0c;但它无法想象一个从没见过的事物。近期&#xff0c;阿里巴巴达摩院将因果推理方法引入计算机视觉领域&#xff0c;尝试克服机器学习方法的缺…

博客文章排版学习

一、序言 第一次写博客觉得文章的排版十分重要&#xff0c;查阅了几篇博文&#xff0c;觉得Leo_wlCnBlogs的文章让我获益良多&#xff0c;所以我做出了总结&#xff0c;方便自己学习复习。 博文写出来排版好了才让人看得舒服&#xff0c;才有动力看下去&#xff0c;之前百度查资…