class: left, bottom, inverse, title-slide # 商业预测 ## 第2讲:商业预测基础 ### 康雁飞 ### 2019-08-01(更新于2019-09-20) --- class: inverse, center, middle # 我们可以预测什么? --- # 许多情况下都需要预测: - 例如决定是否要在未来五年内建立另一个发电厂需要预测未来的用电需求量。 - 下周呼叫中心的人员日程安排,需要对呼叫量进行预测。 - 库存存货需要库存需求的预测。 - 预测可能是需要提前几年(如资本投资),或者是仅仅提前几分钟(如电信线路)。 --- # 可预测性 可预测性取决于多个因素: 1. 我们对它的影响因素的了解程度; 2. 有多少数据是可用的; 3. 预测是否会影响我们试图预测的事物。 --- # 例:电力需求预测 电力需求可以非常准确地预测。 1. 电力需求很大程度上受温度影响,也受经济状况和日期的影响。 2. 假日,对电力需求的影响较小。 3. 假如有足够的电力需求和天气状况方面的历史数据,并且我们有能力建立一个合适的模型来连接电力需求和关键驱动变量的话,我们的预测可以非常准确。 --- # 例:货币汇率预测 1. 我们可以获取足够的可用的数据。 2. 但是我们对影响汇率的因素知之甚少,并且汇率的预测会对汇率本身产生影响。 3. 如果有明确的预测说汇率将会上涨,那么人们会立刻调整他们的心理价位。 4. 这是“有效市场假说”的一个例子。因此,预言汇率明天会是上涨还是下跌,就如同预言抛一枚硬币它落下将会是正面还是反面一样不可预测。 --- # 什么是好的预测? - 好的预测可以捕捉到历史数据中的真实模式和关系。 - 好的预测不是重复过去发生过未来不会再发生的事情。 - 我们将学习如何区分应该忽略的历史数据中的随机波动,和历史数据中应该建模推断的真实模式。 --- class: inverse, center, middle # 什么是时间序列预测? --- # 时间序列数据 时间序列数据样例包括: * IBM每日股票价格 * 每月降水量 * 亚马逊季度销售结果 * 谷歌年度利润 任何按照时间顺序观察的事物都是时间序列。我们将只考虑定期观察的时间序列 (例如,每小时、每天、每周、每月、每季度、每年)。不规则间隔时间序列也可能出现,但是超出了本课程的范围。 --- # 时间序列预测 在预测时间序列数据时, 目的是**估计观测序列将如何持续到未来**。下图显示从1992年到2010年第二季度的澳大利亚季度啤酒产量。 <img src="BF-L2-basics_files/figure-html/beer-1.png" style="display: block; margin: auto;" /> --- # 案例1 在这个案例中,服务对象是澳大利亚联邦政府,他们需要对药品津贴计划(PBS)的年度预算进行预测。药品津贴计划对在澳大利亚销售的多种医药产品提供补贴,且该项政府支出取决于人们在当年购买的药品种类。2009年药品津贴计划总支出约为70亿澳元,在我们协助制定更准确的预测方法之前的两年中,每年的总支出都低估了近10亿澳元。 为了预测药品津贴计划的总支出,我们首先需要根据月度数据对数百种药品的销售量进行预测。几乎每种药品的销售量数据都包含长期趋势和季节变动模式。很多药品的销量会因药品补贴政策的变化而突然上升或下降,对很多药品的津贴支出也会因出现低价可替代药品而突然发生变化。 因此,我们需要寻找到一种能够对包含长期趋势和季节变动因素的数据进行预测的方法,使得该方法不仅可以对潜在模式下的突然变动进行稳健预测,同时能够处理大样本的时间序列数据。 --- # 案例2 一家大型汽车公司要求我们帮助他们预测汽车转售价格,他们将购入的新车对外出租三年后再次售出。更好的对汽车销售价格进行预测就意味着更多的利润。因此,找到影响汽车转售价格的因素可能会优化租赁和销售政策,从而实现利润最大化。 当时,一群专家正在预测汽车转售价格。他们认为统计模型的建立会对他们的生计造成威胁,因而在提供信息方面不合作。尽管如此,该公司还是给我们提供了大量的车辆和汽车转售价格的历史数据。 --- # 案例3 在这个项目中,我们需要开发一个模型来预测澳大利亚主要航空公司的主要国内航线的周航空客运量。该公司要求对各主要国内航线及各类乘客(经济舱、商务舱和头等舱)的人数进行预测并向我们提供了前6年的航线周历史数据。 航空乘客人数会受到学校假期、重大体育赛事、广告活动、竞争行为等影响。一般情况下,澳大利亚不同城市的学校假期不会同时出现,体育赛事有时也会从一个城市转移到另一个城市。在历史数据相应期间发生过一场关键飞行员的罢工运动,其间几个月都没有相关航线运行,一条新的低价航线推出后也惨遭失败。在历史数据期间的末尾,航空公司将一些经济舱座位重新改造为商务舱和头等舱座位,然而几个月后,座位安排重新恢复到原来的状态。 --- class: inverse, center, middle # 预测的步骤 --- # 预测的步骤 1. 定义问题。最难的一步。需要沟通。 2. 收集信息。需要数据。 3. 初步(探索性)分析。看图形。有一致的模式吗?有明显的长期趋势吗?季节性重要吗?是否有证据表明商业周期存在?数据中是否包含需要专业知识解释的异常值?用于分析的变量之间的相关性有多强? 4. 选择及拟合模型。最佳模型的选择取决于历史数据的可用性、预测变量与各解释变量之间的相关性,以及预测的使用方式。比较两个或三个潜在的模型是很常见的。 5. 使用及评估预测模型。一旦模型及其参数确定后,该模型就可以用来进行预测。模型的预测效果只有用于预测的数据得到之后才能得到正确的评价。 --- class: inverse, center, middle # 时间序列可视化 --- # `ts`对象 时间序列是一组按照时间发生先后顺序进行排列,并且包含一些信息的数据点序列。在R中,这些信息可以被储存在`ts`对象中。 假设我们有某个变量在过去几年中每年的观测值: <table> <thead> <tr> <th style="text-align:right;"> 年份 </th> <th style="text-align:right;"> 观测值 </th> </tr> </thead> <tbody> <tr> <td style="text-align:right;"> 2012 </td> <td style="text-align:right;"> 123 </td> </tr> <tr> <td style="text-align:right;"> 2013 </td> <td style="text-align:right;"> 39 </td> </tr> <tr> <td style="text-align:right;"> 2014 </td> <td style="text-align:right;"> 78 </td> </tr> <tr> <td style="text-align:right;"> 2015 </td> <td style="text-align:right;"> 52 </td> </tr> <tr> <td style="text-align:right;"> 2016 </td> <td style="text-align:right;"> 110 </td> </tr> </tbody> </table> 我们可以采用`ts()`函数将数据转化为`ts`类型: ```r y <- ts(c(123,39,78,52,110), start=2012) ``` --- # `ts`对象 假如一个变量的观测频率大于每年一次,我们可以通过设置`frequency`参数来设置频率。例如,如果我们的月度数据已经被储存在了数值型向量`z`中,那么我们可以用如下的方式将其转换为时间序列: ```r y <- ts(z, start=2003, frequency=12) ``` --- # 时间图 对于时间序列数据而言,我们从最简单的时间图开始。时间图是用将观测值与观测时间点作图,散点之间用直线连接。 .pull-left[ ```r autoplot(melsyd[,"Economy.Class"]) + ggtitle("墨尔本 - 悉尼经济舱乘客客流量") + xlab("年份") + ylab("千")+ theme(text = element_text(family = "STHeiti"))+ theme(plot.title = element_text(hjust = 0.5)) ``` ] .pull-right[ <img src="BF-L2-basics_files/figure-html/ansett-out-1.png" style="display: block; margin: auto;" /> ] ??? 该时间图直观地展现出数据具有的一些特征: - 由于1989年当地的工业纠纷,当年的客流量为0。 - 在1992年中,由于一部分经济舱被商务舱取代,导致客流量大幅减少。 - 1991年下半年客流量大幅上升。 - 由于假日效应,在每年年初,客流量都会有一定幅度的下降。 - 这是序列存在长期波动,在1987年向上波动,在1988年向下波动,而在1990年和1991年又再次向上波动。 - 在某些时期存在缺失值。 --- # 时间序列模式 我们通常使用例如“趋势”、“季节性”等词语描述时间序列。在深入研究时间序列模式时,应该更精确的定义这些词语。 - 趋势:当一个时间序列数据长期增长或者长期下降时,表示该序列有 **趋势** 。在某些场合,趋势代表着“转换方向”。例如从增长的趋势转换为下降趋势。 - 季节性:当时间序列中的数据受到季节性因素(例如一年的时间或者一周的时间)的影响时,表示该序列具有 **季节性** 。 - 周期性:当时间序列数据存在不固定频率的上升和下降时,表示该序列有 **周期性** 。 --- # 它们的模式? <img src="BF-L2-basics_files/figure-html/6-decomp1-1.png" style="display: block; margin: auto;" /> ??? 1. 美国新建房屋销售额(左上)表现出强烈的年度季节性,以及周期为6~10年的周期性。但是数据并没有表现出明显的趋势。 2. 美国国债价格(右上)表示1981年美国国债在芝加哥市场连续100个交易日的价格。可以看出,该序列并没有季节性,但是有明显下降的趋势。假如我们拥有该序列更多的观测数据,我们可以看到这个下降的趋势是一个长期循环的一部分。但是现在我们只有连续100天的数据,它表现出下降的趋势。 3. 澳大利亚月度电力产值数据(左下)明显表现出向上增长的趋势,以及强季节性。但是并不存在周期性。 4. Google收盘股价格(右下)的价格波动没有趋势,季节性和周期性。随机波动没有良好的形态特性,不能很好地预测。 --- # 季节图 季节图和时间序列图很相似,不同之处是季节图是针对观察数据的“季节性”绘制的。下面的例子是降糖药物的销售情况。 .pull-left[ ```r ggseasonplot(a10, year.labels=TRUE, year.labels.left=TRUE) + xlab("月份")+ ylab("百万(美元)") + ggtitle("季节图:降糖药物销量")+ theme(text = element_text(family = "STHeiti"))+ theme(plot.title = element_text(hjust = 0.5)) ``` ] .pull-right[ <img src="BF-L2-basics_files/figure-html/seasonplot1-out-1.png" style="display: block; margin: auto;" /> ] --- # 季节图(极坐标) .pull-left[ ```r ggseasonplot(a10, polar=TRUE) + xlab("月份")+ ylab("百万(美元)") + ggtitle("极坐标季节图:降糖药物销量")+ theme(text = element_text(family = "STHeiti"))+ theme(plot.title = element_text(hjust = 0.5)) ``` ] .pull-right[ <img src="BF-L2-basics_files/figure-html/seasonplot2-out-1.png" style="display: block; margin: auto;" /> ] --- # 滞后图 .pull-left[ 右图是澳大利亚每季度啤酒产量的散点图,横轴表示时间序列的滞后阶数。各图分别显示了不同 `\(k\)` 值下 `\(y_{t}\)` 和 `\(y_{t-k}\)` 的散点图。 ```r beer2 <- window(ausbeer, start=1992) gglagplot(beer2) + ggtitle('') ``` ] .pull-right[ <img src="BF-L2-basics_files/figure-html/beerlagplot-out-1.png" style="display: block; margin: auto;" /> ] --- # 实验2 1. 使用帮助函数了解`gold`、`woolyrnq`和`gas`时间序列 - 使用`autoplot()`分别绘制上述序列。 - 各个序列的频率是多少? 提示:运用`frequency()`函数。 2. `arrivals`数据包括从日本、新西兰、英国和美国到达澳大利亚的人数(千)。请使用`autoplot()`和`ggseasonplot()`函数比较四个国家到达澳大利亚人数的不同之处。你对这些时间序列有什么认识? --- class: inverse, center, middle # 一些简单的预测方法 --- # 均值法 此方法中,所有未来值的预测值等于历史数据的平均值。我们把历史数据记作 `\(y_{1},\dots,y_{T}\)`,预测值就可以表示为: `$$\hat{y}_{T+h|T} = \bar{y} = (y_{1}+\dots+y_{T})/T.$$` ```r meanf(y, h) # y 历史数据时间序列 # h 预测期数 ``` --- # Naïve 方法 在 naïve 预测方法中,我们简单地将所有预测值设为最后一次的观测值,即: `$$\hat{y}_{T+h|T} = y_{T}.$$` 这种方法在很多经济和金融时间序列预测中表现得非常好。 ```r naive(y, h) rwf(y, h) # 二者等价 ``` --- # 季节性 Naïve 方法 季节性 Naïve 方法与 Naïve 方法类似,它适用于季节性变化剧烈的数据。我们将每个预测值设为同一季节的前一期观测值(例如:去年的同一个月)。那么: `$$\hat{y}_{T+h|T} = y_{T+h-km},$$` 等式中 `\(m\)` 为周期长度, `\(k\)` 是 `\((h-1)/m\)` 的整数部分(也就是在 `\(T + h\)` 时刻前预测期所包含的整年数)。 ```r snaive(y, h) ``` --- # 漂移法 相对于 Naïve 方法,趋势法(漂移法)允许预测值随着时间的推移增大或减小,并且我们假定单位时间改变量(称作 “漂移”)等于历史数据的平均改变量,因此 `\(T+h\)` 时刻的预测值可以表示为: `$$\hat{y}_{T+h|T} = y_{T} + \frac{h}{T-1}\sum_{t=2}^T (y_{t}-y_{t-1}) = y_{T} + h \left( \frac{y_{T} -y_{1}}{T-1}\right).$$` 这相当于把第一个观测点和最后一个观测点连成一条直线并延伸到未来预测点。 ```r rwf(y, h, drift=TRUE) ``` --- # 例:啤酒销量预测 .pull-left[ ```r # 设定1992年至2007年为训练数据 beer2 <- window(ausbeer,start=1992,end=c(2007,4)) # 画出预测图 autoplot(beer2) + autolayer(meanf(beer2, h=11)$mean, series="均值") + autolayer(naive(beer2, h=11)$mean, series="Naïve") + autolayer(snaive(beer2, h=11)$mean, series="季节性 naïve") + ggtitle("啤酒季度销量的预测") + xlab("年份") + ylab("百万升") + guides(colour=guide_legend(title="预测")) + theme(text=element_text(family="STHeiti"))+ theme(plot.title = element_text(hjust = 0.5)) ``` ] .pull-right[ <img src="BF-L2-basics_files/figure-html/beerf-out-1.png" style="display: block; margin: auto;" /> ] --- # 例:谷歌股票收盘价预测 .pull-left[ ```r # 画出预测图 autoplot(goog200) + autolayer(meanf(goog200, h=40), PI=FALSE, series="均值") + autolayer(rwf(goog200, h=40), PI=FALSE, series="Naïve") + autolayer(rwf(goog200, drift=TRUE, h=40), PI=FALSE, series="漂移") + ggtitle("每日谷歌股票收盘价(截止到2013年12月6日)的预测") + xlab("天") + ylab("收盘价 (美元)") + guides(colour=guide_legend(title="预测")) + theme(text=element_text(family="STHeiti"))+ theme(plot.title = element_text(hjust = 0.5)) ``` ] .pull-right[ <img src="BF-L2-basics_files/figure-html/googf-out-1.png" style="display: block; margin: auto;" /> ] -- - 有时候这些最简单的方法可能会是最好的预测方法 - 但是在很多情况下,这些方法只是作为基准方法而不是被直接运用。 --- # 评估预测精度 - 使用真实的预测来评估预测精度是很重要的。 - 残差的大小并不能很好地表示真实预测误差的大小。 - 评估模型预测精度只能通过模型在新数据中的预测效果决定。 - 在选择模型时,通常我们会将可用数据分成训练数据集和测试数据集两部分,其中训练数据集用于估计预测方法中的任意参数,而测试数据集用于评估预测精度。 - 由于训练数据集并没有用于确定预测模型,因此它能可靠地检验模型对于新数据的预测准确性。 --- # 评估预测精度 ```r googfc1 <- meanf(goog200, h=40) googfc2 <- rwf(goog200, h=40) googfc3 <- rwf(goog200, drift=TRUE, h=40) googtest <- window(goog, start=201, end=240) accuracy(googfc1, googtest) accuracy(googfc2, googtest) accuracy(googfc3, googtest) ``` --- # 本讲总结 1. 我们可以预测什么? 2. 什么是时间序列预测? 3. 预测的步骤 4. 可视化 5. 一些简单的预测方法