ccombox获取选择的文本_NLP入门5:文章情感分与回报率研究-数据获取部分与预处理...

cfed9a8edc1fecf49f69647ced8a41d9.png

为了复刻《Predicting Returns with Text Data》这篇文章进行的研究。2020年版本在如下链接中,尝试的方法会以2019年版本为主。

Predicting Returns with Text Data​poseidon01.ssrn.com

项目:在不依靠已存在字典的情况下理解文本的sentimental structure

为了减轻workload和计算量,只会使用10-20个股票、1-2年内的数据。

11/21:主要任务移到Methodology部分,预处理部分可能按需要稍微调整

内容总结

  • 获取数据
    • 新闻来源:NEXIS UNI
    • 股票数据:CRSP
  • 数据读取和预处理
    • 去专有名词
    • 标准化
    • stemming & lemmazation
    • 标记化
    • 去停用词
    • 词袋与词向量
    • crsp获取前两个、前一个、下一个交易日的股票价格

数据获取

1)无法获取Dow Jones Newswire数据,其他来源数据质量不理想

按照原文所述,文本内容来自Dow Jones Newswires,实际上学校没有订阅数据,价格也比较贵(2.5万还是5万美金/年),没法自费购买。备选的方法有Nexis Uni资料和自己写爬虫,各有优缺点:

Nexis UniWeb Scrapping (New York Times)
+1)新闻数量多,涵盖内容丰富+1)消息来源可靠,真实
+2)一次性可以下载100条文章+2)每天都有1条新闻
-1)全程需要手动下载数据,缩小文章搜索范围-1)如果不用seleunim进行点击操作,单个股票/公司只能爬9条新闻(技术原因)
-2)文章内容有重复-2)消息来源和内容单一,可能只包括金融方面信息
×

最后决定使用Nexis Uni数据,它的优点也比较明显,缺点相对来说可以接受。同时,(两个)数据仍然有无法解决问题:

  • 发布时间只精确到天,所以无法按照原文精确到小时的日起分类方法;

2)CRSP股票数据

订阅的权威数据,clean data,不需要额外操作,但是缺少2020年的数据。

//********************************************************************//

数据读取和预处理

1)从解压好的新闻里读取文件,使用reg ex提取文章内容和时间

# read docx file

2)文本数据预处理

# 需要的包

3)CRSP数据处理

对表格进行self join,获得

时的股票价格。

4)合并文本数据和CRSP数据

主要包括时间、单词、词向量、股票价格

下面是详细介绍日常进展汇报


1 数据准备

文章里的文本来自Dow Jones Newswires,股票回报数据来自CRSP,由于学校没有买Dow Jones Newswires,所以使用其他数据来源。

(1)选取Nexis Uni作为文本来源

这家新闻覆盖面比较全,日期、来源、地域、语言、领域都可以选择,一次性下载100篇文章基本也符合需要了,毕竟文本量太大的话处理起来比较费时间。目前暂定以New York Times作为消息来源,主要是为了避免多家媒体对于同一事情以不同方式做了处理、单一消息源可以cover尽量多的时间范围(100条新闻上限),不过问题还是有几个:

  • 单独下载的文件会以.docx存在,暂时不知道怎么读取(11/11 已解决)
  • 必须手动下载文件,读取多个文件包里的多个内容暂时不知道怎么做(11/12 已解决)
  • 不知道怎么精确提取文本内容和时间,去掉不必要的东西(11/15 基本解决)

(2)选取web scraping New York Times作为文本来源

理由基本同上,但需要先搜公司名,在搜索结果中再把新闻一条一条提取出来,缺点是只能提取9条新闻,如果需要点击“show more”需要再用selenium包,没有那么多时间研究

关于获取新闻链接的函数已经写好了(2020/11/11),以苹果公司为例,获取结果如下:

[

同样,这个函数/搜索方式的缺点是不可以用ticker搜索

(3)CRSP数据

学校买了,下就完事了

数据质量

2020/11/13:

关于这部分,最主要的问题是对文本内容和质量的担忧。

  • 按照论文所述,每篇文章可能对应一个或者多个公司,也可能完全没有对应,目前不知道研究者是怎么移除不符合要求的文章的
  • 由于Nexis Uni上的文章的发布时间没有精确到小时,无法按照文中给出的方法合并文章,按原文所说,一篇在(t-1) 4 p.m.后且(t)4p.m.前的文章要和公司三天(t-2到t+1)的收盘价挂钩
那暂且假设,前一天(t-1)的文章可能会对后一天(t)的开盘价造成一定影响,当天的股票(姑且不管发布时间)对于收盘价有影响
  • 所谓“Chained Article”,文章并没有解释
  • CRSP数据只更新到了2019/12/31,之后并未给出
  • 研究人员自己也指出,新闻网的数据来源于多个媒体,可能会对同一事件有冗余覆盖,尽管在训练和测试集中没有影响,但对于样本外的分析会有反作用(adverse impact on our out-of-sample analysis)。

2 预处理 Pre-Processing

根据2020年版本,

关于 文本部分的处理,首先 去掉专有名词(proper noun),接下来 正则化文本内容。
第一步:
1)所有单词转成小写;
2)扩展缩写,列如“haven't”转化为“have not”;
3)去掉数字,标点,特殊符号,非英语单词;
第二步:通过stemming和lemmazation,将不同时态、不同单复数形式等单词转化为同词根单词。
第三步:tokenize文本
第四步:去掉停用词。
第五步:获取词向量,以"bag-of-words"表示。

实际操作起来的时候,我不太能明白为什么研究者在第三步才分开单词。基本按照原文提供的步骤,主要的思路如下:

  • 在读取文本的时候就扩展缩写,具体方法来自stackoverflow,
Expanding English language contractions in Python​stackoverflow.com
153df5abb1a4afd35f812b42bfe107c6.png
  • 使用nltk.tag.pos_tag()获取单词的成分,移除专有名词(NNP和NNPS)[1]
  • tokenize
  • 使用isalpha()和lower()去标点
  • stemming,lemmazation
  • 去掉停用词
  • 获取词向量

edd54ebe15471e093fe35e8ec1c9dfe0.png
词频分布(去掉停用词等)

去掉停用词以后,300篇文章大约提供了5300个单词,其中有一些在stemming和lemmazation之后不是“完整”的单词。进一步统计了特定出现频率单词的个数,例如只出现1-2次的单词个数,并移除:

dd09fcdb7e875b357ca237e56d630aa7.png
统计各词频单词个数

移除1-2词频单词后,还有3000+单词。

11/19重要进展(目前依然只有296篇文章):

之前一直很疑惑,为什么研究人员在预处理部分采取了先标准化,stemming和lemmazation,再标记化的决定。个人是觉得,既然stemming和lemmazation要求input是list,那直接用nltk.word_tokenize()——一下子就标记化并且改为word list,然后stemming更方便。但这样会带来一个问题:

由于一些动词可以采用不同的格式,列如study有studies, studying, studied等形式,在标记化时解释器会当做不同的单词对待,即便这些格式都指向同一个单词的同一个意思。

正因为如此,才需要先stemming和lemmazation。

但是,在一些教程、实际操作中我也发现,stemming出来的单词并不总是“real words”,比如company会变成compani,虽然说也能推断出原来的单词,却有一点影响理解。所以我只用了lemmazation,把pos设定为v,假定动词对于文章更重要

大部分预处理都采取研究人员的操作顺序。

现在的顺序原来顺序(错误)
(标准化:在读取文章时就把缩写转扩写)(标准化:在读取文章时就把缩写转扩写)
去掉专有名词去掉专有名词
1)标准化:去标点、特殊字符、非英语单词,去数字,转小写,(扩写)3) 标记化
2)lemmazation1)标准化:去标点、特殊字符、非英语单词,去数字,转小写,(扩写)
3) 标记化2)stemming和lemmazation
4) 去停用词,附加去低频词4) 去停用词,附加去低频词
5)词向量与词袋5)词向量与词袋

好处有三个(算是3个):

1)留了更少的单词,对于之后的研究分析很有帮助,提升效率,应该也能省内存吧,比如说原先不去低频词大约有5300+单词,现在只有4690个,去掉低频单词后也从3360+单词变为约2900单词

91789a4a31f3c1f9400795406a36dcab.png
原来的单词个数统计

714eb7348ac87021e0f60efb5429f0cc.png
现在单词个数统计

2)词云图里的单词都是real words,不会出现compani,ha, wa,这种奇怪的词,也不会同时出现said和say

8b5d14b022b8ff73dcba9b38d6e9cd40.png
原来的词云图

c31a12f2204875370b73722eda446397.png
现在的词云图

3)个人觉得代码更简洁,运行效率更高了,比如原来stemming和lemmazation一共要处理4s,现在大约400ms(毕竟不需要Stemming);原来移除停用词是299ms,现在200ms出头(虽然在毫秒级别上这点进步没什么意义)


进展汇报:

  • 2020/11/11:
    • 判断新闻数据源的优劣,尝试web scraping纽约时报网站
    • 写了.docx读取方法
  • 2020/11/12:
    • Nexis Uni无法保证New York Times信息的即时性;根据现在的筛选,一天之内依然有多个新闻(其实是好事,一条新闻判断涨跌很武断);筛选个数20条,具体筛选条件如下:

d1a39d1449f839c8cf765798b96b8f4a.png
    • 写了读取目录下文件的函数
from 
    • Nexis Uni下载的数据发现一些问题:
      • 存在标题完全一致的文章,如果下载20篇,2篇重复,就只有19篇独立文章
      • 由于每天都有多条新闻,20篇文章可能只cover了3天的新闻量
    • 写了从文章里读取时间、文章内容,由于文章内容是从Body开始,但是结束的地方没有固定的格式,有的地方是有Graphic标记,有的直接就是by author,所以不好判断结束。最后使用了笨办法获取文本,获取文本list中文本开始和结束的(也就是body标记和by标记的地方)index,取出文本,合并为string,最后生成一个带有ticker,发布时间,标题,内容的DataFrame
# read docx file in the directory
    • 即使获取了如上信息,时间格式仍然不统一,在之后data clean部分做处理:

bd8b20c17308cd53887f3544315173d1.png
    • 使用regex取出时间,按月,日,年分别放入三个列,去掉空行(因为日期为空),并改变日期格式
# regex, extract time and drop na

13ae9bade5364588c5170e2afe28ba5f.png
  • 2020/11/13
    • 重新获取新闻数据,时间范围改为2019/01/31 - 2019/12/31,按newest-oldest取100篇文章(实际上并不能cover很长的日期),group duplicates

e1b8850528f1c695ac6b30d3967206b0.png
    • 转换时间格式后,获取weekday信息,简单查看新闻数量分布
    • 使用上面笨办法取出的文本可能依然含有“Body”这个东西,同一件事用不同title还是会出现

5c9b1d57999278c6684ff778b732ea63.png
  • 11/14
    • 正在研究另一篇NLP入门[2],并无实质性进展
    • 从NLP入门里看到的字母判断(去掉标点)、大小写转化:
#Empty list to store words:
    • 获取词频的method,参考了上述tutorial给出的代码,并且画出分布,具体例子明天写(这篇文章真的非常有用!)
# Import required libraries: 
    • 停用词等部分不抄了,尊重原作者。整理一下思路:先拆分出单词(tokenize),接着看一下最初的词频;去掉标点(no punctuation),再看词频和词的数量;去停用词,再查看词频+数量
    • 接下来预计做词云图
  • 11/15:
    • 按照tutorial,用一篇文章作为sample(简称sample),一直做到了词云图
    • 优化NLP代码,使其简洁、更精确提取文章内容(使用了正则表达)
    • 开始进行预处理工作,去掉专有名词(proper noun),移除数字、标点、特殊符号,无法完成缩写转扩写(haven't→have not),pyconstraction包无法安装,会尝试写函数修改
# 去专有名词
  • 11/16:
    • 继续完成预处理部分,已经做好了stemming,lemmazation,去停用词,去低频词部分
# remove low frequency words
df["words"] = df.apply(lambda row: removeLowFreq(row['clean_words'], freq1), axis = 1)
df["words"] = df.apply(lambda row: removeLowFreq(row['words'], freq2), axis = 1)
df["words_len"] = df["words"].str.len()
    • 准备整合函数,开始对CRSP数据进行处理
  • 11/17:
    • 完成bag-of-words,并以DataFrame格式呈现,尝试在countvector里再筛选掉低词频单词,目前单词数量3342

8311332d9e64573678e970fa353656db.png
    • 目前已经处理好了这几部分:文章题目,文章发布时间,词向量;需要处理的部分:CRSP数据
      • CRSP数据遇到了问题,苹果(Apple, Inc)的Ticker APPL提交以后没法取到数据
      • 合并表格的时候用到BOW(bag-of-words),文本title和日期,这三个能合并起来;但是加上CRSP还不成功,因为一个同一个日期有好几个股票的数据,对应的时候必须选择TICKER和日期同时进行合并;另外,CRSP的数据里的date似乎不是unique....
  • 11/18:
    • 昨天说到crsp数据的问题,处理方式如下:1)按ticker去掉重复日期(可能数据更新不及时导致这个问题)2)时间格式从MM/DD/YYYY改为MM-DD-YYYY,保持和文本部分时间格式一致,这样解决了即使成功连接两表也会让右侧值为NaN的问题
    • 关于合并时的新问题,报错。准确说我也不知道为什么,但是把文本数据存在电脑上再读取一次,就能顺利合并了。
The column label 'date' is not unique
    • 准备着手Methodology部分,对于CRSP数据,以文章发布时间为t计算,还需要(t-2), (t-1), (t+1)用于训练或预测的股价/回报,为了整合这个数据我想了好几个小时,
      • 先是通过pd.merge()(即上面合并表格方法),通过改变date的办法(为了得到对应t-1,把所有的t'都改为t+1,然后连接两表),还学会了改后缀(suffix),结果只有MSFT的结果没有BABA
      • pd.shift(),结果全部结果都shift,压根就无视了ticker
      • pd.shift() + groupby,顺利完成任务,不过缺点是所有t都代表了交易日,不是自然日,也就是说t是12-24的话,t+1是12-26而不是12-25(圣诞节是法定节日)
  • 11/19:
    • 调整预处理顺序,改进代码,报告已经在文本里更新
      • 优先lemmazation再tokenize
      • 去掉stemming
      • 优化代码
      • 更新词云图
    • 整合文档
  • 11/20:
    • 整合crsp数据,对于时间t',获取(t'-2),(t'-1),(t'+1)时的收盘价格,其中t为交易日,不是自然日
    • 在已经做好词向量+文章发布时间t的数据表内,合并crsp,对于任意时间t,有t-2,t-1,t+1的收盘价

835b8fd3184e64412258ceffb03b883c.png
  • 11/21
    • 解决了apple, inc无对应股票价格的问题:ticker写错了(是我瞎)
    • 加入1个新的股票:Tesla,获取一百条新闻(其中有大量重复)
    • 删除去低频词,原因:
      • 1)词频计算方式变化。在后文作者描述词频f计算方式时,需要的是包含词j的文章的数量,也就是说如果词j在一篇文章里出现2词,那么按原方法计算词频是2,现在方法计算是1,举例来说,词“apple”在3篇文章里出现了1次,2次,10次,按原方法计算词频是13词,很可能不被去掉;按照现在的方法是3次,需要去掉
      • 2)去掉低频词可以通过调整超参k去掉,简洁代码
    • 调整CRSP与词向量合并参数,从inner join 改为left,在t和(t'-2),(t'-1),(t'+1)均为NaN时保留文章
    • 想把新闻搜索结果按“newest to oldest”改为按相关度排序
    • 进入Methodology部分

参考

  1. ^https://stackoverflow.com/questions/39634222/is-there-a-way-to-remove-proper-nouns-from-a-sentence-using-python
  2. ^https://link.zhihu.com/?target=https%3A//medium.com/towards-artificial-intelligence/natural-language-processing-nlp-with-python-tutorial-for-beginners-1f54e610a1a0%237d22
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值