用时间序列的方法处理数据
Posted R语言中文社区
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用时间序列的方法处理数据相关的知识,希望对你有一定的参考价值。
1、 本文简介
本文以处理A股财务报表为例,介绍了将数据转换成时间序列后在进行处理的一些方法和思路。将会用到xts,lapply,do.call等数据结构和函数。
我们从各个途径获得了个股的财务报表原始数据后,还需要对数据做一些处理,以便后续指标计算和使用。举个简单的例子,个股发布的利润表和现金流量表,在年内各个季度值都是累计值,不方便环比比较,所以我们现在想把它们全部都处理成当季实际发生额。对于这样的数据,无论是SQL还是R,Python里面传统的数据结构,实现起来都是要费一番功夫进行数据处理的。但是如果使用了时间序列的方法,再结合一些R语言自带的语法结构,只需要短短几行代码,就能完成复杂的数据清洗。
2、 原始数据
原始文件我已经整理好了,记录了*万科*,*国农科技*,*世纪星源*和*深振业A*这四只股票从2014年一季度到2017年三季度,利润表里“营业总收入”的数据(单位:万元)。每只个股有15条记录,合计60行数据。数据结构如下:
## 'data.frame': 60 obs. of 3 variables: ## $ 季度 : chr "2017-09-30" "2017-06-30" ... ## $ 名称 : chr "万科" "万科" "万科" "万科" ... ## $ 营业总收入: int 11710050 6981048 1858923 ...
以万科为例,具体内容如下:
data[data$名称=="万科",]
## 季度 名称 营业总收入
## 1 2017-09-30 万科 11710050
## 2 2017-06-30 万科 6981048
## 3 2017-03-31 万科 1858923
## 4 2016-12-31 万科 24047724
## 5 2016-09-30 万科 11705480
## 6 2016-06-30 万科 7479529
## 7 2016-03-31 万科 1461131
## 8 2015-12-31 万科 19554913
## 9 2015-09-30 万科 7959621
## 10 2015-06-30 万科 5026680
## 11 2015-03-31 万科 889434
## 12 2014-12-31 万科 14638800
## 13 2014-09-30 万科 6313959
## 14 2014-06-30 万科 4096190
## 15 2014-03-31 万科 949722
我们看到,每只个股按照时间倒序排列,营业总收入是一个累计值。比如,表中显示万科在2017年3季度的营业收入为11710050(万元),2季度的营业收入为6981048(万元),那么万科2017年3季度的营业收入世纪发生额为11710050-6981048=4729002 万元。我们的目的是在原始数据的基础之上,再加一列,把单季度的发生额加在后面。
3、处理过程
3.1、数据切分
原始数据里有4只股票,他们的数据结构是一致的,处理方法也一致,为了方便处理,把原始数据从数据框切成列表。在dataframe上使用split,可以将dataframe按照指定的条件切成一个个列表。示例如下:
data<-split(data,data$名称) #数据类型
class(data) ## [1] "list"
#列表名称
names(data) ## [1] "国农科技" "深振业A" "世纪星源" "万科"
# 第一个列表内容
## 17 2017-06-30 国农科技 2929
data[[1]] ## 季度 名称 营业总收入
## 16 2017-09-30 国农科技 7100
## 18 2017-03-31 国农科技 1087
## 19 2016-12-31 国农科技 28767
## 20 2016-09-30 国农科技 21757
## 21 2016-06-30 国农科技 10215
## 22 2016-03-31 国农科技 1348
## 23 2015-12-31 国农科技 12045
## 24 2015-09-30 国农科技 8889
## 25 2015-06-30 国农科技 5955
## 26 2015-03-31 国农科技 2094
## 27 2014-12-31 国农科技 8061
## 28 2014-09-30 国农科技 4842
## 29 2014-06-30 国农科技 2743
## 30 2014-03-31 国农科技 1130
这样数据从dataframe切分成了4个列表,分别对应每一只个股。
3.2、数据处理
df<-data[[1]] df$季度<-as.Date(df$季度) df<-as.xts(df[-c(1,2)],order.by=df$季度) class(df) ## [1] "xts" "zoo"
df ## 营业总收入
## 2014-03-31 1130
## 2014-06-30 2743
## 2014-09-30 4842
## 2014-12-31 8061
## 2015-03-31 2094
## 2015-06-30 5955
## 2015-09-30 8889
## 2015-12-31 12045
## 2016-03-31 1348
## 2016-06-30 10215
## 2016-09-30 21757
## 2016-12-31 28767
## 2017-03-31 1087
## 2017-06-30 2929
## 2017-09-30 7100
时间序列只能处理数值型的数据,数据转化成时间序列后,原来数据框中的日期和名称都消失了。要在后面在加上去。现在开始计算单季数据,只要拿当前的值减去上期的值即可。在时间序列了,可以使用DIFF差分函数来实现,diff(x,n),表示将当前值减去N个周期前的值。默认n=1.将处理后的数据合并会原来的数据。并把日期加上去。
datadiff<-diff(df) datanew<-as.data.frame(merge(df,datadiff)) datanew<-cbind(row.names(datanew),datanew) colnames(datanew)<-c("季度","营业总收入","营业总收入单季") datanew ## 季度 营业总收入 营业总收入单季
## 2014-03-31 1130 NA ## 2014-06-30 2743 1613
## 2014-09-30 4842 2099
## 2014-12-31 8061 3219
## 2015-03-31 2094 -5967
## 2015-06-30 5955 3861
## 2015-09-30 8889 2934
## 2015-12-31 12045 3156
## 2016-03-31 1348 -10697
## 2016-06-30 10215 8867
## 2016-09-30 21757 11542
## 2016-12-31 28767 7010
## 2017-03-31 1087 -27680
## 2017-06-30 2929 1842
## 2017-09-30 7100 4171
注意到这个结果还有一个问题,一个是一季度的数据不需要减去上期值,一季度的单季数值等于累计值。所以数据还要处理一下。
#quarter方法来自lubridate包,可以传入文本判断季度
datanew[quarter(datanew$季度)==1,3]=datanew[quarter(datanew$季度)==1,2]
DataPrc<-function (x){ #转成时间序列 x$季度<-as.Date(x$季度) StkNam<-as.character(x$名称[1]) x<-as.xts(x[-c(1,2)],order.by=x$季度) #利用差分计算单期值并合并 x.diff<-diff(x) x.new<-as.data.frame(merge(x,x.diff)) x.new<-cbind(row.names(x.new),StkNam,x.new) colnames(x.new)<-c("季度","名称","营业总收入","营业总收入单季") #处理特殊情况 #quarter 方法来自lubridate包,可以传入文本判断季度 x.new[quarter(x.new$季度)==1,4]=x.new[quarter(x.new$季度)==1,3] x.new } stkdata<-lapply(data,DataPrc) stkdata
## $国农科技 ## 季度 名称 营业总收入 营业总收入单季 ## 2014-03-31 2014-03-31 国农科技 1130 1130 ## 2014-06-30 2014-06-30 国农科技 2743 1613 ## 2014-09-30 2014-09-30 国农科技 4842 2099 ## 2014-12-31 2014-12-31 国农科技 8061 3219 ## 2015-03-31 2015-03-31 国农科技 2094 2094 ## 2015-06-30 2015-06-30 国农科技 5955 3861 ## 2015-09-30 2015-09-30 国农科技 8889 2934 ## 2015-12-31 2015-12-31 国农科技 12045 3156 ## 2016-03-31 2016-03-31 国农科技 1348 1348 ## 2016-06-30 2016-06-30 国农科技 10215 8867 ## 2016-09-30 2016-09-30 国农科技 21757 11542 ## 2016-12-31 2016-12-31 国农科技 28767 7010 ## 2017-03-31 2017-03-31 国农科技 1087 1087 ## 2017-06-30 2017-06-30 国农科技 2929 1842 ## 2017-09-30 2017-09-30 国农科技 7100 4171
## $深振业A ## 季度 名称 营业总收入 营业总收入单季 ## 2014-03-31 2014-03-31 深振业A 26292 26292 ## 2014-06-30 2014-06-30 深振业A 49149 22857 ## 2014-09-30 2014-09-30 深振业A 64985 15836 ## 2014-12-31 2014-12-31 深振业A 232873 167888 ## 2015-03-31 2015-03-31 深振业A 138923 138923 ## 2015-06-30 2015-06-30 深振业A 202261 63338 ## 2015-09-30 2015-09-30 深振业A 230546 28285 ## 2015-12-31 2015-12-31 深振业A 365431 134885 ## 2016-03-31 2016-03-31 深振业A 38249 38249 ## 2016-06-30 2016-06-30 深振业A 86869 48620 ## 2016-09-30 2016-09-30 深振业A 114571 27702 ## 2016-12-31 2016-12-31 深振业A 335883 221312 ## 2017-03-31 2017-03-31 深振业A 116791 116791 ## 2017-06-30 2017-06-30 深振业A 186960 70169 ## 2017-09-30 2017-09-30 深振业A 231926 44966
## ## $世纪星源 ## 季度 名称 营业总收入 营业总收入单季 ## 2014-03-31 2014-03-31 世纪星源 1218 1218 ## 2014-06-30 2014-06-30 世纪星源 2386 1168 ## 2014-09-30 2014-09-30 世纪星源 3585 1199 ## 2014-12-31 2014-12-31 世纪星源 5278 1693 ## 2015-03-31 2015-03-31 世纪星源 1349 1349 ## 2015-06-30 2015-06-30 世纪星源 3629 2280 ## 2015-09-30 2015-09-30 世纪星源 4576 947 ## 2015-12-31 2015-12-31 世纪星源 8413 3837 ## 2016-03-31 2016-03-31 世纪星源 4342 4342 ## 2016-06-30 2016-06-30 世纪星源 18995 14653 ## 2016-09-30 2016-09-30 世纪星源 35050 16055 ## 2016-12-31 2016-12-31 世纪星源 48186 13136 ## 2017-03-31 2017-03-31 世纪星源 7145 7145 ## 2017-06-30 2017-06-30 世纪星源 20360 13215 ## 2017-09-30 2017-09-30 世纪星源 31423 11063## $万科 ## 季度 名称 营业总收入 营业总收入单季 ## 2014-03-31 2014-03-31 万科 949722 949722 ## 2014-06-30 2014-06-30 万科 4096190 3146468 ## 2014-09-30 2014-09-30 万科 6313959 2217769 ## 2014-12-31 2014-12-31 万科 14638800 8324841 ## 2015-03-31 2015-03-31 万科 889434 889434 ## 2015-06-30 2015-06-30 万科 5026680 4137246 ## 2015-09-30 2015-09-30 万科 7959621 2932941 ## 2015-12-31 2015-12-31 万科 19554913 11595292 ## 2016-03-31 2016-03-31 万科 1461131 1461131 ## 2016-06-30 2016-06-30 万科 7479529 6018398 ## 2016-09-30 2016-09-30 万科 11705480 4225951 ## 2016-12-31 2016-12-31 万科 24047724 12342244 ## 2017-03-31 2017-03-31 万科 1858923 1858923 ## 2017-06-30 2017-06-30 万科 6981048 5122125 ## 2017-09-30 2017-09-30 万科 11710050 4729002
4、合并
以上结果显示数据都是列表,把它们合成一个数据框。方便后续处理。你当然可以选择使用循环将列表合并,但R里处理循环的效率实在无法恭维。这里有个更好的办法,代码如下:
result<- do.call(rbind,stkdata) rownames(result) <- NULL head(result[result$名称=="世纪星源",],2)
# 季度 名称 营业总收入 营业总收入单季
## 2014-03-31 世纪星源 1218 1218
## 2014-06-30 世纪星源 2386 1168
do.call() 是告诉列表一个函数,让列表里的所有元素来执行这个函数。将其用于列表合并,效果比循环好太多。
这样,我们就把数据整理完毕了。这种差分的数据处理方法,在很多场景都有应用。比如运营上拿到了一系列周期上的指标数值,都同时会看看同比、环比的增减情况。这些数据使用传统的数据结构,使用传统的数据处理方法,计算脚本都是很复杂的,而把数据转化成时间序列后,这些处理的过程都可以用简单的方法解决。另外,在使用R进行数据分析时,应该利用这种向量化语言的特点,用向量化的方法处理数据。
以上是关于用时间序列的方法处理数据的主要内容,如果未能解决你的问题,请参考以下文章
Oracle 数据库 - 使用UEStudio修改dmp文件版本号,解决imp命令恢复的数据库与dmp本地文件版本号不匹配导致的导入失败问题,“ORACLE error 12547”问题处理(代码片段