8  Quadratic Terms

\[ \definecolor{bayesred}{RGB}{147, 30, 24} \definecolor{bayesblue}{RGB}{32, 35, 91} \definecolor{bayesorange}{RGB}{218, 120, 1} \definecolor{grey}{RGB}{128, 128, 128} \definecolor{couleur1}{RGB}{0,163,137} \definecolor{couleur2}{RGB}{255,124,0} \definecolor{couleur3}{RGB}{0, 110, 158} \definecolor{coul1}{RGB}{255,37,0} \definecolor{coul2}{RGB}{242,173,0} \definecolor{col_neg}{RGB}{155, 191, 221} \definecolor{col_pos}{RGB}{255, 128, 106} \definecolor{wongBlack}{RGB}{0,0,0} \definecolor{wongLightBlue}{RGB}{86, 180, 233} \definecolor{wongGold}{RGB}{230, 159, 0} \definecolor{wongGreen}{RGB}{0, 158, 115} \definecolor{wongYellow}{RGB}{240, 228, 66} \definecolor{wongBlue}{RGB}{0, 114, 178} \definecolor{wongOrange}{RGB}{213, 94, 0} \definecolor{wongPurple}{RGB}{204, 121, 167} \definecolor{IBMPurple}{RGB}{120, 94, 240} \definecolor{IBMMagenta}{RGB}{220, 38, 127} \]

This chapter, as Chapter 7, uses Jordà (2005) Local Projection framework to measure how sensitive agricultural output is to exogenous changes in the weather. The differences lies in the fact that the weather variables are included with first order and second order term in the equations.

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.4     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.0
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(fastDummies)

The data can be loaded (see Chapter 5)

load("../data/output/df_lp.rda")
df
# A tibble: 8,460 × 69
   product_eng region_id month date       y_new     y region   product ln_prices
   <chr>       <fct>     <dbl> <date>     <dbl> <dbl> <chr>    <chr>       <dbl>
 1 Cassava     1             1 2001-01-01 5322   1.32 AMAZONAS YUCA        0.255
 2 Cassava     1             2 2001-02-01 4388   1.14 AMAZONAS YUCA        0.262
 3 Cassava     1             3 2001-03-01 5664.  1.35 AMAZONAS YUCA       NA    
 4 Cassava     1             4 2001-04-01 5664.  1.18 AMAZONAS YUCA        0.293
 5 Cassava     1             5 2001-05-01 5099   1.20 AMAZONAS YUCA        0.307
 6 Cassava     1             6 2001-06-01 5537   1.21 AMAZONAS YUCA       NA    
 7 Cassava     1             7 2001-07-01 5537   1.11 AMAZONAS YUCA        0.336
 8 Cassava     1             8 2001-08-01 5993   1.21 AMAZONAS YUCA        0.336
 9 Cassava     1             9 2001-09-01 5622.  1.18 AMAZONAS YUCA       NA    
10 Cassava     1            10 2001-10-01 5622.  1.26 AMAZONAS YUCA        0.344
# ℹ 8,450 more rows
# ℹ 60 more variables: ln_produc <dbl>, year <dbl>, Value_prod <dbl>,
#   surf_m <dbl>, Value_surfR <dbl>, Value_prices <dbl>, campaign <dbl>,
#   campaign_plain <chr>, month_campaign <dbl>, surf_lag_calend <dbl>,
#   perc_product <dbl>, perc_product_mean <dbl>, diff_plant_harv <dbl>,
#   exposition <dbl>, exposition_trend <dbl>, exposition_detrended <dbl>,
#   exposition_norm <dbl>, temp_min <dbl>, temp_max <dbl>, temp_mean <dbl>, …

Some packages are needed, make sure that they are installed.

# install.packages("fastDummies")
# install.packages("imputeTS")
# install.packages("ggh4x")
# install.packages("mFilter")
# install.packages("pbapply")
# install.packages("latex2exp")
# install.packages("sandwich")

We load some useful functions:

# Functions useful to shape the data for local projections
source("../weatherperu/R/format_data.R")

# Load function in utils
source("../weatherperu/R/utils.R")

# Load detrending functions
source("../weatherperu/R/detrending.R")

# Estimation functions
source("../weatherperu/R/estimations.R")

8.1 Linear Local Projections

In this section, we focus on estimating the Local Projections (Jordà 2005) to quantify the impact of weather on agricultural production. We utilize panel data, similar to the approach used in the study by Acevedo et al. (2020), and independently estimate models for each specific crop.

For a particular crop denoted as \(c\), the model can be expressed as follows: \[ \begin{aligned} \underbrace{y_{c,i,{\color{wongGold}t+h}}}_{\text{Production}} = & \underbrace{\alpha_{c,i,h}}_{\text{reg. fixed effect}} + {\color{wongOrange}\beta_{c,{\color{wongGold}h}}^{{\color{wongPurple}T}}} {\color{wongPurple}{T_{i,{\color{wongGold}t}}}} + {\color{wongOrange}\beta_{c,{\color{wongGold}h}}^{{\color{wongPurple}T^2}}} {\color{wongPurple}{T^2_{i,{\color{wongGold}t}}}} + {\color{wongOrange}\beta_{c,{\color{wongGold}h}}^{{\color{wongPurple}P}}} {\color{wongPurple}P_{i,{\color{wongGold}t}}} + {\color{wongOrange}\beta_{c,{\color{wongGold}h}}^{{\color{wongPurple}P^2}}} {\color{wongPurple}P^2_{i,{\color{wongGold}t}}}\\ &+\delta_{c,i,h}\underbrace{X_{t}}_{\text{controls}}+\varepsilon_{c,i,t+h} \end{aligned} \tag{8.1}\]

Here, \(i\) represents the region, \(t\) represents the time, and \(h\) represents the horizon. The primary focus lies on estimating the coefficients associated with temperature and precipitation for different time horizons \(\color{wongGold}h=\{0,1,...,T_{c}\}\)

The squared variables are added to the dataset.

df <- 
  df |> 
  mutate(
    temp_max_dev_sq = temp_max_dev^2,
    precip_sum_dev_sq = precip_sum_dev^2
  )

8.1.1 Estimation

To loop over the different crops, we can utilize the map() function. This function enables us to apply the estimate_linear_lp() function to each crop iteratively, facilitating the estimation process.

crops <- df$product_eng |> unique()
weather_variables <- c(
  "temp_max_dev", "precip_sum_dev",
  "temp_max_dev_sq", "precip_sum_dev_sq"
)
control_variables <- c("rer_hp", "r_hp", "pi", "ind_prod", "ONI", "price_int_inf")

resul_lp_quad <- map(
  crops, ~ estimate_linear_lp(
    df = df,
    horizons = 8,
    y_name = "y",
    group_name = "region_id",
    add_month_fe = FALSE,
    add_intercept = FALSE,
    crop_name = .,
    control_names = control_variables,
    weather_names = weather_variables,
    std = "Cluster",
    other_var_to_keep = "y_new"
  )
)

8.1.2 Results

We can visualize the Impulse Response Functions (IRFs) by plotting the estimated coefficients associated with the weather variables. These coefficients represent the impact of weather on agricultural production and can provide valuable insights into the dynamics of the system. By plotting the IRFs, we can gain a better understanding of the relationship between weather variables and the response of agricultural production over time.

The data for the graphs:

df_irfs_lp_quad <- 
  map(resul_lp_quad, "coefs") |> 
  list_rbind() |> 
  filter(name %in% weather_variables) |> 
  mutate(
    order = ifelse(str_detect(name, "_sq$"), 2, 1),
    name = str_remove(name, "_sq$")
  ) |> 
  pivot_wider(
    names_from = order, 
    values_from = c(value, std, std_shock, median_shock, q05_shock, q95_shock), 
    names_prefix = 'order_') |> 
  rename(d = std_shock_order_1) |> 
  mutate(
    ir = value_order_1 * d + value_order_2 * d^2,
    # IC 95%
    ir_lower_95 = (value_order_1 - qnorm(0.975) * std_order_1) * d + 
      (value_order_2 - qnorm(0.975) * std_order_2) * d^2,
    ir_upper_95 = (value_order_1 + qnorm(0.975) * std_order_1) * d +
      (value_order_2 + qnorm(0.975) * std_order_2) * d^2,
    # IC 68%
    ir_lower_68 = (value_order_1 - qnorm(0.84) * std_order_1) * d + 
      (value_order_2 - qnorm(0.84) * std_order_2) * d^2,
    ir_upper_68 = (value_order_1 + qnorm(0.84) * std_order_1) * d +
      (value_order_2 + qnorm(0.84) * std_order_2) * d^2
  ) |> 
  mutate(
    crop = factor(
      crop, 
      levels = c("Rice", "Dent corn", "Potato", "Cassava"),
      labels = c("Rice", "Maize", "Potato", "Cassava"))
  ) |> 
  mutate(
    name = factor(
      name,
      levels = c(
        "temp_max_dev",
        "precip_sum_dev"
      ),
      labels = c(
        "Temp. anomalies", 
        "Precip. anomalies"
      )
    )
  )

For the confidence intervals:

df_irfs_lp_quad_ci <- 
  df_irfs_lp_quad |> 
  select(horizon, crop, name, matches("^(ir_lower)|^(ir_upper)", perl = TRUE)) |> 
  pivot_longer(
    cols = matches("^(ir_lower)|^(ir_upper)", perl = TRUE),
    names_pattern = "(.*)_(95|68)$",
    names_to = c(".value", "level")
  ) |> 
  mutate(level = str_c(level, "%"))
ggplot() +
  geom_ribbon(
    data = df_irfs_lp_quad_ci,
    mapping = aes(
      x = horizon,
      ymin = ir_lower, ymax = ir_upper, fill = level),
    alpha = .2
  ) +
  geom_line(
    data = df_irfs_lp_quad,
    mapping = aes(x = horizon, y = ir),
    colour = "#0072B2") +
  geom_hline(yintercept = 0, colour = "#D55E00") +
  ggh4x::facet_grid2(
    name~crop, scales = "free_y", 
    independent = "y", switch = "y") +
  scale_y_continuous(labels = scales::percent) +
  labs(x = "Horizon", y = NULL) +
  scale_fill_manual(
    "C.I. level", 
    values = c("68%" = "gray10", "95%" = "gray60")
  ) +
  theme_paper() +
  theme(strip.placement = "outside")

Figure 8.1: Agricultural production response to a weather shock