---
title: "Code for Session 3"
author: "Dr. Richard M. Crowley"
format:
  html:
    code-tools: true
    code-link: true
    embed-resources: true
---

Note that the directories used to store data are likely different on your computer, and such references will need to be changed before using any such code.

```{r helpers, warning=FALSE, message=F}
library(knitr)
library(kableExtra)

#' Pretty formatted HTML tables
#' 
#' @param df The dataframe to format as a table
#' @param names Names to use for columns if not using the df column names. Vector
#' @param highlight_cols Columns to highlight. Default is c(1) for highlighting the first row. Use c() to remove.
#' @param highlight_rows Rows to highlight. Default is c() to not highlight any rows.
#' @param color_rows Rows to highlight in color. Default is c() to not highlight any rows.
#' @param highlight_end_rows Rows to highlight. Uses a reverse indexing where 1 is the last row, 2 is second to last, etc.
#' @param full Use to span the full width of a slide. FALSE by default.
#' @param fixed_header Whether the first row should be treated as a header row. TRUE by default.
html_df <- function(df, names=NULL, highlight_cols=c(1), highlight_rows=c(), color_rows=c(), highlight_end_rows=c(), full=F, fixed_header=T) {
  if(!length(names)) {
    names=colnames(df)
  }
  kbl(df,"html", col.names = names, align = c("l",rep('c',length(cols)-1))) %>%
    kable_paper(c("striped","hover"), full_width=full, fixed_thead=F, html_font = "\"Source Sans Pro\", Helvetica, sans-serif") %>%
    {if(length(highlight_cols)) column_spec(., highlight_cols,bold=T, background = "#ffffff99") else .} %>%
    {if(length(highlight_rows)) row_spec(., highlight_rows,bold=T, background = "#ffffff99") else .} %>%
    {if(length(color_rows)) row_spec(., color_rows,bold=T, background = "#aaaaff99") else .} %>%
    {if(length(highlight_end_rows)) row_spec(., nrow(df) + 1 - highlight_end_rows,bold=T, background = "#ffffff99") else .}
}

library(tidyverse)
```

```{r}
#| include: false

library(tidyverse)
df <- read.csv("../../Data/Session_3-1.csv", stringsAsFactors=FALSE)

# load in relevant data from Session 2
load("../../Data/Session_2_export.RData")
```

```{r}
#| include: false
#| eval: false

wmt <- filter(df, tic == "WMT") %>%
  select(tic, fyearq, fqtr, revtq) %>%
  mutate(revtq_lag=lag(revtq))
write_csv(wmt, '../shiny/S3/data/S3.csv')



wmt_training <- filter(wmt, fyearq < 2015)
wmt_testing <- filter(wmt, fyearq >= 2015)
mod1 <- lm(revtq ~ revtq_lag, data=wmt_training)
mod2 <- lm(revtq ~ revtq_lag:factor(fqtr), data=wmt_training)

saveRDS(mod1, "../shiny/S3/data/S3_mod1.rds")
saveRDS(mod2, "../shiny/S3/data/S3_mod2.rds")

# For session 4:
# Data is from: https://fred.stlouisfed.org/series/JHDUSRGDPBR
df_fed <- read_csv('../../Data/Session_4_Fed.csv') %>%
  rename(recession = 2)
  
library(lubridate)
df_fed <- df_fed %>%
  mutate(date = ymd(DATE),
         fyearq = year(date),
         fqtr = quarter(date)) %>%
  select(fyearq, fqtr, recession)
wmt <- wmt %>% left_join(df_fed)
write_csv(wmt, '../shiny/S4/data/S4.csv')

# For session 5
wmt <- wmt %>% select(-revtq_lag) %>%
  mutate(revtq_yoy = (revtq - lag(revtq, 4)) / lag(revtq, 4),
         recession_lag = lag(recession),
         revtq_down = factor(ifelse(revtq_yoy<0,1,0), levels=c(0,1)),
         revtq_yoy_lag = lag(revtq_yoy),
         date = fyearq + (fqtr-1)/4)

s5mod1 <- glm(revtq_down ~ revtq_yoy_lag, data=df, family=binomial)

wmt2 <- wmt
wmt2$pred <- predict(s5mod1, wmt2, type="response")
wmt2 <- wmt2 %>% filter(!is.na(revtq_down), !is.na(pred))

write_csv(wmt, '../shiny/S5/data/S5_1.csv')
write_csv(wmt2, '../shiny/S5/data/S5_2.csv')
saveRDS(s5mod1, "../shiny/S5/data/S5_mod1.rds")

```

```{r}
forecast3.1 <-
  lm(revt_lead ~ revt + act + che + lct + dp + ebit + factor(isin),
     data=df_clean[df_clean$fic=="SGP",])
# n=15 to prevent outputting every fixed effect
library(broom)
print(tidy(forecast3.1), n=15)
```

```{r}
glance(forecast3.1)
anova(forecast3, forecast3.1, test="Chisq")
```

```{r, message=F, error=F, warning=F}
library(fixest)
forecast3.2 <-
  feols(revt_lead ~ revt + act + che + lct + dp + ebit | isin,
       data=df_clean[df_clean$fic=="SGP",])
summary(forecast3.2)
```

```{r, message=F, fig.height=4}
library(tidyverse)
df_clean %>%
  filter(fic=="SGP") %>%
  group_by(isin) %>%
  mutate(mean_revt_lead=mean(revt_lead, na.rm=T)) %>%
  slice(1) %>%
  ungroup() %>%
  ggplot(aes(x=mean_revt_lead)) + geom_histogram(aes(y = ..density..)) +  geom_density(alpha=.4, fill="#FF6666")
```

```{r, message=F, warning=F}
library(tidyverse)  # As always
library(plotly)  # interactive graphs
library(lubridate)  # import some sensible date functions

# Generate quarter over quarter growth "revtq_gr"
df <- df %>% group_by(gvkey) %>% mutate(revtq_gr=revtq / lag(revtq) - 1) %>% ungroup()

# Generate year-over-year growth "revtq_yoy"
df <- df %>% group_by(gvkey) %>% mutate(revtq_yoy=revtq / lag(revtq, 4) - 1) %>% ungroup()

# Generate first difference "revtq_d"
df <- df %>% group_by(gvkey) %>% mutate(revtq_d=revtq - lag(revtq)) %>% ungroup()

# Generate a proper date
# Date was YYYY-MM-DD, can be converted from text to date easily
df$date <- ymd(df$datadate)  # From lubridate
df$qtr <- quarter(df$date)   # From lubridate
```

```{r}
html_df(head(df[,c("conm","date","revtq","revtq_gr", "revtq_yoy", "revtq_d")]))

head(df[,c("conm","date", "datadate")])
```

```{r}
# Make a copy of our data frame to compare later
df2 <- df
```

```{r, message=F}
# Approach #2: Mixing purrr with dplyr across()
library(purrr)

multi_lag_map <- function(df, lags, var, postfix="") {
  new_columns <- map(lags,
    function(x) df %>% 
      group_by(gvkey) %>%
      transmute(across(all_of(var),
                       .fns = list(~ lag(., x)),
                       .names = paste0('{col}', postfix, x) ) ) %>%
      ungroup() %>%
      select(-gvkey)
      )
  cbind(df, list_cbind(new_columns))
}
```

```{r, message=F}
# Approach #3: Advanced programming using quosures...
library(rlang)
multi_lag <- function(df, lags, var, postfix="") {
  var <- enquo(var)
  quosures <- map(lags, ~quo(lag(!!var, !!.x))) %>%
    set_names(paste0(quo_text(var), postfix, lags))
  return(ungroup(mutate(group_by(df, gvkey), !!!quosures)))
}
```

```{r}
df <- multi_lag_map(df, 1:8, 'revtq', "_l")  # Generate lags "revtq_l#"
df <- multi_lag_map(df, 1:8, 'revtq_gr')     # Generate changes "revtq_gr#"
df <- multi_lag_map(df, 1:8, 'revtq_yoy')    # Generate year-over-year changes "revtq_yoy#"
df <- multi_lag_map(df, 1:8, 'revtq_d')      # Generate first differences "revtq_d#"
```

```{r}
df2 <- multi_lag(df2, 1:8, revtq, "_l")  # Generate lags "revtq_l#"
df2 <- multi_lag(df2, 1:8, revtq_gr)     # Generate changes "revtq_gr#"
df2 <- multi_lag(df2, 1:8, revtq_yoy)    # Generate year-over-year changes "revtq_yoy#"
df2 <- multi_lag(df2, 1:8, revtq_d)      # Generate first differences "revtq_d#"
```

```{r}
all(df==df2, na.rm=T)
```

```{r}
html_df(head(df[,c("conm","date","revtq","revtq_l1", "revtq_l2", "revtq_l3", "revtq_l4")]))
```

```{r}
# Clean the data: Replace NaN, Inf, and -Inf with NA
df <- df %>%
  mutate(across(where(is.numeric), ~replace(., !is.finite(.), NA)))

# Split into training and testing data
# Training data: We'll use data released before 2018
train <- filter(df, year(date) < 2018)

# Testing data: We'll use data released 2018 through 2023
test <- filter(df, year(date) >= 2018)
```

```{r, message=F, warning=F}
summary(df[,c("revtq","revtq_gr","revtq_yoy", "revtq_d","qtr")])
```

```{r}
# These functions are a bit ugly, but can construct many charts quickly
# eval(parse(text=var)) is just a way to convert the string name to a variable reference
# Density plot for 1st to 99th percentile of data
plt_dist <- function(df,var) {
  df %>%
    filter(eval(parse(text=var)) < quantile(eval(parse(text=var)),0.99, na.rm=TRUE),
           eval(parse(text=var)) > quantile(eval(parse(text=var)),0.01, na.rm=TRUE)) %>%
    ggplot(aes(x=eval(parse(text=var)))) + 
    geom_density() + xlab(var)
}
```

```{r}
# Density plot for 1st to 99th percentile of both columns
plt_bar <- function(df,var) {
  df %>%
    filter(eval(parse(text=var)) < quantile(eval(parse(text=var)),0.99, na.rm=TRUE),
           eval(parse(text=var)) > quantile(eval(parse(text=var)),0.01, na.rm=TRUE)) %>%
    ggplot(aes(y=eval(parse(text=var)), x=qtr)) + 
    geom_bar(stat = "summary", fun.y = "mean") + ylab(var) + xlab("Calendar quarter")
}
```

```{r}
# Scatter plot with lag for 1st to 99th percentile of data
plt_sct <- function(df,var1, var2) {
  df %>%
    filter(eval(parse(text=var1)) < quantile(eval(parse(text=var1)),0.99, na.rm=TRUE),
           eval(parse(text=var2)) < quantile(eval(parse(text=var2)),0.99, na.rm=TRUE),
           eval(parse(text=var1)) > quantile(eval(parse(text=var1)),0.01, na.rm=TRUE),
           eval(parse(text=var2)) > quantile(eval(parse(text=var2)),0.01, na.rm=TRUE)) %>%
    ggplot(aes(y=eval(parse(text=var1)), x=eval(parse(text=var2)), color=factor(qtr))) + 
    geom_point() + geom_smooth(method = "lm") + ylab(var1) + xlab(var2)
}
```

```{r, message=F, warning=F, fig.height=3}
plt_dist(train, "revtq")
```

```{r, message=F, warning=F, fig.height=3}
plt_dist(train, "revtq_gr")
```

```{r, message=F, warning=F, fig.height=3}
plt_dist(train, "revtq_yoy")
```

```{r, message=F, warning=F, fig.height=3}
plt_dist(train, "revtq_d")
```

```{r, message=F, warning=F, fig.height=3}
plt_bar(train, "revtq")
```

```{r, message=F, warning=F, fig.height=3}
plt_bar(train, "revtq_gr")
```

```{r, message=F, warning=F, fig.height=3}
plt_bar(train, "revtq_yoy")
```

```{r, message=F, warning=F, fig.height=3}
plt_bar(train, "revtq_d")
```

```{r, message=F, warning=F, fig.height=3}
plt_sct(train, "revtq", "revtq_l1")
```

```{r, message=F, warning=F, fig.height=3}
plt_sct(train, "revtq_gr", "revtq_gr1")
```

```{r, message=F, warning=F, fig.height=3}
plt_sct(train, "revtq_yoy", "revtq_yoy1")
```

```{r, message=F, warning=F, fig.height=3}
plt_sct(train, "revtq_d", "revtq_d1")
```

```{r}
cor(train[,c("revtq","revtq_l1","revtq_l2","revtq_l3", "revtq_l4")],
    use="complete.obs")
```

```{r}
cor(train[,c("revtq_gr","revtq_gr1","revtq_gr2","revtq_gr3", "revtq_gr4")],
    use="complete.obs")
```

```{r}
cor(train[,c("revtq_yoy","revtq_yoy1","revtq_yoy2","revtq_yoy3", "revtq_yoy4")],
    use="complete.obs")
```

```{r}
cor(train[,c("revtq_d","revtq_d1","revtq_d2","revtq_d3", "revtq_d4")],
    use="complete.obs")
```

```{r}
mod1 <- lm(revtq ~ revtq_l1, data=train)
```

```{r}
mod2 <- lm(revtq ~ revtq_l1 + revtq_l4, data=train)
```

```{r}
mod3 <- lm(revtq ~ revtq_l1 + revtq_l2 + revtq_l3 + revtq_l4 + revtq_l5 +
           revtq_l6 + revtq_l7 + revtq_l8, data=train)
```

```{r}
summary(mod1)
```

```{r}
summary(mod2)
```

```{r}
summary(mod3)
```

```{r}
rmse <- function(v1, v2) {
  sqrt(mean((v1 - v2)^2, na.rm=T))
}
```

```{r}
mae <- function(v1, v2) {
  mean(abs(v1-v2), na.rm=T)
}
```

```{r, warning=F, message=F}
models <- list(mod1, mod2, mod3)
model_names <- c("1 quarter", "1 and 4 quarters", "8 quarter")

# sapply can be replaced by map here, but it would be a good bit more verbose
df_test <- data.frame(adj_r_sq=sapply(models, function(x)summary(x)[["adj.r.squared"]]),
                      rmse_in=sapply(models, function(x)rmse(train$revtq, predict(x,train))),
                      mae_in=sapply(models, function(x)mae(train$revtq, predict(x,train))),
                      rmse_out=sapply(models, function(x)rmse(test$revtq, predict(x,test))),
                      mae_out=sapply(models, function(x)mae(test$revtq, predict(x,test))))
rownames(df_test) <- model_names
html_df(df_test)  # Custom function using knitr and kableExtra
```

```{r, warning=F, fig.height=4.5}
test %>%
  ggplot(aes(y=revtq,x=predict(mod1,test), color=factor(qtr))) +
  geom_abline(slope=1) + geom_point() +
  ylab("Actual revenue") + 
  xlab("Prediction: 1 quarter model")
```

```{r, warning=F, fig.height=4.5}
test %>%
  ggplot(aes(y=revtq,x=predict(mod3,test), color=factor(qtr))) +
  geom_abline(slope=1) + geom_point() +
  ylab("Actual revenue") + 
  xlab("Prediction: 8 quarter model")
```

```{r, warning=F, message=F}
# models
mod1g <- lm(revtq_gr ~ revtq_gr1, data=train)
mod2g <- lm(revtq_gr ~ revtq_gr1 + revtq_gr4, data=train)
mod3g <- lm(revtq_gr ~ revtq_gr1 + revtq_gr2 + revtq_gr3 + revtq_gr4 + revtq_gr5 + revtq_gr6 + revtq_gr7 + revtq_gr8, data=train)

models <- list(mod1g, mod2g, mod3g)
model_names <- c("1 quarter", "1 and 4 quarters", "8 quarter")

df_test <- data.frame(adj_r_sq=sapply(models, function(x)summary(x)[["adj.r.squared"]]),
                      rmse_in=sapply(models, function(x)rmse(train$revtq, (1+predict(x,train))*train$revtq_l1)),
                      mae_in=sapply(models, function(x)mae(train$revtq, (1+predict(x,train))*train$revtq_l1)),
                      rmse_out=sapply(models, function(x)rmse(test$revtq, (1+predict(x,test))*test$revtq_l1)),
                      mae_out=sapply(models, function(x)mae(test$revtq, (1+predict(x,test))*test$revtq_l1)))
rownames(df_test) <- model_names
html_df(df_test)
```

```{r, warning=F, fig.height=5}
test %>%
  ggplot(aes(y=revtq,x=(1+predict(mod1g,test))*test$revtq_l1, color=factor(qtr))) +
  geom_abline(slope=1) + geom_point() +
  ylab("Actual revenue") + 
  xlab("Prediction: 1 quarter model")
```

```{r, warning=F, fig.height=5}
test %>%
  ggplot(aes(y=revtq,x=(1+predict(mod3g,test))*test$revtq_l1, color=factor(qtr))) +
  geom_abline(slope=1) + geom_point() +
  ylab("Actual revenue") + 
  xlab("Prediction: 8 quarter model")
```

```{r, warning=F, message=F}
# models
mod1y <- lm(revtq_yoy ~ revtq_yoy1, data=train)
mod2y <- lm(revtq_yoy ~ revtq_yoy1 + revtq_yoy4, data=train)
mod3y <- lm(revtq_yoy ~ revtq_yoy1 + revtq_yoy2 + revtq_yoy3 + revtq_yoy4 + revtq_yoy5 + revtq_yoy6 + revtq_yoy7 + revtq_yoy8, data=train)

models <- list(mod1y, mod2y, mod3y)
model_names <- c("1 quarter", "1 and 4 quarters", "8 quarter")

df_test <- data.frame(adj_r_sq=sapply(models, function(x)summary(x)[["adj.r.squared"]]),
                      rmse_in=sapply(models, function(x)rmse(train$revtq, (1+predict(x,train))*train$revtq_l4)),
                      mae_in=sapply(models, function(x)mae(train$revtq, (1+predict(x,train))*train$revtq_l4)),
                      rmse_out=sapply(models, function(x)rmse(test$revtq, (1+predict(x,test))*test$revtq_l4)),
                      mae_out=sapply(models, function(x)mae(test$revtq, (1+predict(x,test))*test$revtq_l4)))
rownames(df_test) <- model_names
html_df(df_test)
```

```{r, warning=F, fig.height=5}
test %>%
  ggplot(aes(y=revtq,x=(1+predict(mod1y,test))*test$revtq_l4, color=factor(qtr))) +
  geom_abline(slope=1) + geom_point() +
  ylab("Actual revenue") + 
  xlab("Prediction: 1 quarter model")
```

```{r, warning=F, fig.height=5}
test %>%
  ggplot(aes(y=revtq,x=(1+predict(mod3y,test))*test$revtq_l4, color=factor(qtr))) +
  geom_abline(slope=1) + geom_point() +
  ylab("Actual revenue") + 
  xlab("Prediction: 8 quarter model")
```

```{r, warning=F, message=F}
# models
mod1d <- lm(revtq_d ~ revtq_d1, data=train)
mod2d <- lm(revtq_d ~ revtq_d1 + revtq_d4, data=train)
mod3d <- lm(revtq_d ~ revtq_d1 + revtq_d2 + revtq_d3 + revtq_d4 + revtq_d5 + revtq_d6 + revtq_d7 + revtq_d8, data=train)

models <- list(mod1d, mod2d, mod3d)
model_names <- c("1 quarter", "1 and 4 quarters", "8 quarter")

df_test <- data.frame(adj_r_sq=sapply(models, function(x)summary(x)[["adj.r.squared"]]),
                      rmse_in=sapply(models, function(x)rmse(train$revtq, predict(x,train)+train$revtq_l1)),
                      mae_in=sapply(models, function(x)mae(train$revtq, predict(x,train)+train$revtq_l1)),
                      rmse_out=sapply(models, function(x)rmse(test$revtq, predict(x,test)+test$revtq_l1)),
                      mae_out=sapply(models, function(x)mae(test$revtq, predict(x,test)+test$revtq_l1)))
rownames(df_test) <- model_names
html_df(df_test)
```

```{r, warning=F, fig.height=5}
test %>%
  ggplot(aes(y=revtq,x=predict(mod1d,test)+test$revtq_l1, color=factor(qtr))) +
  geom_abline(slope=1) + geom_point() +
  ylab("Actual revenue") + 
  xlab("Prediction: 1 quarter model")
```

```{r, warning=F, fig.height=5}
test %>%
  ggplot(aes(y=revtq,x=predict(mod3d,test)+test$revtq_l1, color=factor(qtr))) +
  geom_abline(slope=1) + geom_point() +
  ylab("Actual revenue") + 
  xlab("Prediction: 8 quarter model")
```

