month,
year and approve columns. Describe the range
of the time series. Do you think the data set contains enough
observations?# 1. Загрузка данных и выбор колонок
setwd("/Users/andreii/Documents/R_files/ds_hw1")
data <- read.csv("approval.csv")
data <- data %>% select(month, year, approve)
summary(data)
## month year approve
## Min. : 1.000 Min. :2001 Min. :35.67
## 1st Qu.: 3.000 1st Qu.:2002 1st Qu.:48.50
## Median : 6.000 Median :2003 Median :54.67
## Mean : 6.308 Mean :2003 Mean :57.17
## 3rd Qu.: 9.000 3rd Qu.:2005 3rd Qu.:65.20
## Max. :12.000 Max. :2006 Max. :88.00
date column with
paste0 function or any way you come up with. Apply the
as.Date function and assign %Y-%m-%d date
format.data$date <- as.Date(paste0(data$year, "-", data$month, "-01"), "%Y-%m-%d")
ggplot2. Add a mean line. Visually inspect
the series and guess whether it is stationary or not. Justify your
answer with the appropriate statistics.data %>%
ggplot(aes(x = date, y = approve)) +
geom_line() +
geom_hline(yintercept = mean(data$approve, na.rm = TRUE), col = "red")
adf_result <- adf.test(na.omit(data$approve))
pp_result <- pp.test(na.omit(data$approve))
kpss_result <- kpss.test(na.omit(data$approve))
## Warning in kpss.test(na.omit(data$approve)): p-value smaller than printed
## p-value
results_table <- data.frame(
Test = c("ADF", "PP", "KPSS"),
H0 = c("Non-stationary", "Non-stationary", "Stationary"),
p_value = c(adf_result$p.value, pp_result$p.value, kpss_result$p.value),
Decision = c(ifelse(adf_result$p.value < 0.05, "Stationary", "Non-stationary"),
ifelse(pp_result$p.value < 0.05, "Stationary", "Non-stationary"),
ifelse(kpss_result$p.value < 0.05, "Non-stationary", "Stationary"))
)
results_table
par(mfrow = c(1, 2))
acf(na.omit(data$approve))
pacf(na.omit(data$approve))
arima_model <- arima(data$approve, c(1,0,1))
data$fitted <- fitted(arima_model)
ggplot(data, aes(x = date)) +
geom_line(aes(y = approve), col = "black") +
geom_line(aes(y = fitted), col = "red")
data$approve_diff <- c(NA, diff(data$approve))
plot.ts(na.omit(data$approve_diff))
par(mfrow = c(1, 2))
acf(na.omit(data$approve_diff))
pacf(na.omit(data$approve_diff))
date column. Rename the column with
an approval share to approve.gallup <- read_dta("/Users/andreii/Documents/R_files/ds_hw1/approval_gallup.dta")
skim(gallup)
| Name | gallup |
| Number of rows | 541 |
| Number of columns | 13 |
| _______________________ | |
| Column type frequency: | |
| character | 6 |
| numeric | 7 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| pres | 0 | 1 | 4 | 10 | 0 | 9 | 0 |
| poll | 0 | 1 | 6 | 6 | 0 | 1 | 0 |
| polltype | 0 | 1 | 0 | 8 | 533 | 2 | 0 |
| month2 | 0 | 1 | 1 | 2 | 0 | 12 | 0 |
| year2 | 0 | 1 | 4 | 4 | 0 | 48 | 0 |
| time | 0 | 1 | 6 | 7 | 0 | 541 | 0 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| month | 0 | 1.00 | 6.42 | 3.45 | 1 | 3 | 6 | 9 | 12 | ▇▆▅▅▇ |
| year | 0 | 1.00 | 1976.79 | 13.95 | 1953 | 1965 | 1977 | 1989 | 2000 | ▇▇▇▇▇ |
| papp | 0 | 1.00 | 56.19 | 11.94 | 24 | 48 | 57 | 65 | 89 | ▁▅▇▅▁ |
| disapprove | 0 | 1.00 | 31.81 | 12.77 | 2 | 22 | 32 | 41 | 65 | ▂▆▇▅▁ |
| none | 0 | 1.00 | 12.03 | 4.78 | 2 | 9 | 12 | 14 | 43 | ▆▇▁▁▁ |
| pollsize | 123 | 0.77 | 1400.14 | 318.08 | 615 | 1039 | 1518 | 1558 | 3077 | ▃▇▁▁▁ |
| date | 0 | 1.00 | 206.94 | 167.51 | -83 | 63 | 212 | 355 | 491 | ▇▇▇▇▇ |
gallup$date <- as.Date(paste0(gallup$year, "-", gallup$month, "-01"), "%Y-%m-%d")
names(gallup)[names(gallup) == "papp"] <- "approve"
(1.5 points) Do all the steps from the previous part on the approval_gallup data set. Inspect time series properties both visually and technically (employing formal unit root tests). Describe all the steps by commenting the code.
# 9.1 Визуализация
gallup %>%
ggplot(aes(x = date, y = approve)) +
geom_line()
# 9.2 Unit-root тесты
adf.test(na.omit(gallup$approve))
##
## Augmented Dickey-Fuller Test
##
## data: na.omit(gallup$approve)
## Dickey-Fuller = -3.7492, Lag order = 8, p-value = 0.02154
## alternative hypothesis: stationary
pp.test(na.omit(gallup$approve))
## Warning in pp.test(na.omit(gallup$approve)): p-value smaller than printed
## p-value
##
## Phillips-Perron Unit Root Test
##
## data: na.omit(gallup$approve)
## Dickey-Fuller Z(alpha) = -52.203, Truncation lag parameter = 6, p-value
## = 0.01
## alternative hypothesis: stationary
kpss.test(na.omit(gallup$approve))
## Warning in kpss.test(na.omit(gallup$approve)): p-value smaller than printed
## p-value
##
## KPSS Test for Level Stationarity
##
## data: na.omit(gallup$approve)
## KPSS Level = 1.2296, Truncation lag parameter = 6, p-value = 0.01
# 9.3 ACF/PACF и ARIMA
par(mfrow = c(1, 2))
acf(na.omit(gallup$approve))
pacf(na.omit(gallup$approve))
manual_arima <- arima(gallup$approve, c(1,1,1))
# 9.4 Auto-ARIMA
auto_model <- auto.arima(gallup$approve)
AIC(manual_arima)
## [1] 3326.202
AIC(auto_model)
## [1] 3324.202
(1 point) Now join two data sets in one called
ts_approval. Visualise it. Do you still believe it is
stationary? In fact, there are plenty of missings in the resulting data
set. It might cause some problems with data wrangling and model fitting.
For example, you have a missing for 2001-01-01. Try to
insert 65% presidential approval to the time point. Let’s
try to find all missings in the time series:
lapply algorithm to find the missed
months. Try to figure out what’s going on under the hood of the
function.seq(start, by='1 month', length=<number of months in a period of interest>).
This should result in sequential list of months from February 1953 to
June 2006.data.frame(date=full_vector, approve=with(<your merged data set>, approve[match(full_vector, date)])).
Describe the patterns in missing data.approve column a timeseries (ts) object with
an appropriate time span.ggplot_na_distribution(<your ts>) from
imputeTS package to your time series to inspect the
missigness pattern. Could you believe the missings are at random?na_mean algorithm
from the same imputeTS package. Are you satisfied with a
quality of imputation? Find the better algorithm from the cheat sheet
provided in the Google Drive class folder. Proceed with the best
imputation technique.# 10. Объединение датасетов
ts_approval <- full_join(data, gallup, by = "date", suffix = c("_1", "_2"))
ts_approval$approve <- coalesce(ts_approval$approve_1, ts_approval$approve_2)
ts_approval <- ts_approval %>% select(date, approve) %>% arrange(date)
# Вставка значения для 2001-01-01
ts_approval[ts_approval$date == "2001-01-01", "approve"] <- 65
# Поиск пропущенных месяцев
start_date <- min(ts_approval$date, na.rm = TRUE)
end_date <- max(ts_approval$date, na.rm = TRUE)
full_vector <- seq(start_date, end_date, by = "1 month")
df_nans <- data.frame(
date = full_vector,
approve = with(ts_approval, approve[match(full_vector, date)])
)
# Создание ts объекта и импутация
ts_obj <- ts(df_nans$approve, start = c(1953, 2), frequency = 12)
ggplot_na_distribution(ts_obj)
# Импутация
ts_imputed <- na_interpolation(ts_obj, option = "spline")
df_nans$approve_imputed <- as.numeric(ts_imputed)
URL: https://cran.rstudio.com/web/packages/imputeTS/vignettes/Cheat_Sheet_imputeTS.pdf
seasonal argument to FALSE).
Choose the \(p,i,q\), based on the
plots and tests you used above.arima_imputed <- arima(ts_imputed, c(1,1,1))
auto-arima by residual diagnostics.
Describe the behaviour of residuals. What’s unusual in the distribution
of the residuals?auto_imputed <- auto.arima(ts_imputed, seasonal = FALSE)
# Диагностика остатков
checkresiduals(arima_imputed)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(1,1,1)
## Q* = 28.205, df = 22, p-value = 0.169
##
## Model df: 2. Total lags used: 24
checkresiduals(auto_imputed)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,1,1)
## Q* = 27.971, df = 23, p-value = 0.2169
##
## Model df: 1. Total lags used: 24
econ <- read.csv("/Users/andreii/Documents/R_files/ds_hw1/econ_join.csv", sep = ";")
skim(econ)
| Name | econ |
| Number of rows | 148 |
| Number of columns | 12 |
| _______________________ | |
| Column type frequency: | |
| character | 1 |
| numeric | 11 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| Date | 0 | 1 | 10 | 10 | 0 | 148 | 0 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| X | 0 | 1.00 | 74.50 | 42.87 | 1.0 | 37.75 | 74.50 | 111.25 | 148.0 | ▇▇▇▇▇ |
| econ_join | 0 | 1.00 | 20.03 | 5.01 | 8.0 | 17.00 | 20.00 | 23.25 | 33.0 | ▂▆▇▅▁ |
| econ_join_lag | 7 | 0.95 | 20.08 | 5.06 | 8.0 | 17.00 | 20.00 | 24.00 | 33.0 | ▂▆▇▅▁ |
| net_way | 10 | 0.93 | -1.59 | 25.96 | -71.0 | -12.00 | 1.50 | 15.00 | 42.0 | ▁▁▃▇▃ |
| net_way_lag | 14 | 0.91 | -1.70 | 26.30 | -74.0 | -14.00 | 2.00 | 16.00 | 44.0 | ▁▁▃▇▃ |
| unemployment | 10 | 0.93 | 7.55 | 2.29 | 4.0 | 5.60 | 7.15 | 8.60 | 14.1 | ▇▇▅▂▁ |
| unemployment_lag | 9 | 0.94 | 7.63 | 2.31 | 4.1 | 5.60 | 7.30 | 9.00 | 14.6 | ▇▇▅▃▁ |
| cpi | 10 | 0.93 | 1.25 | 3.35 | -0.3 | 0.40 | 0.70 | 1.30 | 38.4 | ▇▁▁▁▁ |
| cpi_lag | 9 | 0.94 | 1.01 | 1.22 | -0.5 | 0.40 | 0.80 | 1.20 | 11.6 | ▇▁▁▁▁ |
| misery | 10 | 0.93 | 8.80 | 4.60 | 4.1 | 6.20 | 8.00 | 10.28 | 50.3 | ▇▁▁▁▁ |
| misery_lag | 9 | 0.94 | 8.65 | 3.09 | 4.4 | 6.30 | 7.80 | 10.40 | 24.8 | ▇▅▁▁▁ |
# DLM модель
dlm <- lm(econ_join ~ lag(unemployment, 1) + lag(unemployment, 2) + lag(unemployment, 3), data = econ)
summary(dlm)
##
## Call:
## lm(formula = econ_join ~ lag(unemployment, 1) + lag(unemployment,
## 2) + lag(unemployment, 3), data = econ)
##
## Residuals:
## Min 1Q Median 3Q Max
## -10.1123 -3.1799 -0.4367 2.5088 12.9853
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 12.4588 1.3531 9.208 6.61e-16 ***
## lag(unemployment, 1) 1.2719 0.6084 2.091 0.0385 *
## lag(unemployment, 2) 0.6919 0.8132 0.851 0.3964
## lag(unemployment, 3) -0.9572 0.6098 -1.570 0.1189
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.476 on 132 degrees of freedom
## (12 observations deleted due to missingness)
## Multiple R-squared: 0.2406, Adjusted R-squared: 0.2234
## F-statistic: 13.94 on 3 and 132 DF, p-value: 5.954e-08
# ADL модель
adl <- lm(econ_join ~ lag(unemployment, 1) + lag(unemployment, 1) + lag(unemployment, 2), data = econ)
summary(adl)
##
## Call:
## lm(formula = econ_join ~ lag(unemployment, 1) + lag(unemployment,
## 1) + lag(unemployment, 2), data = econ)
##
## Residuals:
## Min 1Q Median 3Q Max
## -9.7697 -3.2884 -0.5057 2.8459 12.9976
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 12.1668 1.3402 9.078 1.24e-15 ***
## lag(unemployment, 1) 1.1716 0.6076 1.928 0.0559 .
## lag(unemployment, 2) -0.1342 0.6101 -0.220 0.8262
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.492 on 134 degrees of freedom
## (11 observations deleted due to missingness)
## Multiple R-squared: 0.2237, Adjusted R-squared: 0.2121
## F-statistic: 19.31 on 2 and 134 DF, p-value: 4.274e-08
dynlm package and some others from seminar on orange
juice, run the dynamic linear model, explaining a share of those who
think the country goes wrong way by unemployment. Choose an appropriate
number of lags and plot dynamic and cumulative effects.library(dynlm)
# Подготовка данных
time_data <- read.csv("/Users/andreii/Documents/R_files/ds_hw1/time.csv", sep=";")
ts_wrongway <- ts(time_data$wrongway, start = c(2000, 1), frequency = 12)
ts_unemp <- ts(time_data$unemployment, start = c(2000, 1), frequency = 12)
# Динамическая модель
dyn_model <- dynlm(ts_wrongway ~ L(ts_unemp, 0:4))
# Динамические эффекты
dynamic_effects <- coef(dyn_model)[-1]
cumulative_effects <- cumsum(dynamic_effects)
# Визуализация
par(mfrow = c(1, 2))
plot(0:4, dynamic_effects, type = "b", main = "Dynamic Effects")
plot(0:4, cumulative_effects, type = "b", main = "Cumulative Effects")