利用主成分分析构建股票指数

作者:谢佳标

中国R语言大会讲师,高级数据分析师,8年以上数据挖掘建模工作实战经验

https://ask.hellobi.com/blog/xiejiabiao/4288

利用主成分分析构造你个人的股市指数,然后分析你的私家指数和该股市常用官方股票指数的相关性。

接用ML_for_Hackers-master 书中的数据。

> prices<-read.csv("stock_prices.csv")
> prices[1,]
        Date Stock Close
1 2011-05-25   DTE 51.12
> # 原始数据集并不是我们喜欢使用的格式,因此需要进行预处理。
> # 第一步,把数据集中的时间戳转换为正确编码的日期变量。这要用到lubridate包中的ymd函数
> # install.packages("lubridate")
> library(lubridate)
> prices<-transform(prices,Date=ymd(Date))
> # 一旦完成这一步,就能适用reshape函数库中的cast函数
> library(reshape)

Attaching package: ‘reshape’

The following object is masked from ‘package:lubridate’:

    stamp

> date.stock.matrix<-cast(prices,Date~Stock,value="Close")
> which(complete.cases(date.stock.matrix)==F) # 22 875条记录有缺失值
[1]  22 875
> # 分析了这个生成结--巨大的日期-股票矩阵之后,我们注意到缺失了一些元素。
> date.stock.matrix[22,];date.stock.matrix[875,]
         Date ADC AFL ARKR AZPN CLFD DDR DTE ENDP FLWS FR GMXR GPC HE ISSC ISSI KSS MTSC
22 2002-02-01  NA  NA   NA   NA   NA  19  NA   NA   NA NA   NA  NA NA   NA   NA  NA   NA
   NWN ODFL PARL RELV SIGM STT TRIB UTR
22  NA   NA   NA   NA   NA  NA   NA  NA
          Date  ADC   AFL  ARKR AZPN CLFD DDR   DTE  ENDP FLWS    FR  GMXR   GPC    HE
875 2005-06-22 30.4 43.49 26.56 5.76 1.47  NA 46.89 25.88 7.23 41.45 13.45 42.76 27.21
     ISSC ISSI   KSS  MTSC   NWN  ODFL  PARL RELV SIGM   STT TRIB   UTR
875 35.42 7.22 56.06 34.54 36.87 27.74 28.96 10.3 8.12 49.22 6.69 49.98
> # 因此回到最初的prices数据集,删除那些缺失元素的数据,再运行cast函数:
> prices<-subset(prices,Date!=ymd('2002-02-01'))
> prices<-subset(prices,Stock !='DDR')
> date.stock.matrix<-cast(prices,Date~Stock,value="Close")
> which(complete.cases(date.stock.matrix)==F)  
#0
integer(0)
> # 接下来可以适用cor函数来找到这个矩阵中所有数字列之间的相关性。然后将相关性矩阵转换成一个数值向量,并且画一个相关性密度图,
> # 以此来获得两个直观认识:a)相关性的均值;b)低相关性出现的频率。
> cor.matrix<-cor(date.stock.matrix[,2:ncol(date.stock.matrix)])
> correlations<-as.numeric(cor.matrix)
> library(ggplot2)
> ggplot(data.frame(Correlation=correlations),
+        aes(x=Correlation,fill=1))+
+   geom_density()+opts(legend.position='none')
> #正如密度图所示,大部分相关性是正数,因此PCA适合用于这份数据集.
> # 我们适用princomp函数来运行PCA:
> pca<-princomp(date.stock.matrix[,2:ncol(date.stock.matrix)])
> # 我们只对第一主成份感兴趣,所以只把pca载荷的第一列提取出来:
> principal.component<-pca$loadings[,1]
> # 完成这些之后,我们可以分析载荷的密度图,直观地了解第一主成份是如何形成的。
> loadings<-as.numeric(principal.component)
> ggplot(data.frame(Loadings=loadings),
+        aes(x=Loadings,fill=1))+
+   geom_density()+opts(legend.position="none")
> # 这个结果有点让人疑惑,因为载荷有一个相当不错的分布,但是几乎全是负数。它实际上是个很小的麻烦,我们用一行代码就能解决。
> # 到目前为止我们获得了主成分,接下来可以把这些数据总结成一列了。可以使用predict函数完成这个目标:
> market.index<-predict(pca)[,1]
> # 如何才能知道这些预测值的效果呢?幸运的是,对这个实例我们可以很容易地判断结果好坏

> # ,因为可以把结果和著名的市场指数做比较。在本章中,我们用道琼斯指数(Down Jones Index DJI).
> dji.prices<-read.csv("DJI.csv")
> dji.prices<-transform(dji.prices,Date=ymd(Date))
> # 因为使用整个DJI运行的时间比我们预想的要长很多,所以需要取一个它的自己,仅仅获得我们感兴趣的那些日期。
> dji.prices<-subset(dji.prices,Date>ymd('2001-12-31'))
> dji.prices<-subset(dji.prices,Date !=ymd('2002-02-01'))
> # 然后,提取DJI中我们感兴趣的部分,也就是每日收盘价格和我们记录过的那些日期。
> # 因为它们的顺序和我们现在的数据集相反,用rev函数反转它们即可:
> dji<-with(dji.prices,rev(Close))
> dates<-with(dji.prices,rev(Date))
> # 现在我们可以绘制一些简单的图,将使用PCA生成的市场指数和DJI相比较:
> comparison<-data.frame(Date=dates,MarketIndex=market.index,DJI=dji)
> ggplot(comparison,aes(x=MarketIndex,y=DJI))+
+   geom_point()+geom_smooth(method="lm",se=FALSE)
> #从图可以看出,那些之前看上去烦人的负载荷,真的成为了麻烦的源头:我们的指数和DJI付相关。
> # 但是,我们可以很容易地解决这个麻烦。只需要对指数乘以-1,即可生成一个和DJI正相关的指数
> comparison<-transform(comparison,MarketIndex=-1*MarketIndex)
> # 现在可以再尝试一次进行比较:
> ggplot(comparison,aes(x=MarketIndex,y=DJI))+
+   geom_point()+geom_smooth(method="lm",se=FALSE)
+   geom_point()+geom_line(
)
> #如图,我们已经修正了指数的方向,并且它看上去和DJI真的很匹配。
> # 剩下的最后一件事情,就是获得我们的指数随着时间推移与DJI的趋势保持一直的程度。
> # 首先,使用melt函数获得一个数据框,它可以很容易地一次性对两个指标进行可视化。
> # 然后,我们对每个指数活出一条以日期为x轴,以价格为y轴的线。
> alt.comparison<-melt(comparison,id.vars="Date")
> names(alt.comparison)<-c("Date","Index","Price")
> ggplot(alt.comparison,aes(x=Date,y=Price,group=Index,color=Index))+
+   geom_point()+geom_line()
> # 这一次结果并不是很好,因为DJI都是很高的值,而我们的指数都是很小的值,但是可以使用scale函数解决这个问题。
> comparison$MarketIndex<-scale(comparison$MarketIndex)
> comparison$DJI<-scale(comparison$DJI)
> alt.comparison<-melt(comparison,id.vars="Date")
> names(alt.comparison)<-c("Date","Index","Price")
> ggplot(alt.comparison,aes(x=Date,y=Price,group=Index,color=Index))+
+   geom_point()+geom_line()

> # 看上去与DJI的趋势保持得相当好。总之,用PCA真的能够产生一副股票价格的趋势图。

原文发布于微信公众号 - 大数据挖掘DT数据分析(datadw)

原文发表时间:2016-08-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Hadoop数据仓库

HAWQ + MADlib 玩转数据挖掘之(八)——聚类方法之k-means

一、聚类方法简介         所谓“物以类聚,人以群分”,其核心思想就是聚类。通过聚类,人们能意识到密集和稀疏的区域,发现全局的分布模式,以及数据属性之间有...

2235
来自专栏微信公众号:Java团长

BATJ等公司必问的8道Java经典面试题,你都会了吗?

我在 Oracle 已经工作了近 7 年,面试过从初级到非常资深的 Java 工程师,且由于 Java 组工作任务的特点,我非常注重面试者的计算机科学基础和编程...

621
来自专栏人工智能

Redis-ML简介(第5部分)

原文地址:https://dzone.com/articles/an-introduction-to-redis-ml-part-five-redis-labs

6788
来自专栏java思维导图

跳槽时,这些Java面试题99%会被问到

工作多年以及在面试中,我经常能体会到,有些面试者确实是认真努力工作,但坦白说表现出的能力水平却不足以通过面试,通常是两方面原因:

1123
来自专栏恰同学骚年

OOAD利器之UML基础

UML:Unified Modeling Language,即统一建模语言,简单地说就是一种有特殊用处的语言。本文是我初步学习UML的学习笔记,对于我们菜鸟码农...

592
来自专栏数据和云

神马?SQL竟然可以解脑筋急转弯的题目?

我在很多公开演讲中都明目张胆的羡慕过一类人,他们把SQL当做艺术,把旁人眼中的枯燥演绎成经典,云和恩墨专家团队中的杨廷琨、罗海雄就都是这样的SQL专家。 今天,...

3084
来自专栏斑斓

面向流的设计思想

作者 | 张逸 特别说明:本文包含大量代码片段,若要获得更好阅读观感,请点击文末“阅读原文”或访问我的博客。 响应式编程(Reactive Programmin...

3263
来自专栏跟着阿笨一起玩NET

浅谈数据库设计技巧(上)(转)

转一篇他人写的数据库设计技巧,感觉也不一定都正确,开拓一下思路吧。 说到数据库,我认为不能不先谈数据结构。1996年,在我初入大学学习计算机...

461
来自专栏程序员维他命

2017年5月iOS招人心得(附面试题)

在2017年5月中旬,技术老大让我招两个1-2年的iOS开发,把简历的筛选和第一轮技术面试的任务交给了我。于是便自己准备了这套面试题。

1094
来自专栏小樱的经验随笔

设计模式六大原则(1):单一职责原则

定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。 问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需...

3326

扫描关注云+社区