• Posts tagged "数据科学"

Blog Archives

用R语言实现数据离散化

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

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

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

关于作者:

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

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

前言

在做数据挖掘模型的时候,我们有时会需要把连续型变量转型离散变量,这种转换的过程就是数据离散化,分箱就是离散化常用的一种方法。

数据离散化处理属于数据预处理的一个过程,R语言在数据处理上有天然的优势,也有直接用于离散化计算的包,无监督的离散化可以用infotheo包,有监督的离散化可以用discretization包来处理复杂的离散化操作。

目录

  1. 数据离散化的需求
  2. 无监督的数据离散化
  3. 有监督的数据离散化

1. 数据离散化的需求

数据离散化,教课书上面的定义是,把无限空间中有限的个体映射到有限的空间中。数据离散化操作,大多是针对连续型变量进行的,处理之后数据从连续型变量转变为离散型变量。

离散化处理的特点:

  • 快速迭代,离散化的过程,离散特征增加和减少都很容易,易于扩展。
  • 高效计算,稀疏向量内积乘法运算速度快,计算结果方便存储。
  • 适应性,有些分类模型适合用离散化数据做为数据指标,比如决策树虽然支持输入连续型变量,但决策树模型本身会先将连续型变量转化为离散型变量,做逻辑回归时,也通常会先把连续型特征变量离散化,变成0或1。
  • 鲁棒性,数据离散化会让特征变化不是特别明显,特别是对于降低异常数据干扰。
  • 稳定性,牺牲了数据的微小变化,但保证了模型的稳定性。
  • 过拟合,减少的数据信息,降低了过拟合的风险。
  • 业务性,业务上已经定义出了离散值的含义,需要做离散化处理。

离散化处理通常对连续型变量进行处理,但同时也可以对离散型变量再进行离散化,适用于数据聚合或重新分组。

2. 无监督的数据离散化

我们可以无监督的数据离散化方法,进行数据的分箱操作,包括等宽分箱法、等频分箱法、通过kmeans分箱法等。

  • 等宽分箱法,将观察点均匀划分成n等份,每份的间距相等。
  • 等频分箱法,将观察点均匀分成n等份,每份的观察点数相同。
  • kmeans分箱法,先给定中心数,将观察点利用欧式距离计算与中心点的距离进行归类,再重新计算中心点,直到中心点不再发生变化,以归类的结果做为分箱的结果。

接下来,我们用R语言来实现上面提到的几种分箱的操作。

2.1 准备数据

本文所使用的系统环境

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

首先,生成一组数据,这组织通过3个正态分布的随机数进行叠加,主要用于体现分箱的不同特征。


# 设置随机数种子,生成符合正态分布N(0,1)的数据1000个点
> set.seed(0)
> a1<-rnorm(1000)

> set.seed(1)
> a2<-rnorm(300,0,0.2)

> set.seed(2)
> a3<-rnorm(300,3,0.5)

# 按顺序,合并3种数据
> aa<-c(a1,a2,a3)

# 查看数据
> head(aa,30)
 [1]  1.26295 -0.32623  1.32980  1.27243  0.41464 -1.53995 -0.92857 -0.29472 -0.00577  2.40465  0.76359
[12] -0.79901 -1.14766 -0.28946 -0.29922 -0.41151  0.25222 -0.89192  0.43568 -1.23754 -0.22427  0.37740
[23]  0.13334  0.80419 -0.05711  0.50361  1.08577 -0.69095 -1.28460  0.04673

画出数据的散点图,x轴为索引序号,y轴为值。


> plot(aa)

查看数据的分布形状,x轴为值,y轴为这个值出现的次数。


# 画出数据的直方图
> hist(aa,200)

通过散点图和直方图,就可以很明显的看到数据的特征,数据有倾斜的,值在0和3附近是比较多的。

2.2 infotheo包使用

在R语言中,我们可以使用infotheo包,来做等宽分箱和等频分箱。

项目主页:https://cran.r-project.org/web/packages/infotheo/

安装infotheo包,是非常简单的,只需要一条命令。


~ R
> install.packages("infotheo")
> library(infotheo)

进行等宽分箱,将观察点均匀划分成n等份,每份的间距相等。


> d1<-discretize(aa,"equalwidth",5)
> table(d1)
d1
  1   2   3   4   5 
 40 467 703 217 173 

# 可视化分箱
> plot(aa,col=d1$X)

分为5组,第一组最少,第三组最多,每组值的区间是一样的。

进行等频率分箱,将观察点均匀分成n等份,每份的观察点数相同。


> d2<-discretize(aa,"equalfreq",5)
> table(d2)
d2
  1   2   3   4   5 
320 320 320 320 320 

# 可视化分箱
> plot(aa,col=d2$X)

分为5组,每组的数量都相同。

kmeans分箱法,先给定中心数为5。


> d3<-kmeans(aa,5)
> table(d3$cluster)
  1   2   3   4   5 
121 258 303 267 651 

# 5个中心
> d3$centers
     [,1]
1 -1.6196
2  1.2096
3  3.0436
4 -0.7228
5  0.0736

# 可视化分箱
> plot(aa,col=d3$cluster)

5组聚类的结果。

每一种方法,对于分箱的离散化的结果都是不同的,使用哪一种方法,最好都有业务上的解释,不能随便乱用。

3. 有监督的数据离散化方法

有监督的离散化的方法,可以用R语言中discretization包来操作。discretization包,是一个用来做有监督离散化的工具集,主要用于卡方分箱算法,它提供了几种常用的离散化工具函数,可以按照自上而下或自下而上,实施离散化算法。

项目主页:https://cran.r-project.org/web/packages/discretization/

安装discretization包是非常简单的,只需要一条命令。


~ R
> install.packages("discretization")
> library(discretization)

discretization提供了几个主要的离散化的工具函数:

  • chiM,ChiM算法进行离散化
  • chi2, Chi2算法进行离散化
  • mdlp,最小描述长度原理(MDLP)进行离散化
  • modChi2,改进的Chi2方法离散数值属性
  • disc.Topdown,自上而下的离散化
  • extendChi2,扩展Chi2算法离散数值属性

3.1 卡方分箱

卡方分箱是依赖于卡方检验的分箱方法,在统计指标上选择卡方统计量(chi-Square)进行判别。卡方分箱的基本思想是判断相邻的两个区间是否有分布差异,如果两个相邻的区间具有非常类似的分布,则这两个区间可以合并;否则,它们应当保持分开。基于卡方统计量的结果进行自下而上的合并,直到满足分箱的限制条件为止。

卡方分箱的实现步骤:

1. 预先设定一个卡方的阈值。以这个阈值为标准,我们对数据进行卡方检验,通过显著性水平和自由度,计算出数据的卡方值与这个阈值进行比较。

  • 显著性水平,当置信度90%时显著性水平为10%,ChiMerge算法推荐使用置信度为0.90、0.95、0.99。
  • 自由度,比分类数量小1。例如:有3类,自由度为2。

类别和属性独立时,有90%的可能性,计算得到的卡方值会小于4.6。大于阈值4.6的卡方值就说明属性和类不是相互独立的,不能合并。如果阈值选的大,区间合并就会进行很多次,离散后的区间数量少、区间大。

2. 初始化:根据要离散化的数据对实例进行排序,每个实例属于一个区间
3. 合并区间:
1) 计算每一个对相邻区间的卡方值
2) 将卡方值最小的一对区间合并

卡方统计量衡量了区间内样本的频数分布与整体样本的频数分布的差异性,在做分箱处理时可以使用两种限制条件:

  • 分箱个数:限制最终的分箱个数结果,每次将样本中具有最小卡方值的区间与相邻的最小卡方区间进行合并,直到分箱个数达到限制条件为止。
  • 卡方阈值:根据自由度和显著性水平得到对应的卡方阈值,如果分箱的各区间最小卡方值小于卡方阈值,则继续合并,直到最小卡方值超过设定阈值为止。

4.评估指标

分为箱之后需要评估,常用的评估手段是计算出WOE和IV值。对于WOE和IV值的含义,参考文章:https://blog.csdn.net/kevin7658/article/details/50780391

3.2 数据准备

有监督的离散化算法,只少需要数据为2列,一列用于离散化的向量数据,一列是分类的评价标准数据,所以我们需要重新选择一个数据集,具有分类标准的数据。

我们使用一个系统自带的数据集iris,这个着名的Fisher的鸢尾花数据。iris包含150个记录,和5个变量的数据框,名为Sepal.Length(萼片的长度),Sepal.Width(萼片的宽度),Petal.Length(花瓣的长度),Petal.Width(花瓣的长度)和Species(种类,setosa,versicolor和virginica)。

查看数据集


> data(iris)
> head(iris,10)
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1           5.1         3.5          1.4         0.2  setosa
2           4.9         3.0          1.4         0.2  setosa
3           4.7         3.2          1.3         0.2  setosa
4           4.6         3.1          1.5         0.2  setosa
5           5.0         3.6          1.4         0.2  setosa
6           5.4         3.9          1.7         0.4  setosa
7           4.6         3.4          1.4         0.3  setosa
8           5.0         3.4          1.5         0.2  setosa
9           4.4         2.9          1.4         0.2  setosa
10          4.9         3.1          1.5         0.1  setosa

接下来,我们分别用不同的算法,把这个数据集进行离散化处理。

3.3 chiM算法进行离散化

ChiM()函数,使用ChiMerge算法基于卡方检验进行自下而上的合并。通过卡方检验判断相邻阈值的相对类频率,是否有明显不同,或者它们是否足够相似,从而合并为一个区间。

chiM(data,alpha)函数解读。

  • 第一个参数data,是输入数据集,要求最后一列是分类属性。
  • 第二个参数alpha,表示显著性水平。
  • 自由度,通过数据计算获得是2,一共3个分类减去1。

下面使用chiM()进行计算。


# 离散化计算
> chi1<-chiM(iris,alpha=0.05)

# 查看前10条结果
> head(chi1$Disc.data,10)
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1             1           3            1           1  setosa
2             1           2            1           1  setosa
3             1           2            1           1  setosa
4             1           2            1           1  setosa
5             1           3            1           1  setosa
6             1           3            1           1  setosa
7             1           3            1           1  setosa
8             1           3            1           1  setosa
9             1           1            1           1  setosa
10            1           2            1           1  setosa

chi2算法的结果解读,从输出结果可以看出,Sepal.Length Sepal.Width Petal.Length Petal.Width,这几个变量被自动地离散化处理了。

查看这4个列的离散化情况。


> apply(chi1$Disc.data,2,table)
$Sepal.Length
 1  2  3  4 
52 21 65 12 

$Sepal.Width
 1  2  3 
57 56 37 

$Petal.Length
 1  2  3  4 
50 45 21 34 

$Petal.Width
 1  2  3 
50 54 46 

$Species
    setosa versicolor  virginica 
        50         50         50 

再查看每个列的阈值。


# 查看分组阈值
> chi1$cutp
[[1]]
[1] 5.45 5.75 7.05

[[2]]
[1] 2.95 3.35

[[3]]
[1] 2.45 4.75 5.15

[[4]]
[1] 0.80 1.75

以第一组Sepal.Length举例,被分为4类,当源数据Sepal.Length列的值,小于 5.45值为1类,大于5.45同时小于5.75为2类,大于5.75同时小于7.05为3类,大于7.05为4类。

我们把离散化后的数据,与源数据进行合并进行观察。第一列是离散化后的数据,第二列是源数据。


> chi1df<-cbind(chi1$Disc.data$Sepal.Length,iris$Sepal.Length)
> head(chi1df,20)
      [,1] [,2]
 [1,]    1  5.1
 [2,]    1  4.9
 [3,]    1  4.7
 [4,]    1  4.6
 [5,]    1  5.0
 [6,]    1  5.4
 [7,]    1  4.6
 [8,]    1  5.0
 [9,]    1  4.4
[10,]    1  4.9
[11,]    1  5.4
[12,]    1  4.8
[13,]    1  4.8
[14,]    1  4.3
[15,]    3  5.8
[16,]    2  5.7
[17,]    1  5.4
[18,]    1  5.1
[19,]    2  5.7
[20,]    1  5.1

这样就完成了卡方分箱的操作,接下来的其他几个函数的使用,与chiM()的算法类似,就不再过多讨论了。

3.4 其他算法

chi2()算法,查看分组阈值。


> chi2<-chi2(iris,alp=0.5,del=0.05)
> chi2$cutp
[[1]]
[1] 3.5 4.5 6.5

[[2]]
[1] 3.5 4.5

[[3]]
[1] 1.5 2.5 3.5

[[4]]
[1] 1.5 3.5

modChi2()算法,查看分组阈值。


> chi3<-modChi2(iris,alp=0.5)
> chi3$cutp
[[1]]
[1] 1.5 2.5

[[2]]
[1] 2.5

[[3]]
[1] 1.5 2.5

[[4]]
[1] 1.5 2.5

extendChi2()算法,查看分组阈值。


> chi4<-extendChi2(iris,alp = 0.5)
> chi4$cutp
[[1]]
[1] 1.5 2.5

[[2]]
[1] 1.5 2.5

[[3]]
[1] 1.5 2.5

[[4]]
[1] 1.5 2.5

> m1<-mdlp(iris)
> m1$cutp
[[1]]
[1] 5.55 6.15

[[2]]
[1] 2.95 3.35

[[3]]
[1] 2.45 4.75

[[4]]
[1] 0.80 1.75

disc.Topdown()算法,查看分组阈值。


> d1<-disc.Topdown(iris,method=1)
> d1$cutp
[[1]]
[1] 4.30 5.55 6.25 7.90

[[2]]
[1] 2.00 2.95 3.05 4.40

[[3]]
[1] 1.00 2.45 4.75 6.90

[[4]]
[1] 0.10 0.80 1.75 2.50

最后,分箱需要注意的是,分完箱之后,某些箱区间里可能数据分布比例极不均匀,那么这样子会直接导致后续计算WOE时出现inf无穷大的情况,这是不合理的。这种情况,说明分箱太细,需要进一步缩小分箱的数量。

本文详细地介绍了无监督的离散化方法和有监督的离散化方法,针对不同的场景,我们可以选择不同的方法进行使用。R语言中,包提供了各种离散化的工具函数,使用起来很方便,可以大幅提供数据处理过程的效率。

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

打赏作者

HiBlock社区:区块链链上数据的认知与探索

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

关于作者

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

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

前言

数字货币百花齐放,数字货币开发是区块链开发者的必修课也是入门课,通过ERC20智能合约很快就可以掌握开发技巧,但数字货币的安全如何保障?数字货币交易过程中产生了大量的数据,资金流转规律、操盘方式、筹码分布等等,通过数据预测数字货币价格走势也不是没有可能,除此之外区块链产生的数据还有什么价值?

本次的沙龙2个主题,一个是安全,一个是数据。

目录

  1. 我的演讲主题:区块链链上数据的认知与探索
  2. 会议体验和照片分享

1. 我的演讲主题:区块链链上数据的认知与探索

本次的沙龙2个主题,一个是安全,一个是数据,都是技术流!!所以,来听的也都是技术流,很少人,但很聊的来。

我本次分享的主题为:区块链链上数据的认知与探索,PPT下载,主要内容来自我的1篇博客文篇:区块链链上数据的认知与探索(未发布)。

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

  1. 认识区块链
  2. 区块浏览器
  3. 链上数据探索

主题简介:区块链上所有的交易都是公开透明的,链上账本会记录所有参与者交易行为,包括资金流转规律,庄家操盘,筹码分布等,价值巨大,从数据科学的角度,分享对区块链链上数据进行的认知与探索。

本此分析主要是从数据的角度切入,开始先介绍区块链,让大家有所认知;然后介绍区块链有什么样的数据,区别场内数据和场外数据;最后引出主题,对场外数据进行数据探索,通过账本的交易流水发现这些数据中的规律性的行为,坐庄行为,散户行为,拉盘行为….

数据是很有意思的,希望大家能够了解链上数据,用技术的武器去发现和鉴别真实的交易。

2. 会议体验和照片分享

本次线下沙龙的核心主题为,技术维度解读数字货币安全与数据价值,会议的主页:http://www.huodongxing.com/event/3453087067011

30人的小沙龙,定位就是区块链的技术圈,同业交流。我的分享是 “区块链链上数据的认知与探索” 也是在我这次转型积累的新的经验,跨学科的知识结合,从数据的角度理解区块链。

会议主题:

  • 14:00-14:05 开场 主办方介绍
  • 14:05-14:30 参会者自我介绍
  • 14:30-15:30《智能合约审计》分享嘉宾:赵威
  • 15:30-16:30《区块链链上数据的认知与探索》分享嘉宾:张丹
  • 16:30-17:00 合影 交流

我的介绍和照片分享。

分布式科技CTO,《R的极客理想-量化投资篇》作者,微软MVP。10年编程经验,获得10项SUN及IBM技术认证。前民生银行大数据分析师。个人博客 http://fens.me, Alexa全球排名70K。

2.2 会议相关照片

本次的场地在北京朝阳区建国路89号华贸商务楼16号B1 联合创业办公社,看上去更像是一个活动吧。

主持人:成芳

张丹,区块链链上数据的认知与探索

赵威, 智能合约审计

会后交流

政策条文: 分享开始前特意被关照,只能讲技术,不要讲其他的,最近太敏感,可能随时会被叫停!我们搞技术的人,底线是一定不会触碰的!!

布置会场。

大合照

主办方的小伙伴很辛苦,就一个小姑娘!坚持支持分享,保持高质量,坚持!坚持!

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

打赏作者

2018Finance-AI社区:区块链链上数据的认知与探索

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

关于作者

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

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

前言

第一次在公开场合分享区块链,是一个好的开始。2017底到现在,中国经济在去杠杠,又要打贸易战,P2P各种爆仓,银行缩表,房市限购,人民币对美元大幅贬值,各种事情都在给这个浮躁的社会降温。

区块链的世界却是一片火热,各种人都在炒作概念,搞搞投机。数据,可以说是区块链里最能落地的事情,公链上记录的账本数据,对所有人都是公开的,数据之间藏着大量地真实的交易行业为,是数据学科家最好的探索的素材。

目录

  1. 我的演讲主题:区块链链上数据的认知与探索
  2. 会议体验和照片分享

1. 我的演讲主题:区块链链上数据的认知与探索

首先,感谢主办方的Aislinn的邀请。我本次分享的主题为:区块链链上数据的认知与探索,PPT下载,主要内容来自我的1篇博客文篇:区块链链上数据的认知与探索(未发布)。

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

  1. 认识区块链
  2. 区块浏览器
  3. 链上数据探索

主题简介:区块链上所有的交易都是公开透明的,链上账本会记录所有参与者交易行为,包括资金流转规律,庄家操盘,筹码分布等,价值巨大,从数据科学的角度,分享对区块链链上数据进行的认知与探索。

本此分析主要是从数据的角度切入,开始先介绍区块链,让大家有所认知;然后介绍区块链有什么样的数据,区别场内数据和场外数据;最后引出主题,对场外数据进行数据探索,通过账本的交易流水发现这些数据中的规律性的行为,坐庄行为,散户行为,拉盘行为….

数据是很有意思的,希望大家能够了解链上数据,用技术的武器去发现和鉴别真实的交易。

2. 会议体验和照片分享

本次线下沙龙的核心主题为“突围”,在AI时代,我们如何进行突围,会议的主页:http://www.huodongxing.com/event/7448082509300?td=7742536708807

120人的小沙龙,有5500多人浏览和193个收藏,不得不说主办方的组织能力。同时也能看出,本次的主题定位,就是当下时代大家最关心的话题。我的分享是 “区块链链上数据的认知与探索” 也是在我这次转型积累的新的经验,跨学科的知识结合,迎接AI时代。

会议主题:

  • Finance·AI社区金融算法介绍 Aislinn
  • 主题分享《大牛组团的年代,怎么做才能突围》 Kevin
  • 深度对话 《AI时代个人成长迭代之路 》 Aislinn对话Kevin
  • 主题分享 《区块链链上数据的认知与探索》 张丹
  • 主题分享 《知识图谱在金融风控中的应用》 邵平
  • 圆桌论坛 《金融算法职场与精进》Aislinn对话邵平和张丹
  • 金融算法社区学习计划 Aislinn

我的介绍和照片分享。

分布式科技CTO,《R的极客理想-量化投资篇》作者,微软MVP。10年编程经验,获得10项SUN及IBM技术认证。前民生银行大数据分析师。个人博客 http://fens.me, Alexa全球排名70K。

2.2 会议相关照片

本次的场地在 在(北京朝阳)云享客 · 长富宫中心(建国门外大街26号5号楼一层),一个很适合活动聚会的咖啡厅。

kevin的分享:大牛组团的年代,怎么做才能突围

邵平的分享:知识图谱在金融风控中的应用

现场的同学们。

布置会场。

茶点,小吃。

主办方的小伙伴辛苦啦!!获得嘉宾和听众的一致好评!继续高质量坚持!

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

打赏作者

2017WOT全球软件开发技术峰会:面向数据的思维模式和R语言编程

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

关于作者

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

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

前言

第三次参加WOT的峰会了,这次来到深圳进行分享,蓝蓝的天空,暖暖的天气,真是宜居的城市。

在本次大会上,我主要介绍的是面向数据的思维模式和R语言的编程技巧。谈到思维模式,就是一种自我进化的方法,当你在一味的追求技术的过程中,积累了很多年,遇到了突破不了的瓶颈。你就需要停下来,想一想,是不是要换个角度看问题。

目录

  1. 我的演讲主题:面向数据的思维模式和R语言编程
  2. 会议体验和照片分享

1. 我的演讲主题:面向数据的思维模式和R语言编程

首先,感谢51cto主办方的邀请,并且让我担当“编程语言与框架”分会场的出品人。我本次分享的主题为:面向数据的思维模式和R语言编程,PPT下载,主要内容来自我的2篇文篇:用R语言把数据玩出花样 和 51CTO采访稿 如何用R语言打开面向数据的思维模式

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

  1. 面向数据的思维模式
  2. 金融理论
  3. R语言进行数据处理

本此分析主要是从数据的角度切入,比较程序员思维与数据分析师思维的差异,以及思考方式的区别。在数据已经积累有一定数据量后,怎么让数据产生价值,如何设计数据产品,就是一个非常值得我们思考的问题。数据,不仅仅只存在于互联网行业,数据存在于各行各业。一旦用数据的思维去思考,你就能够发现,无数的机会在等着你。

我主要是研究量化投资,直白一点说,就是对金融数据进行分析,建立数据模型,找到赚钱的机会。同时,我也在致力于推动R语言在中国金融领域的发展,让R可以给更多的用户使用,培养出更多的数据分析师。也希望让我们中国人的技术能够走出去到世界的舞台。希望多能认识志同道合的朋友,一起做一些事情。

2. 会议体验和照片分享

会议的主页:http://wot.51cto.com/act/2017/development/

本次wot的大会,由9个分会场组成,我是在编程语言与框架会场。本会场的主题是,更多新兴的编程语言、框架和工具改变着开发者的工作方式,并带来更多的可能。如何在日新月异的潮流下理智地选择编程语言,确保框架的稳健和成熟?本专场将分享来自最值得关注的语言和框架的最佳实践。

我的介绍和照片分享。

2.2 会议相关照片

本次的场地在 在深圳中洲万豪酒店,五星级,市中心,高楼大厦林立,会场气派。

这是我,专业照相就是帅。

还是我,签名赠书。

签名赠书。

与谢佳标老师,互赚新书。

大会现场的同学们,1000+人次。

蓝天,白云,大高楼

晚宴,英雄会。

主办方的小伙伴辛苦啦!!获得嘉宾和听众的一致好评!

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

打赏作者

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/

打赏作者