上市公司历史新闻数据分析(二)

今天小编打算补充一下上一篇上市公司历史新闻数据分析(一)的部分内容,以及进一步阐述如何利用SVM和RandomForest做文本分类及效果对比。

       上一篇文章有提到用LDA主题模型做文本特征抽取,其实LDA主要是将“Document x Word”矩阵分解为“Document x Topic”矩阵和“Topic x Word”矩阵。通俗的说,LDA是为了说明某一系列的Words放在一起构成的Document很有可能在描述某一类Topic。下图显示了在实验中,将文本集转为lsi向量或lda向量的大致流程:

        这里顺便说一下word2vec和doc2vec,两者都可以做特征抽取,但实验效果都没有LDA好,因此也就不描述实验。word2vec也叫word embeddings,就是根据词语与上下文词语的关系(相关情况),将已分词的文本进行训练,得到每个词的向量表示,即词向量(稠密向量,distributed representation),并且其中相近意义的词语将被映射到向量空间中相近的位置。主要有以下几点应用:(1)计算词语间的相似度,比如同样在城市主题下,衡量“北京”更接近“上海”还是“广州”;(2)计算词语的类比关系,比如“King”+“Woman”-“man”近似于“Queen”;(3)计算文本间的相似度。word2vec有两种训练算法,一个是CBOW模型,一个是skip-gram模型,详细解释可参考链接<1>。doc2vec又叫做paragraph2vec或者sentenceembeddings,是一种非监督式算法,可以获得句子/段落/文档的向量表达,是word2vec的拓展,详细解释可参考链接<2>。

        在进行文本特征选择后,接下来就是文本表示,也就是把非结构化的文本转为计算机可以处理的结构化数据形式。在Gensim的官方教程(参考链接<3>)中有提到如何将Gensim类型数据转为Numpy和Scipy类型数据,转换的目的自然是为了适应更多机器学习库。在模型上,我选择了scikit-learn的SVM和RandomForest做对比。下面是一部分简约代码展示如何用GridSearchCV做参数优化:

fromsklearnimportsvm

fromsklearn.ensembleimportRandomForestClassifier

fromsklearn.externalsimportjoblib

fromsklearn.model_selectionimportGridSearchCV

fromsklearn.metricsimportclassification_report

scores = ['precision']#['precision','recall']

tuned_parameters_svm = {'kernel': ['rbf'],'gamma': [10,20,50,100,150,200], \

'C': [10,15,20,30,50,100]}

tuned_parameters_rdf = {"n_estimators": [10,20,50,80,100],"criterion": ["gini","entropy"], \

"min_samples_leaf": [2,4,6,10,20]}

forscoreinscores:

ifnotos.path.exists('./svm.pkl'):#或'./randomforest.pkl'

clf = GridSearchCV(svm.SVC(), tuned_parameters_svm, cv=5, scoring='%s_weighted'% score)# 构造这个GridSearch的分类器,5-fold

# clf = GridSearchCV(RandomForestClassifier(random_state=14), tuned_parameters_rdf, cv=5, scoring='%s_weighted' % score) # 构造这个GridSearch的分类器,5-fold

clf.fit(train_X, train_Y)# 只在训练集上面做k-fold,然后返回最优的模型参数

joblib.dump(clf,'./svm.pkl')#或'./randomforest.pkl'

else:

clf = joblib.load('./svm.pkl')

print(clf.best_params_)# 输出最优的模型参数

# for params, mean_score, scores in clf.grid_scores_:

#   print("%0.3f (+/-%0.03f) for %r" % (mean_score, scores.std() * 2, params))

train_pred = clf.predict(train_X)

test_pred = clf.predict(test_X)# 在测试集上测试最优的模型的泛化能力.

print(classification_report(test_Y, test_pred))

其中,scores是优化目标,可以按照准确率(precision)或者召回率(recall),当然还有别的;tuned_parameters_svm(tuned_parameters_rdf)表示选择的参数以及参数优化范围;训练好的模型最好还是用joblib给保存起来;最后用classification_report打印结果,如下图:

依然用山西焦化(600740)作为测试股票。首先从所收集的新闻数据中抽取与600740相关的新闻存到新的数据,并且依据这些数据生成600740的新闻字典以及bow向量,然后用LDA抽取主题模型向量,并保存。最后设置30个Epoch,来对比SVM和RandomForest在测试集的分类效果,如下图:

可见SVM在实验表现优于RandomForest。

        模型训练好了,当然得测试一下实际效果。由于新闻数据的收集只是到最近的2月3日,所以用2月3日之后的关于山西焦化的新闻数据进行测试。这里选了新浪财经在2月6日的一篇新闻(网址是参考链接<5>),标题是《中央、地方支持政策频出 煤炭行业站上了风口》,和金融界在2月5日的一篇新闻(网址是参考链接<6>),标题是《[山西焦化]郭文仓到终点工程项目督导检查》,下面是一段简约代码和输出结果:

Obj = TextMining(IP="localhost",PORT=27017)

doc = ['中央、地方支持政策频出,煤炭行业站上了风口 券商研报浩如烟海,投资线索眼花缭乱,第一财经推出\

《一财研选》产品,挖掘研报精华,每期梳理5条投资线索,便于您短时间内获取有价值的信息。专业团队\

每周日至每周四晚8点准时“上新”,...'

,\

'郭文仓到重点工程项目督导检查 2月2日,公司党委书记、董事长、总经理郭文仓,公司董事,股份公司副\

总经理、总工程师、郭毅民,股份公司副总经理张国富、柴高贵 ...'

]

token = Obj.ge2.jieba_tokenize(doc)#分词

dictionary = corpora.Dictionary.load('./600740_dict.dict')#加载历史文档字典

bowvec_doc = [dictionary.doc2bow(text)fortextintoken]#生成新文档的bow向量

bowvec_all = list(corpora.MmCorpus('D:\\stock_dict_file\\600740\\600740_bowvec.mm'))#加载历史文档bow向量

bowvec_all.extend(bowvec_doc)#更新历史文档bow向量

_, NewmodelVec = Obj.ge2.CallTransformationModel(dictionary,bowvec_all,modelType='lda',\

tfDim=200,renewModel=False,modelPath='D:\\stock_dict_file\\600740\\')#生成新的lda向量

NewCSRMatrix = Obj.ConvertToCSRMatrix(NewmodelVec)#将新的lda向量转为scipy类型的稀疏矩阵

clf = joblib.load('D:\\stock_dict_file\\600740\\600740_svm.pkl')#加载训练好的svm模型进行分类预测

fori, newsinenumerate(doc):

ifclf.predict(NewCSRMatrix[i-2,:])[0] ==1:

print('《'+ news.split(' ')[0] +"》"+'是利好消息 ...')

elifclf.predict(NewCSRMatrix[i-2,:])[0] ==-1:

print('《'+ news.split(' ')[0] +"》"+'是利空消息 ...')

else:

print('《'+ news.split(' ')[0] +"》"+'是中立消息 ...')

下面是山西焦化(600740)最近几天的股票价格,可见2月5日之后股票价格下跌,当然也不排除这几天的下跌多数是由系统性风险造成。但总的来说,这次的研究还是蛮具有实战价值。

参考链接:

<1> http://blog.csdn.net/u014595019/article/details/51884529

<2> https://www.cnblogs.com/maybe2030/p/5427148.html

<3> https://radimrehurek.com/gensim/tut1.html#compatibility-with-numpy-and-        scipy

<4> http://blog.csdn.net/lixiaowang_327/article/details/53434744

<5> http://finance.sina.com.cn/stock/hyyj/2018-02-04/doc-                                        ifyreyvz9053830.shtml

<6> http://stock.jrj.com.cn/2018/02/05000024071826.shtml

推荐阅读更多精彩内容