Blog Archives

图书出版《R的极客理想-量化投资篇》

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹(Conan), 程序员Java,R,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-book3/

前言

终于等到R的极客理想系列,第三本《R的极客理想-量化投资篇》一书出版了。写书不仅是一个漫长的过程,更是知识的浓缩和再精华的过程;写书不仅把自己会的东西记录下来,还要站在读者的角度,让其他人也能看得懂;写书不同于写博客,不仅要保证超过5遍以上的审阅,还要遵守出版的各种规则,包括格式、文字、目录、图片,公式,代码,引用….

写书不是一件容易的事情,这是R的极客理想系列最后一本图书。希望更多的朋友都能静心下来,写本自己的书。尊重知识,就是尊重你的未来。

目录

  1. 写书体验
  2. 为什么要写这本书
  3. 读者对象
  4. 如何阅读本书
  5. 致谢

1. 写书体验

本书是我写的“R的极客理想”系列丛书的第三本,是R语言与金融量化投资领域结合的一本书,本书的主要写作目标就是把R语言的技术和实际的金融量化案例结合起来,让读者能切身的体会把知识变成真正的生产力。

本书撰写花了很长的时间才得以完成,因本书涉猎广泛,包括了大量地跨学科的知识,用通俗易懂的语言描述出来,并让读者更容易地理解并非易事,以致于我自己在写作过程中,有过数次想放弃的冲动。这本书最终完成,都源于每次看到读者在我博客中的留言,看到大家的对于知识的期待和对于我本人的鼓励,这些都是我把这项艰苦的事业完成,源源不断的动力和鞭策。有的同学开玩笑地留言说,“集齐全套图书,就可以召唤神龙了”。我真的非常感谢读者,对于图书的高度肯定和对我不断的支持。

在本书的写作过程中,我经历了一次创业的洗礼,体验了人生的大起和大落,这段特殊的经历也让我有了新目标和方向。每当我回忆整个的创业过程,都觉得自己太年轻了。光有满腔的热情和技术,只能让我把事情做起来,但是经验和阅历的不足,不能支撑我成为一个成功的创业者。天时,地利,人和,缺一不可。

图书介绍的网站http://fens.me/book,介绍了本书的基本情况,包括序、前方、目录、勘误、代码、试读、封面、交流等几个方面内容,读者有任何问题,都可以在网站中留言,并得到我的回复。同时,可以加QQ群:383275651,和更多的网友进行交流。网站还有视频专区(http://fens.me/video),提供我录制的各种视频课程,包括 R, Nodejs, Hadoop, 金融量化投资 等,视频收入仅用于网站的运营成本。

前两本上市后不仅再国内取得了不俗的成绩,获得了良好的口碑,而且英文版被美国知名的出版集团CRC引进,在北美市场也获得了读者的热捧,本书的英文版和繁体版随后也会在美国和中国台湾发行。

最后附上购买链接,各大网站都能买到,建议先去比比价:互动出版社京东当当亚马逊

当然,如果你需要一本签名的书,可以联系我订购,但是成本有点高,图书原价+货到付款;也可以带着书,到各种我参加的分享会来找我,我每年有不少的分享活动

2. 为什么要写这本书

本书撰写的一个主要思路是从IT人的角度,通过技术来切入金融市场,进行量化投资。发挥IT人的专注学习、乐于分享的精神,借助互联网快速传播知识,打破传统的金融壁垒。发挥“极客”的创造力,让知识变成生产力,让更多的有理想的IT人,能够有机会进入金融行业,推动金融行业的改革和创新。

但这不是一本简单易懂的书,因为量化投资是跨学科的领域。你需要有多学科的知识储备,才能胜任量化投资的工作。而本书所涉及的相关的内容,可能需要多本书籍的相关知识支撑才能描述完成。

阅读本书,不但需要你有R语言的使用经验,更需要有对金融市场知识的理解。本书主要介绍了三部分内容,涵盖金融市场,统计知识和IT技术。

  • 金融市场,包括了中国的金融二级市场环境的介绍、交易工具的使用、金融产品的交易规则、国内机构投研思路、策略和回测、基金会计等金融行业的基础知识。
  • 统计知识,包括了时间序列、一元线性回归、多元线性回归、自回归等统计和计量的模型算法。
  • IT技术,就是R语言相关的编程技术,金融量化程序包的使用,金融数据处理,金融数据模型的构建,量化策略的实现思路,R语言代码的编写等。

同时,本书使用了很多的真实案例,以中国实际的金融市场为背景,你会感觉到市场所带来的波动,国家宏观政策对于市场的影响,散户思维与专业投资者的差异,量化思路与主观思路对于市场的不同理解。

本书是我在实际投资研究中的总结,从金融理论模型,到市场特征检验,再到数学公式,R语言建模,再到历史数据回测,会计资产核算,最后进行实盘交易。通过R语言,可以很简单地实现我们脑子中的一个投资想法。类似的投资想法其实谁都有,利用IT人的技术优势,可以真正地与实际操作结合起来。

本书所涉及的金融产品,包括了股票、期货、债券、基金、现金管理等,跨越多个金融市场多种金融标的物。交易模型和交易策略,有基于市场技术指标的量价策略,有基于统计理论的套利策略,有基于金融产品规则的事件性策略;有针对全市场扫描的选股策略,也有高频交易的择时策略。相信本书,会另你感受到金融市场的魅力,以及技术优势能给我们带来的价值。

要想深入理解本书的每一篇的内容,可能你需要像我一样,不仅有技术的积累,还要真正地去金融市场做做交易,多和行业内的人进行沟通,不断地学习和思考。

让IT技术,提高金融的效率。

传统的交易员,都是凭借多年的交易训练,人工的每日盯盘,观察市场的变化。一个好的交易员,可以同时观测几个金融市场的几十个交易品种。随着金融产品的发展,股票市场已经达到3000多只股票,债券市场达到3000多只债券,公墓基金市场达到了6000多只基金,还有多种的金融衍生品,大量金融产品的发展,已经不是能依靠个人之力去消化和分析了。

通过计算机在全市场进行扫面,发现不合理的定价和交易机会,可以极大的提高交易员效率。一种理想化的设计,让程序来为我们交易赚钱,我们就可以去做自己喜欢的事情了。让技术变现,解放我们的生活。

本书中的原创观点和方法,都是基于理论研究在实践中的经验所得。实际上,长久以来我也在找这样的一本书,能够把书本上的理论模型与实际业务相结合,但并没有找到,或者并没有符合中国市场的实际案例应用,所以只能自己动手写一本。本书也有点像是自己的笔记,我也会经常翻翻,让自己的头脑始终保持清晰思路。

3. 读者对象

本书适合以下所有R语言工作者:

  • R语言的学习者和使用者(必读)
  • 金融宽客(Quant)(必读)
  • 计算机背景的金融量化爱好者(必读)
  • 数据分析背景的金融方向数据科学家(必读)
  • 统计背景的金融科研工作者
  • 金融行业从业者,券商研究员、分析师、基金经理
  • 回归中国市场的海外金融量化从业人员
  • 金融、统计、数据科学专业的学生

4. 如何阅读本书

本书分为三个部分,六个章节,每一个章节都是一块大的知识体系。

  • 第一部分是金融市场与金融理论(第1~2章),从了解金融开始,建立对金融认识的基本思路。
  • 第二部分是R语言数据处理与高性能计算(第3~4章),详细介绍了R语言进行数据处理的必备工具和使用方法。
  • 第三部分是金融策略实战(第5~6章),结合R语言技术和金融知识,解决金融量化领域的实际问题。

第一章,金融市场概述,为全书开篇,主要介绍了如何R语言做量化投资的思路和方法。量化投资是跨学科知识结合的一个方向,包括了R语言的技术层面的知识,基础学科的应用和金融市场的情况。R语言社区提供丰富的金融工具包,可以让我们快速构建量化投资的体系结构。本章内容以我个人的从业体会,从数据的角度观察中国的金融市场,发现机会,找到风口。

第二章,金融理论,主要介绍了金融经典理论模型和R语言的实现方法。用R语言深度解读,投资学理论和统计学理论在实际金融市场中的应用,包括4个基础理论模型,资本资产定价模型、一元回归性线模型、多元回归线性模型、自回归模型,希望这些基础理论模型可以帮助读者,找到理解金融市场的方法。

第三章,R语言数据处理。以R语言数据处理技术为核心,介绍了如何用R语言进行各种类型数据的处理方法,包括标准的结构化数据集的处理和字符数据集的处理,同时深入浅出地介绍了R语言数据处理方式,包括循环、分组、合并、管道、分词等的常用数据处理操作。

第四章,R语言高性能计算。R语言的性能问题一直是被大家所关心的,R本身有很多解决方案来提高性能,但由于R语言内核的单线程设计,让R本身的解决方案有飞跃式的性能提升是困难的。本章将介绍通过3种外部技术,来让R语言的性能达到生产环境的要求。

第五章,债券和回购。金融市场很大,不仅有股票,更大市场是债券。本章重点介绍了如何用R语言去进行债券分析,做一些债券投资和套利。低风险的债券投资,说不定是我们投资理财更好的选择。

第六章,量化投资策略案例。本章全部是综合的案例,从金融市场开始研究,到数学公式,R语言建模,历史数据回测,最后找到投资机会,是一套完整的从理论到实践的学习方法。祝大家在金融市场中玩的开心!

本书有很多综合运用的知识,在您阅读本书的时候,建议读者顺序阅读全部的章节。本书的一些技术实现,用到了我前两本书介绍的知识点,《R的极客理想-高级开发篇》和《R的极客理想-工具篇》,建议读者一起阅读。

5. 致谢

感谢在我最失意的时候,帮助我度过难关的朋友,北京千庄智金科技有限责任公司总经理张颂,量子金服CEO刘亚非,民生银行同事许斌。 感谢所有R语言的读者,以及社区的各位朋友,让我们通过R语言认识,并一起把知识进行传播。 感谢天善智能社区CEO梁勇,为本书提供赞助和推广。同时,感谢台湾銓智金融科技合伙人陈琪龙博士,复旦大学黄达教授,为本书写推荐序。感谢机械工业出版社华章公司的主编 杨福川 和编辑 李艺,帮助我审阅全部章节,让本书得以出版。

特别感谢我的爱人一直在鼓励我,最终让我走出了失意的阴影。感谢我的爸爸、妈妈,感谢你们对我工作上的支持和生活上的照顾!小宝宝,也在今年出生。

谨以此书献给我最亲爱的家人以及众多R语言爱好者们!祝大家阅读愉快,欢迎交流。

转载请注明出处:
http://blog.fens.me/r-book3/

打赏作者

2017微软技术暨生态大会:R语言搭建多因子体系

跨界知识聚会系列文章,“知识是用来分享和传承的”,各种会议、论坛、沙龙都是分享知识的绝佳场所。我也有幸作为演讲嘉宾参加了一些国内的大型会议,向大家展示我所做的一些成果。从听众到演讲感觉是不一样的,把知识分享出来,你才能收获更多。

关于作者

  • 张丹, 程序员R,Nodejs,Java
  • weibo:@Conan_Z
  • blog:http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/meeting-ms-20171103

前言

微软的技术大会,够规模,够档次,更切身地感受到,微软已经变得开放了!同时,微软股价创造了历史新高,比尔盖茨来华访问。

在本次大会上,我主要介绍的是开源技术R语言,在金融量化投资领域的应用。本次分享,仅仅从传播知识的角度,用IT人能够理解的语言,说出基金经理在做的事情

目录

  1. 我的演讲主题:R语言搭建多因子体系
  2. 会议体验和照片分享

1. 我的演讲主题:R语言搭建多因子体系

感谢微软对于MVP获得者的邀请,让MVP有展示个人能力的机会。我本次分享的主题为:R语言搭建多因子体系,主要内容来自我的一篇博文:R语言搭建多因子体系(未发布)。

分享主题的目录大纲如下:

  1. 故事开始
  2. 金融理论
  3. 多因子体系
  4. R语言建模
  5. 实例应用

本此分析主要是从金融的角度切入,介绍多因子的体系,进行选股,并通过R语言进行实现的。多因子方法选股,是目前主流的主动型基金的选股操作方法。本次分享,从一个故事引入,让没有金融背景的朋友,也能快速进入场景。用IT人能够理解的语言,说出基金经理在做的事情。

同时,我也在致力于推动R语言在中国金融领域的发展,让R可以给更多的用户使用,培养出更多的数据分析师。也希望让我们中国人的技术能够走出去到世界的舞台。希望多能认识志同道合的朋友,一起做一些事情。

2. 会议体验和照片分享

会议的主页:https://www.microsoft.com/china/techsummit/2017/

本次微软大会由百个主题组成,主要是微软的产品技术介绍。我被安装在11月03月下午的分享。让我没想到的是R语言相关的主题有3个,只不过大家的兴趣点似乎并不在数据分析或R语言。作为小众的R语言,还要有很长的路要走啊!

我的介绍和照片分享。

2.2 会议相关照片

本次的场地在 北京国际饭店会议中心,展位上也有各种新技术,和新厂商。

xbox和VR

金融解决方案

现代化工作模式

大学师弟,看起来比我压力还大。

本次大会办出世界企业的水平,希望明年有机会去微软总部西雅图,参加2018 MVP Global大会。我要赶紧准备签证去!

转载请注明出处:
http://blog.fens.me/meeting-ms-20171103

打赏作者

R语言数据科学新类型tibble

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹, 程序员R,Nodejs,Java
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-tibble/

前言

最近正在整理用R语言进行数据处理的操作方法,发现了 RStudio 公司开发的数据科学工具包tidyverse,一下子就把我吸引了。通过2天时间,我把tidyverse项目整体的学了一遍,给我的启发是非常大的。tidyverse 重新定义了数据科学的工作路径,而且路径上每个核心节点,都定义了对应的R包。这真是一项造福数据分析行业的工程,非常值得称赞!!

tidyverse个项目,包括了一系列的子项目,其中tibble被定义为取代传统data.frame的数据类型,完全有颠覆R的数据操作的可能。跟上R语言领袖的脚步,领先进入数据科学新的时代。

目录

  1. tibble介绍
  2. tibble安装
  3. tibble包的基本使用
  4. tibble的源代码分析

1. tibble介绍

tibble是R语言中一个用来替换data.frame类型的扩展的数据框,tibble继承了data.frame,是弱类型的,同时与data.frame有相同的语法,使用起来更方便。tibble包,也是由Hadley开发的R包。

tibble对data.frame做了重新的设定:

  • tibble,不关心输入类型,可存储任意类型,包括list类型
  • tibble,没有行名设置 row.names
  • tibble,支持任意的列名
  • tibble,会自动添加列名
  • tibble,类型只能回收长度为1的输入
  • tibble,会懒加载参数,并按顺序运行
  • tibble,是tbl_df类型

tibble的项目主页:https://github.com/tidyverse/tibble

2. tibble安装

本文所使用的系统环境

  • Win10 64bit
  • R: 3.2.3 x86_64-w64-mingw32/x64 b4bit

tibble是在CRAN发布的标准库,安装起来非常简单,2条命令就可以了。


~ R
> install.packages('tibble')
> library(tibble)

RStudio官方把tibble项目,集成到了tidyverse项目中了,官方建议直接安装tidyverse项目,这样整个用来做数据科学的库都会被下载下来。


~ R
> install.packages('tidyverse')
> library(tidyverse)
#> Loading tidyverse: ggplot2
#> Loading tidyverse: tibble
#> Loading tidyverse: tidyr
#> Loading tidyverse: readr
#> Loading tidyverse: purrr
#> Loading tidyverse: dplyr
#> Conflicts with tidy packages ----------------------------------------------
#> filter(): dplyr, stats
#> lag():    dplyr, stats

tidyverse项目,是一个包括了数据科学的一个集合工具项目,用于数据提取,数据清理,数据类型定义,数据处理,数据建模,函数化编程,数据可视化,包括了下面的包。

  • ggplot2, 数据可视化
  • dplyr, 数据处理
  • tidyr, 数据清理
  • readr, 数据提取
  • purrr, 函数化编程
  • tibble, 数据类型定义

tidyverse项目的地址:https://github.com/tidyverse/tidyverse。高效的使用R语言做数据科学,请参考开源图书 R for Data Science.

3. tibble包的基本使用

对于tibble包的使用,主要需要掌握创建、数据转型、数据查看、数据操作、与data.frame的区别点。复杂的数据处理功能,是dplyr项目来完成,下一篇讲dplyr的文章再给大家介绍。

3.1 创建tibble

创建一个tibble类型的data.frame是非常简单的,语法与传统的data.frame是类似的。


# 创建一个tibble类型的data.frame
> t1<-tibble(1:10,b=LETTERS[1:10]);t1
# A tibble: 10 x 2
   `1:10`     b
    <int> <chr>
 1      1     A
 2      2     B
 3      3     C
 4      4     D
 5      5     E
 6      6     F
 7      7     G
 8      8     H
 9      9     I
10     10     J

# 创建一个data.frame
> d1<-data.frame(1:10,b=LETTERS[1:10]);d1
   X1.10 b
1      1 A
2      2 B
3      3 C
4      4 D
5      5 E
6      6 F
7      7 G
8      8 H
9      9 I
10    10 J

从上面的输出可以看到tibble类型,会在输出时多一行,用来指定每一列的类型。

tibble用缩写定义了7种类型:

  • int,代表integer
  • dbl,代表double
  • chr,代表character向量或字符串。
  • dttm,代表日期+时间(a date + a time)
  • lgl,代表逻辑判断TRUE或者FALSE
  • fctr,代表因子类型factor
  • date,代表日期dates.

查看类型,发现tbl_df继承了tbl继承是data.frame,所以tibble是data.frame的子类型。


# t1为tbl_df类型
> class(t1)
[1] "tbl_df"     "tbl"        "data.frame"

# 是data.frame类型
> class(d1)
[1] "data.frame"

让我们多角度来观察t1变量。


# 判断是不是tibble类型
> is.tibble(t1)
[1] TRUE

# 查看t1的属性
> attributes(t1)
$names
[1] "1:10" "b"   

$class
[1] "tbl_df"     "tbl"        "data.frame"

$row.names
 [1]  1  2  3  4  5  6  7  8  9 10

# 查看t1的静态结构
> str(t1)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':	10 obs. of  2 variables:
 $ 1:10: int  1 2 3 4 5 6 7 8 9 10
 $ b   : chr  "A" "B" "C" "D" ...

通过文本排列来创建一个tibble


> tribble(
+   ~colA, ~colB,
+   "a",   1,
+   "b",   2,
+   "c",   3
+ )
# A tibble: 3 x 2
   colA  colB
  <chr> <dbl>
1     a     1
2     b     2
3     c     3

通过vector创建tibble


> tibble(letters)
# A tibble: 26 x 1
   letters
     <chr>
 1       a
 2       b
 3       c
 4       d
 5       e
 6       f
 7       g
 8       h
 9       i
10       j
# ... with 16 more rows

通过data.frame创建tibble,这时就会报错了。


> tibble(data.frame(1:5))
Error: Column `data.frame(1:5)` must be a 1d atomic vector or a list

通过list创建tibble


> tibble(x = list(diag(1), diag(2)))
# A tibble: 2 x 1
              x
         <list>
1 <dbl [1 x 1]>
2 <dbl [2 x 2]>

我们看到tibble其实是存储list类型,这是data.frame做不到的。

通过一个tibble,创建另一个tibble,这时也会报错了。

> tibble(x = tibble(1, 2, 3))
Error: Column `x` must be a 1d atomic vector or a list

3.2 数据类型转换

tibble是一个新的类型,R语言中大部分的数据都是基于原有的数据类型,所以原有数据类型与tiblle类型的转换就显的非常重要了。

把一个data.frame的类型的转换为tibble类型


# 定义一个data.frame类型变量
> d1<-data.frame(1:5,b=LETTERS[1:5]);d1
  X1.5 b
1    1 A
2    2 B
3    3 C
4    4 D
5    5 E

# 把data.frame转型为tibble
> d2<-as.tibble(d1);d2
# A tibble: 5 x 2
   X1.5      b
  <int> <fctr>
1     1      A
2     2      B
3     3      C
4     4      D
5     5      E

# 再转回data.frame
> as.data.frame(d2)
  X1.5 b
1    1 A
2    2 B
3    3 C
4    4 D
5    5 E

我们可以看到tibble与data.frame的转型是非常平滑的,一个转型函数就够,不需要中间做任何的特殊处理。

把一个vector转型为tibble类型,但是不能再转回vector了。


# vector转型到tibble
> x<-as.tibble(1:5);x
# A tibble: 5 x 1
  value
  <int>
1     1
2     2
3     3
4     4
5     5

# tibble转型到vector, 不成功
> as.vector(x)
# A tibble: 5 x 1
  value
  <int>
1     1
2     2
3     3
4     4
5     5

把list转型为tibble。


# 把list转型为tibble
> df <- as.tibble(list(x = 1:500, y = runif(500), z = 500:1));df
# A tibble: 500 x 3
       x          y     z
   <int>      <dbl> <int>
 1     1 0.59141749   500
 2     2 0.61926125   499
 3     3 0.06879729   498
 4     4 0.69579561   497
 5     5 0.05087461   496
 6     6 0.63172517   495
 7     7 0.41808985   494
 8     8 0.78110219   493
 9     9 0.95279741   492
10    10 0.98930640   491
# ... with 490 more rows

# 把tibble再转为list
> str(as.list(df))
List of 3
 $ x: int [1:500] 1 2 3 4 5 6 7 8 9 10 ...
 $ y: num [1:500] 0.5914 0.6193 0.0688 0.6958 0.0509 ...
 $ z: int [1:500] 500 499 498 497 496 495 494 493 492 491 ...

tibble与list的转型也是非常平滑的,一个转型函数就够。

把matrix转型为tibble。


# 生成一个matrix
> m <- matrix(rnorm(15), ncol = 5)

# matrix转为tibble
> df <- as.tibble(m);df
# A tibble: 3 x 5
          V1         V2         V3         V4         V5
                               
1  0.8436494  2.1420238  0.2690392 -0.4752708 -0.2334994
2  1.0363340  0.8653771 -0.3200777 -1.7400856  1.2253651
3 -0.2170344 -1.1346455  0.2204718  1.2189431  0.7020156

# tibble转为matrix
> as.matrix(df)
             V1         V2         V3         V4         V5
[1,]  0.8436494  2.1420238  0.2690392 -0.4752708 -0.2334994
[2,]  1.0363340  0.8653771 -0.3200777 -1.7400856  1.2253651
[3,] -0.2170344 -1.1346455  0.2204718  1.2189431  0.7020156

从上面的转型测试可以看到,tibble类型是非常友好的,可以与data.frame, list, matrix 进行相互转型操作。tibble与vector是不能进行直接转型的,这与data.frame的行为是一致的,如果需要转型,我们可以分别取出每一列进行拼接,或转为matrix再操作。

3.3 tibble数据查询

通常我们是str()函数来观察数据的静态组成结果,在tibble包提供了一个glimpse(),可以方便我们来观察tibble和data.frame类型的数据。

比较glimpse()和str()对于data.frame的数据查看输出


> glimpse(mtcars)
Observations: 32
Variables: 11
$ mpg   21.0, 21.0, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.8, 19.2, 17.8, 16.4, 17....
$ cyl   6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, ...
$ disp  160.0, 160.0, 108.0, 258.0, 360.0, 225.0, 360.0, 146.7, 140.8, 167.6, 167.6...
$ hp    110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123, 180, 180, 180, 205, 215...
$ drat  3.90, 3.90, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92, 3.92, 3.92, 3.07, 3.0...
$ wt    2.620, 2.875, 2.320, 3.215, 3.440, 3.460, 3.570, 3.190, 3.150, 3.440, 3.440...
$ qsec  16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20.00, 22.90, 18.30, 18.90...
$ vs    0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, ...
$ am    1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, ...
$ gear  4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, ...
$ carb  4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2, 1, 1, 2, 2, 4, 2, ...

# 打印静态结构
> str(mtcars)
'data.frame':	32 obs. of  11 variables:
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
 $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

比较glimpse()和str()对于tibble的数据查看输出。


# 新建tibble
> df <- tibble(x = rnorm(500), y = rep(LETTERS[1:25],20))

# 查看df
> glimpse(df)
Observations: 500
Variables: 2
$ x  -0.3295530, -2.0440424, 0.1444697, 0.8752439, 1.7705952, 0.5898253, 0.1991844,...
$ y  "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"...

# 查看df静态结构
> str(df)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':	500 obs. of  2 variables:
 $ x: num  -0.33 -2.044 0.144 0.875 1.771 ...
 $ y: chr  "A" "B" "C" "D" ...

按列出数据,一层[]返回的结果还是tibbe,二层[]与$返回的结果为列组成的向量。


> df <- tibble(x = 1:3, y = 3:1)

# 按列取,返回tibble
> df[1]
# A tibble: 3 x 1
      x
  <int>
1     1
2     2
3     3

# 按列取,返回向量
> df[[1]]
[1] 1 2 3
> df$x
[1] 1 2 3

按行取数据,这时一定要用,来做分隔符


# 取第一行
> df[1,]
# A tibble: 1 x 2
      x     y
  <int> <int>
1     1     3

# 取前2行
> df[1:2,]
# A tibble: 2 x 2
      x     y
  <int> <int>
1     1     3
2     2     2

# 取第二列的2,3行
> df[2:3,2]
# A tibble: 2 x 1
      y
  <int>
1     2
2     1

3.4 tibble数据操作

增加一列。


# 创建一个tibble
> df <- tibble(x = 1:3, y = 3:1);df
# A tibble: 3 x 2
      x     y
  <int> <int>
1     1     3
2     2     2
3     3     1

# 增加一列
> add_column(df, z = -1:1, w = 0)
# A tibble: 3 x 4
      x     y     z     w
  <int> <int> <int> <dbl>
1     1     3    -1     0
2     2     2     0     0
3     3     1     1     0

增加一行,还是基于上面生成的df变量。


# 在最后,增加一行
> add_row(df, x = 99, y = 9)
# A tibble: 4 x 2
      x     y
  <dbl> <dbl>
1     1     3
2     2     2
3     3     1
4    99     9

# 插入第二行,增加一行
> add_row(df, x = 99, y = 9, .before = 2)
# A tibble: 4 x 2
      x     y
  <dbl> <dbl>
1     1     3
2    99     9
3     2     2
4     3     1

3.5 tibble与data.frame的区别

列名,可以自由定义,并且会自动补全。


> tb <- tibble(
+   `:)` = "smile",
+   ` ` = "space",
+   `2000` = "number",
+   `列名` = "hi",
+   1,1L
+ )
> tb
# A tibble: 1 x 6
   `:)`   ` ` `2000`  列名   `1`  `1L`
  <chr> <chr>  <chr> <chr> <dbl> <int>
1 smile space number    hi     1     1

数据,按顺序执行懒加载。


> a <- 1:5
> tibble(a, b = a * 2)
# A tibble: 5 x 2
      a     b
  <int> <dbl>
1     1     2
2     2     4
3     3     6
4     4     8
5     5    10

打印输出控制,tibble的打印控制被重写了,所以执行print()函数时,模型会先进行类型匹配,然后调用print.tbl()。


# 创建tiblle
> tb<-tibble(a=1:5, b = a * 2, c=NA, d='a', e=letters[1:5])

# 打印前10行,不限宽度
> print(tb,n = 10, width = Inf)
# A tibble: 5 x 5
      a     b     c     d     e
  <int> <dbl> <lgl> <chr> <chr>
1     1     2    NA     a     a
2     2     4    NA     a     b
3     3     6    NA     a     c
4     4     8    NA     a     d
5     5    10    NA     a     e

# 打印前3行,宽度30
> print(tb,n = 3, width = 30)
# A tibble: 5 x 5
      a     b     c     d
  <int> <dbl> <lgl> <chr>
1     1     2    NA     a
2     2     4    NA     a
3     3     6    NA     a
# ... with 2 more rows, and 1
#   more variables: e 

# 用print函数,打印data.frame
> df<-data.frame(tb)
> print(df)
  a  b  c d e
1 1  2 NA a a
2 2  4 NA a b
3 3  6 NA a c
4 4  8 NA a d
5 5 10 NA a e

3.7 特殊的函数

lst,创建一个list,具有tibble特性的list。 lst函数的工作原理,类似于执行[list()],这样的操作。


# 创建一个list,懒加载,顺序执行
> lst(n = 5, x = runif(n))
$n
[1] 5
$x
[1] 0.6417069 0.2674489 0.5610810 0.1771051 0.1504583

enframe,快速创建tibble。enframe提供了一个模板,只有2列name和value,快速地把2个向量匹配的tibble中,可以按行生成或按列生成。


# 按列生成
> enframe(1:3)
# A tibble: 3 x 2
   name value
  <int> <int>
1     1     1
2     2     2
3     3     3

# 按行生成
> enframe(c(a = 5, b = 7))
# A tibble: 2 x 2
   name value
  <chr> <dbl>
1     a     5
2     b     7

deframe,把tibble反向转成向量,这个函数就实现了,tibble到向量的转换。它默认把name列为索引,用value为值。


# 生成tibble
> df<-enframe(c(a = 5, b = 7));df
# A tibble: 2 x 2
   name value
  <chr> <dbl>
1     a     5
2     b     7

# 转为vector
> deframe(df)
a b 
5 7 

3.8 用于处理data.frame函数

tibble还提供了一些用于处理data.frame的函数。


# 创建data.frame
> df<-data.frame(x = 1:3, y = 3:1)

# 判断是否有叫x的列
> has_name(df,'x')
[1] TRUE

# 判断是否有行名
> has_rownames(df)
[1] FALSE

# 给df增加行名
> row.names(df)<-LETTERS[1:3];df
  x y
A 1 3
B 2 2
C 3 1

# 判断是否有行名
> has_rownames(df)
[1] TRUE

# 去掉行名
> remove_rownames(df)
  x y
1 1 3
2 2 2
3 3 1

# 把行名转换为单独的一列
> df2<-rownames_to_column(df, var = "rowname");df2
  rowname x y
1       A 1 3
2       B 2 2
3       C 3 1

# 把一列设置为行名
> column_to_rownames(df2, var = "rowname")
  x y
A 1 3
B 2 2
C 3 1

# 把行索引转换为单独的一列
> rowid_to_column(df, var = "rowid")
  rowid x y
1     1 1 3
2     2 2 2
3     3 3 1

这些data.frame的工具函数,我猜是用于data.frame到tibble的数据类型转换用的,因为tiblle是没有行名的。

4. tibble的源代码分析

对于tibble包的深入理解,我们需要分析tibble包底层的源代码,以及设计原理。我们打开github上是tibble项目,找到tibble.R的源代码,先来了解一下tibble类型的定义。

找到tibble函数的定义:


tibble <- function(...) {
  xs <- quos(..., .named = TRUE)
  as_tibble(lst_quos(xs, expand = TRUE))
}

tibble函数的构成是非常简单地,用quos()和lst_quos()函数来分割参数,再用as_tibble()函数,生成tibble类型。

我们再找到as_tibble函数的定义:


as_tibble <- function(x, ...) {
  UseMethod("as_tibble")
}

as_tibble.tbl_df <- function(x, ..., validate = FALSE) {
  if (validate) return(NextMethod())
  x
}

这个函数是一个S3类型的函数,可以S3面向对象类型的方法,来查找tibble相关的重写的函数。关于S3类型的详细介绍,请参与文章R语言基于S3的面向对象编程


> methods(generic.function=as_tibble)
[1] as_tibble.data.frame* as_tibble.default*    as_tibble.list*       as_tibble.matrix*    
[5] as_tibble.NULL*       as_tibble.poly*       as_tibble.table*      as_tibble.tbl_df*    
[9] as_tibble.ts*    

利用S3的查询函数,把整个tibble类型定义的泛型化函数都找到了。

接下来,我们继续到tbl_df的类型的定义


#' @importFrom methods setOldClass
setOldClass(c("tbl_df", "tbl", "data.frame"))

最后,这样就明确了tbl_df是类的定义,包括了属性和方法,而tibble是实例化的对象。通过对tibble函数的源代码分析,了解tibble本身的结构是怎么样的。那么再接下来,就是如何利用tibble来进行用于数据科学的数据处理过程。请继续阅读下一篇文章:R语言数据科学数据处理包dplyr。

转载请注明出处:
http://blog.fens.me/r-tibble/

打赏作者

用R语言把数据玩出花样

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹, 程序员R,Nodejs,Java
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-transform/

前言

作为数据分析师,每天都有大量的数据需要处理,我们会根据业务的要求做各种复杂的报表,包括了分组、排序、过滤、转置、差分、填充、移动、合并、分裂、分布、去重、找重、填充 等等的操作。

有时为了计算一个业务指标,你的SQL怎么写都不会少于10行时,另外你可能也会抱怨Excel功能不够强大,这个时候R语言绝对是不二的选择了。用R语言可以高效地、优雅地解决数据处理的问题,让R来帮你打开面向数据的思维模式。

目录

  1. 为什么要用R语言做数据处理?
  2. 数据处理基础
  3. 个性化的数据变换需求

1. 为什么要用R语言做数据处理?

R语言是非常适合做数据处理的编程语言,因为R语言的设计理念,就是面向数据的,为了解决数据问题。读完本文,相信你就能明白,什么是面向数据的设计了。

一个BI工程师每天的任务,都是非常繁琐的数据处理,如果用Java来做简直就是折磨,但是换成R语言来做,你会找到乐趣的。

当接到一个数据处理的任务后,我们可以把任务拆解为很多小的操作,包括了分组、排序、过滤、转置、差分、填充、移动、合并、分裂、分布、去重、找重等等的操作。对于实际应用的复杂的操作来说,就是把这些小的零碎的操作,拼装起来就好了。

在开始之前,我们要先了解一下R语言支持的数据类型,以及这些常用类型的特点。对于BI的数据处理的工作来说,可能有4种类型是最常用的,分别是向量、矩阵、数据框、时间序列。

  • 向量 Vector : c()
  • 矩阵 Matrix: matrix()
  • 数据框 DataFrame: data.frame()
  • 时间序列 XTS: xts()

我主要是用R语言来做量化投资,很多的时候,都是和时间序列类型数据打交道,所以我把时间序列,也定义为R语言最常用的数据处理的类型。时间序列类型,使用的是第三方包xts中定义的类型。

2. 数据处理基础

本机的系统环境:

  • Win10 64bit
  • R: version 3.2.3 64bit

2.1 创建一个数据集

创建一个向量数据集。


> x<-1:20;x
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20

创建一个矩阵数据集。


> m<-matrix(1:40,ncol=5);m
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    9   17   25   33
[2,]    2   10   18   26   34
[3,]    3   11   19   27   35
[4,]    4   12   20   28   36
[5,]    5   13   21   29   37
[6,]    6   14   22   30   38
[7,]    7   15   23   31   39
[8,]    8   16   24   32   40

创建一个数据框数据集。


> df<-data.frame(a=1:5,b=c('A','A','B','B','A'),c=rnorm(5));df
  a b          c
1 1 A  1.1519118
2 2 A  0.9921604
3 3 B -0.4295131
4 4 B  1.2383041
5 5 A -0.2793463

创建一个时间序列数据集,时间序列使用的第三方的xts类型。关于xts类型的详细介绍,请参考文章 可扩展的时间序列xts。


> library(xts)
> xts(1:10,order.by=as.Date('2017-01-01')+1:10)
           [,1]
2017-01-02    1
2017-01-03    2
2017-01-04    3
2017-01-05    4
2017-01-06    5
2017-01-07    6
2017-01-08    7
2017-01-09    8
2017-01-10    9
2017-01-11   10

2.2 查看数据概况

通常进行数据分析的第一步是,查看一下数据的概况信息,在R语言里可以使用summary()函数来完成。


# 查看矩阵数据集的概况
> m<-matrix(1:40,ncol=5)
> summary(m)
       V1             V2              V3              V4              V5       
 Min.   :1.00   Min.   : 9.00   Min.   :17.00   Min.   :25.00   Min.   :33.00  
 1st Qu.:2.75   1st Qu.:10.75   1st Qu.:18.75   1st Qu.:26.75   1st Qu.:34.75  
 Median :4.50   Median :12.50   Median :20.50   Median :28.50   Median :36.50  
 Mean   :4.50   Mean   :12.50   Mean   :20.50   Mean   :28.50   Mean   :36.50  
 3rd Qu.:6.25   3rd Qu.:14.25   3rd Qu.:22.25   3rd Qu.:30.25   3rd Qu.:38.25  
 Max.   :8.00   Max.   :16.00   Max.   :24.00   Max.   :32.00   Max.   :40.00  

# 查看数据框数据集的概况信息
> df<-data.frame(a=1:5,b=c('A','A','B','B','A'),c=rnorm(5))
> summary(df)
       a     b           c          
 Min.   :1   A:3   Min.   :-1.5638  
 1st Qu.:2   B:2   1st Qu.:-1.0656  
 Median :3         Median :-0.2273  
 Mean   :3         Mean   :-0.1736  
 3rd Qu.:4         3rd Qu.: 0.8320  
 Max.   :5         Max.   : 1.1565  

通过查看概况,可以帮助我们简单了解数据的一些统计特征。

2.3 数据合并

我们经常需要对于数据集,进行合并操作,让数据集满足处理的需求。对于不同类型的数据集,有不同的处理方法。

向量类型


> x<-1:5
> y<-11:15
> c(x,y)
 [1]  1  2  3  4  5 11 12 13 14 15

数据框类型的合并操作。


> df<-data.frame(a=1:5,b=c('A','A','B','B','A'),c=rnorm(5));df
  a b          c
1 1 A  1.1519118
2 2 A  0.9921604
3 3 B -0.4295131
4 4 B  1.2383041
5 5 A -0.2793463

# 合并新行
> rbind(df,c(11,'A',222))
   a b                  c
1  1 A    1.1519117540872
2  2 A  0.992160365445798
3  3 B -0.429513109491881
4  4 B   1.23830410085338
5  5 A -0.279346281854269
6 11 A                222

# 合并新列
> cbind(df,x=LETTERS[1:5])
  a b          c x
1 1 A  1.1519118 A
2 2 A  0.9921604 B
3 3 B -0.4295131 C
4 4 B  1.2383041 D
5 5 A -0.2793463 E

# 合并新列
> merge(df,LETTERS[3:5])
   a b          c y
1  1 A  1.1519118 C
2  2 A  0.9921604 C
3  3 B -0.4295131 C
4  4 B  1.2383041 C
5  5 A -0.2793463 C
6  1 A  1.1519118 D
7  2 A  0.9921604 D
8  3 B -0.4295131 D
9  4 B  1.2383041 D
10 5 A -0.2793463 D
11 1 A  1.1519118 E
12 2 A  0.9921604 E
13 3 B -0.4295131 E
14 4 B  1.2383041 E
15 5 A -0.2793463 E

2.4 累计计算

累计计算,是很常用的一种计算方法,就是把每个数值型的数据,累计求和或累计求积,从而反应数据的增长的一种特征。


# 向量x
> x<-1:10;x
 [1]  1  2  3  4  5  6  7  8  9 10

# 累计求和
> cum_sum<-cumsum(x)

# 累计求积
> cum_prod<-cumprod(x)

# 拼接成data.frame
> data.frame(x,cum_sum,cum_prod)
    x cum_sum cum_prod
1   1       1        1
2   2       3        2
3   3       6        6
4   4      10       24
5   5      15      120
6   6      21      720
7   7      28     5040
8   8      36    40320
9   9      45   362880
10 10      55  3628800

我们通常用累计计算,记录中间每一步的过程,看到的数据处理过程的特征。

2.5 差分计算

差分计算,是用向量的后一项减去前一项,所获得的差值,差分的结果反映了离散量之间的一种变化。


> x<-1:10;x
 [1]  1  2  3  4  5  6  7  8  9 10

# 计算1阶差分
> diff(x)
[1] 1 1 1 1 1 1 1 1 1

# 计算2阶差分
> diff(x,2)
[1] 2 2 2 2 2 2 2 2

# 计算2阶差分,迭代2次
> diff(x,2,2)
[1] 0 0 0 0 0 0

下面做一个稍微复杂一点的例子,通过差分来发现数据的规律。


# 对向量2次累积求和
> x <- cumsum(cumsum(1:10));x
 [1]   1   4  10  20  35  56  84 120 165 220

# 计算2阶差分
> diff(x, lag = 2)
[1]   9  16  25  36  49  64  81 100

# 计算1阶差分,迭代2次
> diff(x, differences = 2)
[1]  3  4  5  6  7  8  9 10

# 同上
> diff(diff(x))
[1]  3  4  5  6  7  8  9 10

差分其实是很常见数据的操作,但这种操作是SQL很难表达的,所以可能会被大家所忽视。

2.6 分组计算

分组是SQL中,支持的一种数据变换的操作,对应于group by的语法。

比如,我们写一个例子。创建一个数据框有a,b,c的3列,其中a,c列为数值型,b列为字符串,我们以b列分组,求出a列与c的均值。


# 创建数据框
> df<-data.frame(a=1:5,b=c('A','A','B','B','A'),c=rnorm(5));df
  a b           c
1 1 A  1.28505418
2 2 A -0.04687263
3 3 B  0.25383533
4 4 B  0.70145787
5 5 A -0.11470372

# 执行分组操作
> aggregate(. ~ b, data = df, mean)
  b        a         c
1 A 2.666667 0.3744926
2 B 3.500000 0.4776466

同样的数据集,以b列分组,对a列求和,对c列求均值。当对不同列,进行不同的操作时,我们同时也需要换其他函数来处理。


# 加载plyr库
> library(plyr)

# 执行分组操作
> ddply(df,.(b),summarise,
+       sum_a=sum(a),
+       mean_c=mean(c))
  b sum_a      mean_c
1 A     8 -0.05514761
2 B     7  0.82301276

生成的结果,就是按b列进行分组后,a列求和,c列求均值。

2.7 分裂计算

分裂计算,是把一个向量按照一列规则,拆分成多个向量的操作。

如果你想把1:10的向量,按照单双数,拆分成2个向量。


> split(1:10, 1:2)
$`1`
[1] 1 3 5 7 9

$`2`
[1]  2  4  6  8 10

另外,可以用因子类型来控制分裂。分成2步操作,第一步先分成与数据集同样长度的因子,第二步进行分裂,可以把一个大的向量拆分成多个小的向量。


# 生成因子规则
> n <- 3; size <- 5
> fat <- factor(round(n * runif(n * size)));fat
 [1] 2 3 2 1 1 0 0 2 0 1 2 3 1 1 1
Levels: 0 1 2 3

# 生成数据向量
> x <- rnorm(n * size);x
 [1]  0.68973936  0.02800216 -0.74327321  0.18879230 -1.80495863  1.46555486  0.15325334  2.17261167  0.47550953
[10] -0.70994643  0.61072635 -0.93409763 -1.25363340  0.29144624 -0.44329187

# 对向量以因子的规则进行拆分
> split(x, fat)
$`0`
[1] 1.4655549 0.1532533 0.4755095

$`1`
[1]  0.1887923 -1.8049586 -0.7099464 -1.2536334  0.2914462 -0.4432919

$`2`
[1]  0.6897394 -0.7432732  2.1726117  0.6107264

$`3`
[1]  0.02800216 -0.93409763

这种操作可以非常有效地,对数据集进行分类整理,比if..else的操作,有本质上的提升。

2.8 排序

排序是所有数据操作中,最常见一种需求了。在R语言中,你可以很方便的使用排序的功能,并不用考虑时间复杂度与空间复杂度的问题,除非你自己非要用for循环来实现。

对向量进行排序。


# 生成一个乱序的向量
> x<-sample(1:10);x
 [1]  6  2  5  1  9 10  8  3  7  4

# 对向量排序 
> x[order(x)]
 [1]  1  2  3  4  5  6  7  8  9 10

以数据框某一列进行排序。


> df<-data.frame(a=1:5,b=c('A','A','B','B','A'),c=rnorm(5));df
  a b          c
1 1 A  1.1780870
2 2 A -1.5235668
3 3 B  0.5939462
4 4 B  0.3329504
5 5 A  1.0630998

# 自定义排序函数 
> order_df<-function(df,col,decreasing=FALSE){
+     df[order(df[,c(col)],decreasing=decreasing),]
+ }

# 以c列倒序排序
> order_df(df,'c',decreasing=TRUE)
  a b          c
1 1 A  1.1780870
5 5 A  1.0630998
3 3 B  0.5939462
4 4 B  0.3329504
2 2 A -1.5235668

排序的操作,大多都是基于索引来完成的,用order()函数来生成索引,再匹配的数据的数值上面。

2.9 去重与找重

去重,是把向量中重复的元素过滤掉。找重,是把向量中重复的元素找出来。


> x<-c(3:6,5:8);x
[1] 3 4 5 6 5 6 7 8

# 去掉重复元素
> unique(x)
[1] 3 4 5 6 7 8

# 找到重复元素,索引位置
> duplicated(x)
[1] FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE

# 找到重复元素
> x[duplicated(x)]
[1] 5 6

2.10 转置

转置是一个数学名词,把行和列进行互换,一般用于对矩阵的操作。


# 创建一个3行5列的矩阵
> m<-matrix(1:15,ncol=5);m
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    4    7   10   13
[2,]    2    5    8   11   14
[3,]    3    6    9   12   15

# 转置后,变成5行3列的矩阵
> t(m)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9
[4,]   10   11   12
[5,]   13   14   15

2.11 过滤

过滤,是对数据集按照某种规则进行筛选,去掉不符合条件的数据,保留符合条件的数据。对于NA值的操作,主要都集中在了过滤操作和填充操作中,因此就不在单独介绍NA值的处理了。


# 生成数据框
> df<-data.frame(a=c(1,NA,NA,2,NA),
+     b=c('B','A','B','B',NA),
+     c=c(rnorm(2),NA,NA,NA));df
   a    b          c
1  1    B -0.3041839
2 NA    A  0.3700188
3 NA    B         NA
4  2    B         NA
5 NA <NA>         NA

# 过滤有NA行的数据
> na.omit(df)
  a b          c
1 1 B -0.3041839

# 过滤,保留b列值为B的数据
> df[which(df$b=='B'),]
   a b          c
1  1 B -0.3041839
3 NA B         NA
4  2 B         NA

过滤,类似与SQL语句中的 WHERE 条件语句,如果你用100个以上的过滤条件,那么你的程序就会比较复杂了,最好想办法用一些巧妙的函数或者设计模式,来替换这些过滤条件。

2.12 填充

填充,是一个比较有意思的操作,你的原始数据有可能会有缺失值NA,在做各种计算时,就会出现有问题。一种方法是,你把NA值都去掉;另外一种方法是,你把NA值进行填充后再计算。那么在填充值时,就有一些讲究了。

把NA值进行填充。


# 生成数据框
> df<-data.frame(a=c(1,NA,NA,2,NA),
+      b=c('B','A','B','B',NA),
+      c=c(rnorm(2),NA,NA,NA));df
   a    b          c
1  1    B  0.2670988
2 NA    A -0.5425200
3 NA    B         NA
4  2    B         NA
5 NA <NA>         NA

# 把数据框a列的NA,用9进行填充
> na.fill(df$a,9)
[1] 1 9 9 2 9

# 把数据框中的NA,用1进行填充
> na.fill(df,1)
     a      b      c           
[1,] " 1"   "B"    " 0.2670988"
[2,] "TRUE" "A"    "-0.5425200"
[3,] "TRUE" "B"    "TRUE"      
[4,] " 2"   "B"    "TRUE"      
[5,] "TRUE" "TRUE" "TRUE"     

填充时,有时并不是用某个固定的值,而是需要基于某种规则去填充。


# 生成一个zoo类型的数据
> z <- zoo(c(2, NA, 1, 4, 5, 2), c(1, 3, 4, 6, 7, 8));z
 1  3  4  6  7  8 
 2 NA  1  4  5  2 

# 对NA进行线性插值
> na.approx(z) 
       1        3        4        6        7        8 
2.000000 1.333333 1.000000 4.000000 5.000000 2.000000 

# 对NA进行线性插值
> na.approx(z, 1:6)
  1   3   4   6   7   8 
2.0 1.5 1.0 4.0 5.0 2.0 

# 对NA进行样条插值
> na.spline(z)
        1         3         4         6         7         8 
2.0000000 0.1535948 1.0000000 4.0000000 5.0000000 2.0000000 

另外,我们可以针对NA的位置进行填充,比如用前值来填充或后值来填充。


> df
   a    b          c
1  1    B  0.2670988
2 NA    A -0.5425200
3 NA    B         NA
4  2    B         NA
5 NA <NA>         NA

# 用当前列中,NA的前值来填充
> na.locf(df)
   a b          c
1  1 B  0.2670988
2  1 A -0.5425200
3  1 B -0.5425200
4  2 B -0.5425200
5  2 B -0.5425200

# 用当前列中,NA的后值来填充
> na.locf(df,fromLast=TRUE)
   a b          c
1  1 B  0.2670988
2  2 A -0.5425200
3  2 B       <NA>
4  2 B       <NA>

2.13 计数

计数,是统计同一个值出现的次数。


# 生成30个随机数的向量
> set.seed(0)
> x<-round(rnorm(30)*5);x
 [1]  6 -2  7  6  2 -8 -5 -1  0 12  4 -4 -6 -1 -1 -2  1 -4  2 -6 -1  2  1  4  0  3  5 -3 -6  0

# 统计每个值出现的次数
> table(x)
x
-8 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7 12 
 1  3  1  2  1  2  4  3  2  3  1  2  1  2  1  1 

用直方图画出。


> hist(x,xlim = c(-10,13),breaks=20)

2.14 统计分布

统计分布,是用来判断数据是否是满足某种统计学分布,如果能够验证了,那么我们就可以用到这种分布的特性来理解我们的数据集的情况了。常见的连续型的统计分布有9种,其中最常用的就是正态分布的假设。关于统计分布的详细介绍,请参考文章 常用连续型分布介绍及R语言实现

  • runif() :均匀分布
  • rnorm() :正态分布
  • rexp() :指数分布
  • rgamma() :伽马分布
  • rweibull() :韦伯分布
  • rchisq() :卡方分布
  • rf() :F分布
  • rt() :T分布
  • rbeta() :贝塔分布

统计模型定义的回归模型,就是基于正态分布的做的数据假设,如果残差满足正态分布,模型的指标再漂亮都是假的。如果你想进一步了解回归模型,请参考文章R语言解读一元线性回归模型

下面用正态分布,来举例说明一下。假设我们有一组数据,是人的身高信息,我们知道平均身高是170cm,然后我们算一下,这组身高数据是否满足正态分布。


# 生成身高数据
> set.seed(1)
> x<-round(rnorm(100,170,10))
> head(x,20)
 [1] 164 172 162 186 173 162 175 177 176 167 185 174 164 148 181 170 170 179 178 176

# 画出散点图 
> plot(x)

通过散点图来观察,发现数据是没有任何规律。接下来,我们进行正态分布的检验,Shapiro-Wilk进行正态分布检验。


> shapiro.test(x)
	Shapiro-Wilk normality test
data:  x
W = 0.99409, p-value = 0.9444

该检验原假设为H0:数据集符合正态分布,统计量W为。统计量W的最大值是1,越接近1,表示样本与正态分布越匹配。p值,如果p-value小于显著性水平α(0.05),则拒绝H0。检验结论: W接近1,p-value>0.05,不能拒绝原假设,所以数据集S符合正态分布!

同时,我们也可以用QQ图,来做正态分布的检验。


> qqnorm(x)
> qqline(x,col='red')

图中,散点均匀的分布在对角线,则说明这组数据符合正态分布。

为了,更直观地对正态分布的数据进行观察,我们可以用上文中计数操作时,使用的直方图进行观察。


> hist(x,breaks=10)

通过计数的方法,发现数据形状如钟型,中间高两边低,中间部分的数量占了95%,这就是正态的特征。当判断出,数据是符合正态分布后,那么才具备了可以使用一些的模型的基础。

2.15 数值分段

数值分段,就是把一个连续型的数值型数据,按区间分割为因子类型的离散型数据。


> x<-1:10;x
 [1]  1  2  3  4  5  6  7  8  9 10

# 把向量转换为3段因子,分别列出每个值对应因子
> cut(x, 3)
 [1] (0.991,4] (0.991,4] (0.991,4] (0.991,4] (4,7]     (4,7]     (4,7]     (7,10]    (7,10]    (7,10]   
Levels: (0.991,4] (4,7] (7,10]

# 对因子保留2位精度,并支持排序
> cut(x, 3, dig.lab = 2, ordered = TRUE)
 [1] (0.99,4] (0.99,4] (0.99,4] (0.99,4] (4,7]    (4,7]    (4,7]    (7,10]   (7,10]   (7,10]  
Levels: (0.99,4] < (4,7] < (7,10]

2.16 集合操作

集合操作,是对2个向量的操作,处理2个向量之间的数值的关系,找到包含关系、取交集、并集、差集等。


# 定义2个向量x,y
> x<-c(3:8,NA);x
[1]  3  4  5  6  7  8 NA
> y<-c(NA,6:10,NA);y
[1] NA  6  7  8  9 10 NA

# 判断x与y重复的元素的位置
> is.element(x, y)
[1] FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE

# 判断y与x重复的元素的位置
> is.element(y, x)
[1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE  TRUE

# 取并集
> union(x, y)
[1]  3  4  5  6  7  8 NA  9 10

# 取交集
> intersect(x, y)
[1]  6  7  8 NA

# 取x有,y没有元素
> setdiff(x, y)
[1] 3 4 5

# 取y有,x没有元素
> setdiff(y, x)
[1]  9 10

# 判断2个向量是否相等
> setequal(x, y)
[1] FALSE

2.17 移动窗口

移动窗口,是用来按时间周期观察数据的一种方法。移动平均,就是一种移动窗口的最常见的应用了。

在R语言的的TTR包中,支持多种的移动窗口的计算。

  • runMean(x) :移动均值
  • runSum(x) :移动求和
  • runSD(x) :移动标准差
  • runVar(x) :移动方差
  • runCor(x,y) :移动相关系数
  • runCov(x,y) :移动协方差
  • runMax(x) :移动最大值
  • runMin(x) :移动最小值
  • runMedian(x):移动中位数

下面我们用移动平均来举例说明一下,移动平均在股票交易使用的非常普遍,是最基础的趋势判断的根踪指标了。


# 生成50个随机数
> set.seed(0)
> x<-round(rnorm(50)*10);head(x,10)
 [1]  13  -3  13  13   4 -15  -9  -3   0  24

# 加载TTR包
> library(TTR)

# 计算周期为3的移动平均值
> m3<-SMA(x,3);head(m3,10)
 [1]         NA         NA  7.6666667  7.6666667 10.0000000  0.6666667 -6.6666667 -9.0000000 -4.0000000
[10]  7.0000000

# 计算周期为5的移动平均值
> m5<-SMA(x,5);head(m5,10)
 [1]   NA   NA   NA   NA  8.0  2.4  1.2 -2.0 -4.6 -0.6

当计算周期为3的移动平均值时,结果的前2个值是NA,计算的算法是


(第一个值 + 第二个值 + 第三个值)  /3 = 第三个值的移动平均值
(13      +    -3   +     13)    /3 = 7.6666667

画出图形


> plot(x,type='l')
> lines(m3,col='blue')
> lines(m5,col='red')

图中黑色线是原始数据,蓝色线是周期为3的移动平均值,红色线是周期为5的移动平均值。这3个线中,周期越大的越平滑,红色线波动是最小的,趋势性是越明显的。如果你想更深入的了解移动平均线在股票中的使用情况,请参考文章二条均线打天下

2.18 时间对齐

时间对齐,是在处理时间序列类型时常用到的操作。我们在做金融量化分析时,经常遇到时间不齐的情况,比如某支股票交易很活跃,每一秒都有交易,而其他不太活跃的股票,可能1分钟才有一笔交易,当我们要同时分析这2只股票的时候,就需要把他们的交易时间进行对齐。


# 生成数据,每秒一个值
> a<-as.POSIXct("2017-01-01 10:00:00")+0:300

# 生成数据,每59秒一个值
> b<-as.POSIXct("2017-01-01 10:00")+seq(1,300,59)

# 打印a
> head(a,10)
 [1] "2017-01-01 10:00:00 CST" "2017-01-01 10:00:01 CST" "2017-01-01 10:00:02 CST" "2017-01-01 10:00:03 CST"
 [5] "2017-01-01 10:00:04 CST" "2017-01-01 10:00:05 CST" "2017-01-01 10:00:06 CST" "2017-01-01 10:00:07 CST"
 [9] "2017-01-01 10:00:08 CST" "2017-01-01 10:00:09 CST"

# 打印b 
> head(b,10)
[1] "2017-01-01 10:00:01 CST" "2017-01-01 10:01:00 CST" "2017-01-01 10:01:59 CST" "2017-01-01 10:02:58 CST"
[5] "2017-01-01 10:03:57 CST" "2017-01-01 10:04:56 CST"

按分钟进行对齐,把时间都对齐到分钟线上。


# 按分钟对齐
> a1<-align.time(a, 1*60)
> b1<-align.time(b, 1*60)

# 查看对齐后的结果
> head(a1,10)
 [1] "2017-01-01 10:01:00 CST" "2017-01-01 10:01:00 CST" "2017-01-01 10:01:00 CST" "2017-01-01 10:01:00 CST"
 [5] "2017-01-01 10:01:00 CST" "2017-01-01 10:01:00 CST" "2017-01-01 10:01:00 CST" "2017-01-01 10:01:00 CST"
 [9] "2017-01-01 10:01:00 CST" "2017-01-01 10:01:00 CST"

> head(b1,10)
[1] "2017-01-01 10:01:00 CST" "2017-01-01 10:02:00 CST" "2017-01-01 10:02:00 CST" "2017-01-01 10:03:00 CST"
[5] "2017-01-01 10:04:00 CST" "2017-01-01 10:05:00 CST"

由于a1数据集,每分钟有多条数据,取每分钟的最后一条代表这分钟就行。


> a1[endpoints(a1,'minutes')]
[1] "2017-01-01 10:01:00 CST" "2017-01-01 10:02:00 CST" "2017-01-01 10:03:00 CST" "2017-01-01 10:04:00 CST"
[5] "2017-01-01 10:05:00 CST" "2017-01-01 10:06:00 CST"

这样子就完成了时间对齐,把不同时间的数据放到都一个维度中了。

3. 个性化的数据变换需求

我们上面已经介绍了,很多种的R语言数据处理的方法,大多都是基于R语言内置的函数或第三方包来完成的。在实际的工作中,实际还有再多的操作,完全是各性化的。

3.1 过滤数据框中,列数据全部为空的列

空值,通常都会给我们做数值计算,带来很多麻烦。有时候一列的数据都是空时,我们需要先把这一个过滤掉,再进行数据处理。

用R语言程序进行实现


# 判断哪列的值都是NA
na_col_del_df<-function(df){
  df[,which(!apply(df,2,function(x) all(is.na(x))))]  
} 

# 生成一个数据集
> df<-data.frame(a=c(1,NA,2,4),b=rep(NA,4),c=1:4);df
   a  b c
1  1 NA 1
2 NA NA 2
3  2 NA 3
4  4 NA 4

# 保留非NA的列
> na_col_del_df(df)
   a c
1  1 1
2 NA 2
3  2 3
4  4 4

3.2 替换数据框中某个区域的数据

我们想替换数据框中某个区域的数据,那么应该怎么做呢?

找到第一个数据框中,与第二个数据框中匹配的行的值作为条件,然后替换这一行的其他指定列的值。


> replace_df<-function(df1,df2,keys,vals){
+     row1<-which(apply(mapply(match,df1[,keys],df2[,keys])>0,1,all))
+     row2<-which(apply(mapply(match,df2[,keys],df1[,keys])>0,1,all))
+     df1[row1,vals]<-df2[row2,vals]
+     return(df1)
+ }

# 第一个数据框 
> df1<-data.frame(A=c(1,2,3,4),B=c('a','b','c','d'),C=c(0,4,0,4),D=1:4);df1
  A B C D
1 1 a 0 1
2 2 b 4 2
3 3 c 0 3
4 4 d 4 4

# 第二个数据框 
> df2<-data.frame(A=c(1,3),B=c('a','c'),C=c(9,9),D=rep(8,2));df2
  A B C D
1 1 a 9 8
2 3 c 9 8

# 定义匹配条件列 
> keys=c("A","B")

# 定义替换的列
> vals=c("C","D")

# 数据替换
> replace_df(df1,df2,keys,vals)
  A B C D
1 1 a 9 8
2 2 b 4 2
3 3 c 9 8
4 4 d 4 4

其实不管R语言中,各种内置的功能函数有多少,自己做在数据处理的时候,都要自己构建很多DIY的函数。

3.3 长表和宽表变换

长宽其实是一种类对于标准表格形状的描述,长表变宽表,是把一个行数很多的表,让其行数减少,列数增加,宽表变长表,是把一个表格列数减少行数增加。

长表变宽表,指定program列不动,用fun列的每一行,生成新的列,再用time列的每个值进行填充。


# 创建数据框
> df<-data.frame(
+     program=rep(c('R','Java','PHP','Python'),3),
+     fun=rep(c('fun1','fun2','fun3'),each = 4),
+     time=round(rnorm(12,10,3),2)
+ );df
   program  fun  time
1        R fun1 15.01
2     Java fun1  7.17
3      PHP fun1 10.84
4   Python fun1  8.96
5        R fun2 10.30
6     Java fun2  9.45
7      PHP fun2  8.87
8   Python fun2  8.18
9        R fun3  6.30
10    Java fun3  9.70
11     PHP fun3  8.89
12  Python fun3  5.19

# 加载reshape2库
> library(reshape2)

# 长表变宽表
> wide <- reshape(df,v.names="time",idvar="program",timevar="fun",direction = "wide");wide
  program time.fun1 time.fun2 time.fun3
1       R      8.31      8.72     10.10
2    Java      8.45      4.15     13.86
3     PHP     10.49     11.47      9.96
4  Python     10.45     13.25     14.64

接下来,进行反正操作,把宽表再转换为长表,还是使用reshape()函数。


# 宽表变为长表
> reshape(wide, direction = "long")
            program  fun  time
R.fun1            R fun1  8.31
Java.fun1      Java fun1  8.45
PHP.fun1        PHP fun1 10.49
Python.fun1  Python fun1 10.45
R.fun2            R fun2  8.72
Java.fun2      Java fun2  4.15
PHP.fun2        PHP fun2 11.47
Python.fun2  Python fun2 13.25
R.fun3            R fun3 10.10
Java.fun3      Java fun3 13.86
PHP.fun3        PHP fun3  9.96
Python.fun3  Python fun3 14.64

我们在宽表转换为长表时,可以指定想转换部分列,而不是所有列,这样就需要增加一个参数进行控制。比如,只变换time.fun2,time.fun3列到长表,而不变换time.fun1列。


> reshape(wide, direction = "long", varying =3:4)
       program time.fun1  time id
1.fun2       R      8.31  8.72  1
2.fun2    Java      8.45  4.15  2
3.fun2     PHP     10.49 11.47  3
4.fun2  Python     10.45 13.25  4
1.fun3       R      8.31 10.10  1
2.fun3    Java      8.45 13.86  2
3.fun3     PHP     10.49  9.96  3
4.fun3  Python     10.45 14.64  4

这样子的转换变形,是非常有利于我们从多角度来看数据的。

3.4 融化

融化,用于把以列进行分组的数据,转型为按行存储,对应数据表设计的概念为,属性表设计。

我们设计一下标准的二维表结构,然后按属性表的方式进行转换。


# 构建数据集
> df<-data.frame(
+   id=1:10,
+   x1=rnorm(10),
+   x2=runif(10,0,1)
+ );df
   id          x1          x2
1   1  1.78375335 0.639933473
2   2  0.26424700 0.250290845
3   3 -1.83138689 0.963861236
4   4 -1.77029220 0.451004465
5   5 -0.92149552 0.322621217
6   6  0.88499153 0.697954226
7   7  0.68905343 0.002045145
8   8  1.35269693 0.765777220
9   9  0.03673819 0.908817646
10 10  0.49682503 0.413977373

# 融合,以id列为固定列
> melt(df, id="id")
   id variable        value
1   1       x1  1.783753346
2   2       x1  0.264247003
3   3       x1 -1.831386887
4   4       x1 -1.770292202
5   5       x1 -0.921495517
6   6       x1  0.884991529
7   7       x1  0.689053430
8   8       x1  1.352696934
9   9       x1  0.036738187
10 10       x1  0.496825031
11  1       x2  0.639933473
12  2       x2  0.250290845
13  3       x2  0.963861236
14  4       x2  0.451004465
15  5       x2  0.322621217
16  6       x2  0.697954226
17  7       x2  0.002045145
18  8       x2  0.765777220
19  9       x2  0.908817646
20 10       x2  0.413977373

这个操作其实在使用ggplot2包画图时,会被经常用到。因为ggplot2做可视化时画多条曲线时,要求的输入的数据格式必须时属性表的格式。

3.5 周期分割

周期分割,是基于时间序列类型数据的处理。比如黄金的交易,你可以用1天为周期来观察,也可以用的1小时为周期来观察,也可以用1分钟为周期来看。

下面我们尝试先生成交易数据,再对交易数据进行周期的分割。本例仅为周期分割操作的示范,数据为随机生成的,请不要对数据的真实性较真。


# 加载xts包
> library(xts)

# 定义生成每日交易数据函数
> newTick<-function(date='2017-01-01',n=30){
+   newDate<-paste(date,'10:00:00')
+   xts(round(rnorm(n,10,2),2),order.by=as.POSIXct(newDate)+seq(0,(n-1)*60,60))
+ }

假设我们要生成1年的交易数据,先产生1年的日期向量,然后循环生成每日的数据。


# 设置交易日期
> dates<-as.Date("2017-01-01")+seq(0,360,1)
> head(dates)
[1] "2017-01-01" "2017-01-02" "2017-01-03" "2017-01-04" "2017-01-05" "2017-01-06"

# 生成交易数据
> xs<-lapply(dates,function(date){
+   newTick(date)
+ })

# 查看数据静态结构
> str(head(xs,2))
List of 2
 $ :An ‘xts’ object on 2017-01-01 10:00:00/2017-01-01 10:29:00 containing:
  Data: num [1:30, 1] 9.98 9.2 10.21 9.08 7.82 ...
  Indexed by objects of class: [POSIXct,POSIXt] TZ: 
  xts Attributes:  
 NULL
 $ :An ‘xts’ object on 2017-01-02 10:00:00/2017-01-02 10:29:00 containing:
  Data: num [1:30, 1] 9.41 13.15 6.07 10.12 10.37 ...
  Indexed by objects of class: [POSIXct,POSIXt] TZ: 
  xts Attributes:  
 NULL

# 转型为xts类型 
> df<-do.call(rbind.data.frame, xs)
> xdf<-as.xts(df)
> head(xdf)
                       V1
2017-01-01 10:00:00  9.98
2017-01-01 10:01:00  9.20
2017-01-01 10:02:00 10.21
2017-01-01 10:03:00  9.08
2017-01-01 10:04:00  7.82
2017-01-01 10:05:00 10.47

现在有了数据,那么我们可以对数据日期,按周期的分割了,从而生成开盘价、最高价、最低价、收盘价。这里一样会用到xts包的函数。关于xts类型的详细介绍,请参考文章 可扩展的时间序列xts


# 按日进行分割,对应高开低收的价格
> d1<-to.period(xdf,period='days');head(d1)
                    xdf.Open xdf.High xdf.Low xdf.Close
2017-01-01 10:29:00     9.98    13.74    5.35     13.34
2017-01-02 10:29:00     9.41    13.54    6.07      9.76
2017-01-03 10:29:00    12.11    13.91    7.16     10.75
2017-01-04 10:29:00    10.43    14.02    6.31     12.10
2017-01-05 10:29:00    11.51    13.97    6.67     13.97
2017-01-06 10:29:00    10.57    12.81    4.30      5.16

# 按月进行分割
> m1<-to.period(xdf,period='months');m1
                    xdf.Open xdf.High xdf.Low xdf.Close
2017-01-31 10:29:00     9.98    16.40    3.85     10.14
2017-02-28 10:29:00     8.25    16.82    4.17     11.76
2017-03-31 10:29:00    10.55    15.54    2.77      9.61
2017-04-30 10:29:00     9.40    16.13    3.84     11.77
2017-05-31 10:29:00    13.79    16.74    3.97     10.25
2017-06-30 10:29:00     9.29    16.15    4.38      7.92
2017-07-31 10:29:00     5.39    16.09    4.55      9.88
2017-08-31 10:29:00     5.76    16.34    3.27     10.86
2017-09-30 10:29:00     9.56    16.40    3.58     10.09
2017-10-31 10:29:00     8.64    15.50    3.23     10.26
2017-11-30 10:29:00     9.20    15.38    3.00     10.92
2017-12-27 10:29:00     6.99    16.22    3.87      8.87

# 按7日进行分割
> d7<-to.period(xdf,period='days',k=7);head(d7)
                    xdf.Open xdf.High xdf.Low xdf.Close
2017-01-07 10:29:00     9.98    15.54    4.30     10.42
2017-01-14 10:29:00    11.38    14.76    5.74      9.17
2017-01-21 10:29:00     9.57    16.40    3.85     11.91
2017-01-28 10:29:00    10.51    14.08    4.66     10.97
2017-02-04 10:29:00    10.43    16.69    4.53      6.09
2017-02-11 10:29:00    11.98    15.23    5.04     11.57

最后,通过可视化把不同周期的收盘价,画到一个图中。


> plot(d1$xdf.Close)
> lines(d7$xdf.Close,col='red',lwd=2)
> lines(m1$xdf.Close,col='blue',lwd=2)

从图中,可以看出切换为不同的周期,看到的形状是完全不一样的。黑色线表示以日为周期的,红色线表示以7日为周期的,蓝色线表示以月为周期的。

从本文的介绍来看,要做好数据处理是相当不容易的。你要知道数据是什么样的,业务逻辑是什么,怎么写程序以及数据变形,最后怎么进行BI展示,表达出正确的分析维度。试试R语言,忘掉程序员的思维,换成数据的思维,也许繁琐的数据处理工作会让你开心起来。

本文所介绍的数据处理的方法,及个性化的功能函数,我已经发布为一个github的开源项目,项目地址为:https://github.com/bsspirit/RTransform 欢迎大家试用,共同完善。

转载请注明出处:
http://blog.fens.me/r-transform/

打赏作者

2017CDAS中国数据分析师行业峰会:用R语言解读股利贴现模型

跨界知识聚会系列文章,“知识是用来分享和传承的”,各种会议、论坛、沙龙都是分享知识的绝佳场所。我也有幸作为演讲嘉宾参加了一些国内的大型会议,向大家展示我所做的一些成果。从听众到演讲感觉是不一样的,把知识分享出来,你才能收获更多。

关于作者:

  • 张丹(Conan), 程序员R,Nodejs,Java
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/meeting-cdas-20170729

前言

今年的数据分析师大会,国贸,中国大饭店,高规格,上档次!虽然只有1天,却吸引了3000+人的报名参会。11个分会场都是从数据角度来切入,包括了 大数据与生物医疗,大数据与云计算,互联网大数据,电商大数据,大数据与金融,大数据与人工智能,数据可视化与商业BI,大数据与交通旅游,大数据与智慧投资,数据库技术与实战,CDA数据分析师专场。

我的分享在 大数据与金融专场,见到了很多熟悉的朋友,同时也认识不少的新朋友。希望大家能够学到知识,并真正地落地到实际的工作中来。

我已经连续参加了3年的CDAS中国数据分析师行业峰会,祝这个数据的大会越办越好。前2年数据分析师大会会议纪要:2016数据分析师大会2015数据分析师大会

目录

  1. 我的演讲主题:用R语言解读股利贴现模型
  2. 会议体验和照片分享

1. 我的演讲主题:用R语言解读股利贴现模型

用R语言解读股利贴现模型,PPT下载,主要内容来自我的一篇博文:用R语言解读股利贴现模型(未发布)

本次分享我详细讲述了,股利贴现模型的原理和方法,并用这个模型分析招商银行(600036.SH)股票,最后用程序来实现。如果你按照我的思路去操作,相信也能很快找到被低估的股票,从而赚到靠能力可以赚到的钱。

本次分享的目录:

  1. 发现错误的定价
  2. 股利贴现模型
  3. 投资机会
  4. A股市场案例分析
  5. 用R语言实现

为了本次的分享,我花了2周的时间进行准备。希望能够给大家分享一个,实用的模型,这样听完了就可以回去动手实验了。由于分享时间比较短,而且又有不少的金融专业知识,要在30分内给大家讲一个新东西,确实很难啊,我也是挑战了一下自己。

我一直延续了一贯的演讲风格,有内容,有图片,有代码,有互动。从方法理论的思路开始,到市场特征检验,再到数学公式,R语言建模,把知识和市场操作联系起来,听完我的分享,你回去把上就可以动手实践。利用IT人的技术优势,可以真正地与实际操作结合起来,实现从IT技术到价值的转变。

2. 会议体验和照片分享

这次的大会虽然只有1天,也能看出来主办方准备充分。不得不说一句,所有的工作人员辛苦了!

“跨界互联,数聚未来”是本次会议的主题,会议主页:http://cdas.cda.cn/。以数据为题,研习技术,比拼创意,交流思想,探寻未来,打造一场大数据与大思维的盛筵。

2.1 大数据与金融场,我是第4位分享嘉宾。

  • 李峰,IBM Analytics LBS首席数据科学家,主题:人工智能助力银行审计管理
  • 于晓松,诸葛io产品VP,主题:深入金融场景的数据驱动与应用
  • 郑志勇,集思录副总裁,主题:资产配置与数据分析
  • 张丹,《R的极客理想》系列图书作者,主题:用R语言实现量化交易策略
  • 雷涛,天云大数据CEO,主题:Fintech实践:从BI到AI的演进路径
  • 赵刚,北京赛智时代信息技术咨询有限公司CEO,主题:“双创”大数据金融分析服务

我在分享的照片

其他嘉宾的照片

李峰

于晓松

郑志勇

金融会场照片

2.2 会议相关照片

大会开幕式

精彩瞬间

工作人员

最后,感谢CDAS工作人员的辛苦劳动,希望保持高水平会议越办越好!

转载请注明出处:
http://blog.fens.me/meeting-cdas-20170729

打赏作者