《精通机器学习:基于R 第二版》学习笔记
1、数据理解与数据准备
使用的数据记录的是年度异常数据,它由某一年的年度地表温度中位数与参考年度(1961~1990)平均温度的差构成。
> climate <- read.csv("./data_set/data-master/climate.csv", stringsAsFactors = F)
> str(climate)
## 'data.frame': 95 obs. of 3 variables:
## $ Year: int 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 ...
## $ CO2 : int 806 932 803 845 970 963 975 983 1062 1065 ...
## $ Temp: num -0.272 -0.241 -0.187 -0.301 -0.272 -0.292 -0.214 -0.105 -0.208 -0.206 ...
> summary(climate)
## Year CO2 Temp
## Min. :1919 Min. : 803 Min. :-0.34800
## 1st Qu.:1942 1st Qu.:1316 1st Qu.:-0.13150
## Median :1966 Median :3288 Median : 0.00000
## Mean :1966 Mean :3852 Mean : 0.04773
## 3rd Qu.:1990 3rd Qu.:6081 3rd Qu.: 0.18550
## Max. :2013 Max. :9776 Max. : 0.55600
> # 将其转换为时间序列结构
> climate <- ts(climate[, 2:3], frequency = 1, start = 1919, end = 2013)
首先绘制两个时间序列:
> library(pacman)
> p_load(forecast, tseries, ggfortify)
>
> plot(climate)
从图中可以看出,温度的异常变化大约发生在20世纪70年代中期,那时开始急剧升高。
再看看两个变量之间的相关性:
> cor(climate)
## CO2 Temp
## CO2 1.0000000 0.8404215
## Temp 0.8404215 1.0000000
两个序列是高度相关的。绘制两个序列的ACF图和PACF图,再看看序列结构:
> p_load(patchwork)
>
> p1 <- autoplot(acf(climate[, 2], plot = F), main = "Temp ACF")
> p2 <- autoplot(pacf(climate[, 2], plot = F), main = "Temp PACF")
> p3 <- autoplot(acf(climate[, 1], plot = F), main = "CO2 ACF")
> p4 <- autoplot(pacf(climate[, 1], plot = F), main = "CO2 PACF")
>
> p1 + p2 + p3 + p4 + plot_layout(ncol = 2, nrow = 2)
ACF图中虚线表示显著相关性的置信带,任何一条超出置信带上界和下界的竖线都被认为是显著的相关性。
PACF计算的是条件相关性。
ACF模式是逐渐衰减的,PACF模式则是快速衰减的。可以假设这两个序列都是自回归的,尽管温度中看上去存在明显的MA项。下一步检查交叉相关函数。
> # 函数规定x要放到y的前面
> Ccf(climate[, 1], climate[, 2], main = "CCF")
CCF图展示了温度和二氧化碳延迟序列之间的相关性。如果x变量的负延迟序列具有强相关性,则x领先于y;如果x变量的正延迟序列具有强相关性,则x滞后于y。此处可以看到,二氧化碳既是个领先变量,也是个滞后变量。
检验数据是否平稳:
> # 扩展迪基-福勒检验
> adf.test(climate[, 1])
##
## Augmented Dickey-Fuller Test
##
## data: climate[, 1]
## Dickey-Fuller = -1.1519, Lag order = 4, p-value = 0.9101
## alternative hypothesis: stationary
> adf.test(climate[, 2])
##
## Augmented Dickey-Fuller Test
##
## data: climate[, 2]
## Dickey-Fuller = -1.8106, Lag order = 4, p-value = 0.6546
## alternative hypothesis: stationary
可以看到,对于这两个序列,p值都是不显著的,所以不能拒绝原假设(数据是不稳定的)。
2、模型构建与模型评价
主要有三项任务:
第一,建立一个仅应用于温度数据的单变量预测模型;
第二,基于温度数据本身和二氧化碳排放量数据建立一个温度数据的回归模型;
第三,使用这个模型的输出揭示二氧化碳排放量和地表温度异常之间是否存在格兰杰因果关系。
2.1 单变量时间序列分析
为地表温度建立一个单变量预测模型,时间从二战之后开始:
> temp <- climate[, 2]
>
> # 拆分为训练集和测试集
> train <- window(temp, start = 1946, end = 2003)
> test <- window(temp, start = 2004)
指数平滑模型对过去的观测进行加权。但和移动平均模型不同的是,在指数平滑模型中,相对于更远期的观测来说,越是近期的观测,所得的权重越高。
现在,建立没有阻尼趋势的holt模型:
> # 预测阶段数量h 初始状态值的方法('optimal' 或者 'simple')
> # 'optimal'表示算法会找出最优的初始值以及平滑参数
> # 'simple'表示使用开始的几个观测来计算初始值
> fit.holt <- holt(train, h = 10, initial = "optimal")
>
> # 绘制预测值,看看模型在样本外数据上的预测效果
> plot(forecast(fit.holt))
> lines(test, type = "o")
图中的预测值表现出线性上升趋势。下面加上阻尼趋势:
> fit.holtd <- holt(train, h = 10, initial = "optimal", damped = T)
> plot(forecast(fit.holtd), main = "HOLT Damped")
> lines(test, type = "o")
最后再建立一个ARIMA模型:
> fit.arima <- auto.arima(train)
> summary(fit.arima)
## Series: train
## ARIMA(0,1,1) with drift
##
## Coefficients:
## ma1 drift
## -0.6949 0.0094
## s.e. 0.1041 0.0047
##
## sigma^2 estimated as 0.01273: log likelihood=44.18
## AIC=-82.37 AICc=-81.92 BIC=-76.24
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set -0.0007038922 0.1098561 0.09017707 26.99009 153.2556 0.878048
## ACF1
## Training set 0.1282754
函数选择的模型是MA = 1、I = 1,也就是带有漂移项(等价于截距)的ARIMA(0, 1, 1)。
具有一阶自回归(AR(1))和一阶差分(I(1))的ARIMA模型可以表示为ARIMA(1, 1, 0)。
通过图形检查它在测试数据上的表现:
> plot(forecast(fit.arima, h = 10))
> lines(test, type = "o")
这个图与不带阻尼趋势的holt方法非常相似。通过下面的代码,可以为每种模型打分,找出具有最低误差,即平均绝对百分误差的模型:
> mape.holt <- sum(abs((test - fit.holt$mean)/test))/10
> print(mape.holt)
## [1] 0.2864105
> mape.holtd <- sum(abs((test - fit.holtd$mean)/test))/10
> print(mape.holtd)
## [1] 0.2211337
> mape.arima <- sum(abs((test - forecast(fit.arima, h = 10)$mean)/test))/10
> print(mape.arima)
## [1] 0.1034813
与holt方法相比,ARIMA(0,1,1)的预测误差要稍小一些。很显然,不带阻尼趋势的模型表现最差。
通过统计检验和可视化证据,单变量预测模型的最好选择似乎是ARIMA模型。
2.2 检查因果关系
首先演示残差受到自相关(也称为序列相关)影响而导致的虚假线性回归。
然后,研究两种实现格兰杰因果关系模型的不同方法。第一种是传统方法,其中两个序列都是平稳的。此后看看Toda和Yamamoto(1995)提出的方法,这种方法可以应用于原始数据(有时也称为“水平”)。
2.2.1 线性回归
> fit.lm <- lm(Temp ~ CO2, data = climate)
> summary(fit.lm)
##
## Call:
## lm(formula = Temp ~ CO2, data = climate)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.36411 -0.08986 0.00011 0.09475 0.28763
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2.430e-01 2.357e-02 -10.31 <2e-16 ***
## CO2 7.548e-05 5.047e-06 14.96 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1299 on 93 degrees of freedom
## Multiple R-squared: 0.7063, Adjusted R-squared: 0.7032
## F-statistic: 223.7 on 1 and 93 DF, p-value: < 2.2e-16
所有统计量都是显著的,修正R方的值是0.7032。二氧化碳水平与温度变化高度相关。但是真的是这样吗?
看看残差时间序列图:
> plot.ts(fit.lm$residuals)
能够看出残差具有明显的模式。再看看ACF图:
> acf(fit.lm$residuals)
可以看出,直到10阶延迟序列,都具有显著的自相关。
对自相关性使用Durbin-Watson检验:
> lmtest::dwtest(fit.lm)
##
## Durbin-Watson test
##
## data: fit.lm
## DW = 0.77425, p-value = 4.468e-12
## alternative hypothesis: true autocorrelation is greater than 0
这个检验的原假设是“不存在自相关”,从P值可以拒绝接受原假设,即存在自相关性。
2.2.2 向量自回归
处理自相关的简单方式是,在相关的时间序列中加入延迟变量,使所有数据具有稳定性。下面进行这样的处理,使用向量自回归找出适当的延迟结构,加入我们的因果关系模型。
查看数据是否平稳,使用forecast包提供的ndiffs()函数。从它的输出中可以找出使数据平稳所需的最小差分次数。在这个函数中,你可以选择3种可用的检验方法,分别是:Kwiatkowski, Philips, Schmidt & Shin(KPSS))、Augmented Dickey Fuller(ADF )和Philips-Peron (PP) )。
使用ADF方法,它的原假设认为数据是不平稳的:
> ndiffs(climate[, 1], test = "adf")
## [1] 1
> ndiffs(climate[, 2], test = "adf")
## [1] 1
在两个序列中,一阶差分即可使数据稳定。
> p_load(vars, aod)
> climate.diff <- diff(climate) %>% window(start = 1946)
> head(climate.diff)
## Time Series:
## Start = 1946
## End = 1951
## Frequency = 1
## CO2 Temp
## 1946 78 -0.099
## 1947 154 0.034
## 1948 77 0.001
## 1949 -50 -0.035
## 1950 211 -0.100
## 1951 137 0.121
使用向量自回归在信息准则的基础上确定最优的延迟结构:
> # lag.max = 12 指定模型中延迟的最大数量为12
> lag.select <- VARselect(climate.diff, lag.max = 12)
> lag.select$selection
## AIC(n) HQ(n) SC(n) FPE(n)
## 5 1 1 5
能够看到,AIC和FPE都选择了5阶延迟作为VAR模型的最优结构,HQ和SC则选择了一阶延迟。我们使用 var() 函数建立这个5阶延迟模型:
> fit.5 <- VAR(climate.diff, p = 5)
> summary(fit.5)
##
## VAR Estimation Results:
## =========================
## Endogenous variables: CO2, Temp
## Deterministic variables: const
## Sample size: 63
## Log Likelihood: -324.566
## Roots of the characteristic polynomial:
## 0.8403 0.8215 0.8215 0.8084 0.8084 0.7843 0.7843 0.7677 0.6263 0.6263
## Call:
## VAR(y = climate.diff, p = 5)
##
##
## Estimation results for equation CO2:
## ====================================
## CO2 = CO2.l1 + Temp.l1 + CO2.l2 + Temp.l2 + CO2.l3 + Temp.l3 + CO2.l4 + Temp.l4 + CO2.l5 + Temp.l5 + const
##
## Estimate Std. Error t value Pr(>|t|)
## CO2.l1 0.29287 0.13824 2.119 0.03892 *
## Temp.l1 -61.55494 150.85121 -0.408 0.68491
## CO2.l2 -0.04541 0.13870 -0.327 0.74470
## Temp.l2 -205.75318 166.79706 -1.234 0.22292
## CO2.l3 0.16232 0.13924 1.166 0.24904
## Temp.l3 -145.88236 173.15840 -0.842 0.40338
## CO2.l4 -0.09110 0.15722 -0.579 0.56478
## Temp.l4 -283.42320 168.28093 -1.684 0.09813 .
## CO2.l5 0.01977 0.16048 0.123 0.90243
## Temp.l5 -163.78328 152.94657 -1.071 0.28918
## const 92.06065 32.20407 2.859 0.00611 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
##
## Residual standard error: 122.3 on 52 degrees of freedom
## Multiple R-Squared: 0.1741, Adjusted R-squared: 0.01528
## F-statistic: 1.096 on 10 and 52 DF, p-value: 0.3825
##
##
## Estimation results for equation Temp:
## =====================================
## Temp = CO2.l1 + Temp.l1 + CO2.l2 + Temp.l2 + CO2.l3 + Temp.l3 + CO2.l4 + Temp.l4 + CO2.l5 + Temp.l5 + const
##
## Estimate Std. Error t value Pr(>|t|)
## CO2.l1 -0.0001160 0.0001137 -1.020 0.312335
## Temp.l1 -0.4924759 0.1240984 -3.968 0.000223 ***
## CO2.l2 0.0002298 0.0001141 2.014 0.049184 *
## Temp.l2 -0.5063847 0.1372163 -3.690 0.000537 ***
## CO2.l3 -0.0000390 0.0001146 -0.340 0.734860
## Temp.l3 -0.4120790 0.1424495 -2.893 0.005565 **
## CO2.l4 0.0001222 0.0001293 0.945 0.349264
## Temp.l4 0.0423256 0.1384370 0.306 0.761024
## CO2.l5 -0.0003945 0.0001320 -2.988 0.004280 **
## Temp.l5 -0.2035228 0.1258221 -1.618 0.111812
## const 0.0472094 0.0264928 1.782 0.080594 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
##
## Residual standard error: 0.1006 on 52 degrees of freedom
## Multiple R-Squared: 0.4509, Adjusted R-squared: 0.3453
## F-statistic: 4.27 on 10 and 52 DF, p-value: 0.0002326
##
##
##
## Covariance matrix of residuals:
## CO2 Temp
## CO2 14955.464 -1.09780
## Temp -1.098 0.01012
##
## Correlation matrix of residuals:
## CO2 Temp
## CO2 1.00000 -0.08923
## Temp -0.08923 1.00000
模型是显著的(p-value: 0.0002326),修正R方为0.35。
检查序列相关性:
> serial.test(fit.5, type = "PT.asymptotic")
##
## Portmanteau Test (asymptotic)
##
## data: Residuals of VAR object fit.5
## Chi-squared = 35.912, df = 44, p-value = 0.8021
Portmanteau检验的原假设认为自相关为0,备择假设认为自相关不为0。p-value = 0.8021不能拒绝原假设,可以认为残差中不存在自相关。
下面进行格兰杰因果关系检验:
> # 建立两个对象,一个表示x引发y,一个表示y引发x
> x2y <- causality(fit.5, cause = "CO2")
> y2x <- causality(fit.5, cause = "Temp")
>
> x2y$Granger
##
## Granger causality H0: CO2 do not Granger-cause Temp
##
## data: VAR object fit.5
## F-Test = 2.2069, df1 = 5, df2 = 104, p-value = 0.05908
> y2x$Granger
##
## Granger causality H0: Temp do not Granger-cause CO2
##
## data: VAR object fit.5
## F-Test = 0.66783, df1 = 5, df2 = 104, p-value = 0.6487
二氧化碳变化是引发温度变化的格兰杰原因”的p值为0.05908,另一个方向则是不显著的。首先,可以认为y不是引发x的原因。至于x引发y,我们不能在0.05的显著性水平上拒绝原假设。所以,可以得出结论:x不是y的格兰杰原因。
使用另外一种格兰杰因果关系技术来为初始的二氧化碳排放数据建模。找到正确延迟数量的过程和前面基本一样,区别在于不需要使数据平稳:
> climate.levels <- window(climate, start = 1946)
> level.select <- VARselect(climate.levels, lag.max = 12)
> level.select$selection
## AIC(n) HQ(n) SC(n) FPE(n)
## 10 1 1 6
尝试一下6阶延迟结构,看看能否得到显著的结果:
> fit.6 <- VAR(climate.levels, p = 6)
> serial.test(fit.6, type = "PT.asymptotic")
##
## Portmanteau Test (asymptotic)
##
## data: Residuals of VAR object fit.6
## Chi-squared = 37.03, df = 40, p-value = 0.6047
看看二氧化碳排放量是否是温度变化的格兰杰原因:
> co2.terms <- seq(1, 11, 2)
> temp.terms <- seq(2, 12, 2)
>
> # Wald检验
> wald.test(b = coef(fit.6$varresult$Temp), Sigma = vcov(fit.6$varresult$Temp), Terms = c(co2.terms))
## Wald test:
## ----------
##
## Chi-squared test:
## X2 = 16.2, df = 6, P(> X2) = 0.013
p值小于0.05,再检验因果关系的另一个方向:
> wald.test(b = coef(fit.6$varresult$CO2), Sigma = vcov(fit.6$varresult$CO2), Terms = c(temp.terms))
## Wald test:
## ----------
##
## Chi-squared test:
## X2 = 8.0, df = 6, P(> X2) = 0.24
最后使用向量自回归进行预测:
> autoplot(predict(fit.6, n.ahead = 25, ci = 0.95))
总结:
1.单变量和双变量时间序列分析;
2.格兰杰因果关系模型;
3.以上分析只是时间序列分析的皮毛。