1. 程式人生 > >用時間序列的方法處理資料

用時間序列的方法處理資料

作者:藍京,商業銀行資料分析師

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"  "世紀星源" "萬科"
# 第一個列表內容
data[[1]] ##          季度     名稱 營業總收入
## 16 2017-09-30 國農科技       7100
## 172017-06-30國農科技2929
## 182017-03-31國農科技1087
## 192016-12-31國農科技28767
## 202016-09-30國農科技21757
## 212016-06-30國農科技10215
## 222016-03-31國農科技1348
## 232015-12-31國農科技12045
## 242015-09-30國農科技8889
## 252015-06-30國農科技5955
## 262015-03-31國農科技2094
## 272014-12-31國農科技8061
## 282014-09-30國農科技4842
## 292014-06-30國農科技2743
## 302014-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進行資料分析時,應該利用這種向量化語言的特點,用向量化的方法處理資料。

640?wx_fmt=png