使用R的prophet包做一个简单的时序预测

      上一篇博客针对prophet包上传了自己的代码,今天这篇博客我跟大家讲述一下prophet包工作原理,以及我对该模型做的一些优化。
      上次使用prophet包做项目主要分为了四个部分,分别是读取数据,设定节假日(奇异点),训练模型,输出自定义结果这四部分,现在我就上个项目做分别讲解。

      一、初始化:装载模型包并读取数据
     
library(prophet)
library(dplyr)
#初始化数据
all<-read.csv('d:/Rdata/zjd/ts/all.csv',na.string='NA',header=T)
qb30<-read.csv('d:/Rdata/zjd/ts/qb30.csv',na.string='NA',header=T)
history30n <- data.frame(ds = seq(as.Date('2016-01-01'), as.Date('2017-09-11'), by = 'd'), y = qb30$yn)
plot(history30n$ds,history30n$y)
history45n <- data.frame(ds = seq(as.Date('2016-01-01'), as.Date('2017-09-11'), by = 'd'), y = qb45$yn)

      读取数据这一部分就不用多说了,基本使用csv格式,最主要的一点是一定要保证是一列数据,并且如果是每天的数据,一定要设定好起始时间点,我的上一个版本是在生成数据集的时候设定时间,因每次都要逐条修改(因为金融产品的期数不同,还非常多),后来我直接用变量代替了,这样只用修改一次变量就行。代码如下:

alln<-read.csv('d:/Rdata/zjd/ts/qball.csv',na.string='NA',header=T)
start<-c('2017-01-01')
end<-c('2017-10-22')
# historyalln <- data.frame(ds = seq(as.Date('2017-01-01'), as.Date('2017-09-18'), by = 'd'), y = alln$yn)
history30 <- data.frame(ds = seq(as.Date(start), as.Date(end), by = 'd'), y = alln$y2031)
history45 <- data.frame(ds = seq(as.Date(start), as.Date(end), by = 'd'), y = alln$y4050)

      二、设定节假日(数据奇异点)
      设置节假日重点需要说明的是除了周末,还有国内一些法定假期,持续时间还不同,比如国庆和春节持续7天及以上,其他节日都只持续3天,所以节假日大小不同,影响也不同,必须区分对待,为此我设置了两个节假日变量,一个是小节日,持续3天;一个是大型节日,持续7天,代码如下:
holiday1 <- data_frame(
  holiday = 'holiday1',
  ds = as.Date(c(  '2016-01-01','2016-04-04','2016-05-01',
                   '2016-06-09','2016-09-15','2017-01-01',
                   '2017-04-02','2017-04-29','2017-05-28')),
  lower_window = 0,
  upper_window = 3
)
holiday2 <- data_frame(
  holiday = 'holiday2',
  ds = as.Date(c(  '2016-02-07','2016-10-01','2017-01-27',
                   '2017-10-01')),
  lower_window = 0,
  upper_window = 7
)
      另外还有一些公司促销活动期间以及有针对不同人群或者产品的营销等等,如果有时间,尽量都在节假日变量中体现,比如我公司的活动有会员日、加息活动、降息活动、新手活动、邀请活动、平时的一些营销活动等等,我全部用不同的节假日变量输入了,最终整合成一个节假日变量:
holidays365<-bind_rows(holiday1,holiday2,VIP365,raiserate365,raise3652,raise3653,reducerate365,promotion)

      三、训练模型
     为了训练模型和输出模型,我对调参做了一些自动化改进,让参数及预测值成为变量,这样就能循环调参,到时候输出参数和结果我就知道什么参数最为合适了。

sea=c(0.5)
cha=c(0.5,0.6)
hol=c(0.5,5,500)
x<-295
y<-322
b3<-matrix(0,1,32)
for (i in 1:length(sea)){
  for (m in 1:length(cha)){
    for (n in 1:length(hol)){
      n90 <- prophet(history90,
                     holidays = holidays90,
                     seasonality.prior.scale=sea[i],
                     changepoint.prior.scale=cha[m],
                     holidays.prior.scale = hol[n],
                     mcmc.samples = 100,
                     interval.width=0.9,
                     uncertainty.samples = 30)
      future90 <- make_future_dataframe(n90, periods = 30)
      a3<-cbind('90',sea[i],cha[m],hol[n],t(forecast90$yhat[x:y]))
      b3=rbind(b3,a3)
    }}}
b3<-b3[-1,]
colnames(b) <- c("period","sea","cha","hol",as.character(as.Date(end)),as.character(as.Date(end)+1),as.character(as.Date(end)+2),as.character(as.Date(end)+3),as.character(as.Date(end)+4),as.character(as.Date(end)+5),as.character(as.Date(end)+6),as.character(as.Date(end)+7))
write.csv(b3,file = "d:/Rdata/zjd/ts/wkallc.csv")

      上面我给出的参数比较少,各位可以根据自己的想法,在参数组里面多加入一些数值,不过出结果的时间肯定也是成倍增长哦,除了结果之后就能根据参数和相应结果选择合适的参数训练以后的模型了。

      四、输出自定义结果
      最终我设置了6个参数组来训练模型,但为了预测未来30天的成交数据,我还需要每次都查看六个结果,并从中找到最合适的结果。那能不能把这个人工筛选也给自动化了呢?
      在验证了大概一周的数据后(不算那么严谨,请各位见谅),我觉得每个结果之间的相差其实并不大,于是我采取了一个算术平均值的简单筛选方法,帮助我直接找到最终结果;另外针对在输出结果的时可能出现的异常值,如负值和极大值,我直接做了优化处理,代码如下:
c3<-cbind('90',mean(as.numeric(b3[,5])),mean(as.numeric(b3[,6])),mean(as.numeric(b3[,7])),mean(as.numeric(b3[,8])),mean(as.numeric(b3[,9])),mean(as.numeric(b3[,10])),mean(as.numeric(b3[,11])),
          mean(as.numeric(b3[,12])),mean(as.numeric(b3[,13])),mean(as.numeric(b3[,14])),mean(as.numeric(b3[,15])),mean(as.numeric(b3[,16])),mean(as.numeric(b3[,17])),mean(as.numeric(b3[,18])),
          mean(as.numeric(b3[,19])),mean(as.numeric(b3[,20])),mean(as.numeric(b3[,21])),mean(as.numeric(b3[,22])),mean(as.numeric(b3[,23])),mean(as.numeric(b3[,24])),mean(as.numeric(b3[,25])),
          mean(as.numeric(b3[,26])),mean(as.numeric(b3[,27])),mean(as.numeric(b3[,28])),mean(as.numeric(b3[,29])),mean(as.numeric(b3[,30])),mean(as.numeric(b3[,31])),mean(as.numeric(b3[,32])))
for (s in 1:dim(c)[1]){
  for (r in 2:dim(c)[2]){
    if(c[s,r]<0|as.numeric(c[s,r])>500000000) {
      c[s,r]<-as.numeric(c[s,r-1])*0.8}
    }}
colnames(c) <- c("period",as.character(as.Date(end)),as.character(as.Date(end)+1),as.character(as.Date(end)+2),as.character(as.Date(end)+3),as.character(as.Date(end)+4),as.character(as.Date(end)+5),as.character(as.Date(end)+6),
                 as.character(as.Date(end)+7),as.character(as.Date(end)+8),as.character(as.Date(end)+9),as.character(as.Date(end)+10),as.character(as.Date(end)+11),as.character(as.Date(end)+12),as.character(as.Date(end)+13),
                 as.character(as.Date(end)+14),as.character(as.Date(end)+15),as.character(as.Date(end)+16),as.character(as.Date(end)+17),as.character(as.Date(end)+18),as.character(as.Date(end)+19),as.character(as.Date(end)+20),
                 as.character(as.Date(end)+21),as.character(as.Date(end)+22),as.character(as.Date(end)+23),as.character(as.Date(end)+24),as.character(as.Date(end)+25),as.character(as.Date(end)+26),as.character(as.Date(end)+27))
write.csv(c,file = "d:/Rdata/zjd/ts/wkalld.csv")

最终得出的结果直接输出csv,并且可以让业务或者运营人员看懂我的预测情况,方便他们进行后天或者下个月的运营准备。

你可能感兴趣的:(R语言,算法)