## ----setup, include = FALSE-------------------------------------------------------------
knitr::opts_chunk$set(echo = TRUE, 
                      eval = TRUE,
                      comment = "#>")
Sys.setenv(lang = "en")

library(fixest)
setFixest_nthreads(1)

## ---------------------------------------------------------------------------------------
library(fixest)
data(trade)
# OLS estimation
gravity = feols(log(Euros) ~ log(dist_km) | Destination + Origin + Product + Year, trade)
# Two-way clustered SEs
summary(gravity, vcov = "twoway")
# Two-way clustered SEs, without small sample correction
summary(gravity, vcov = "twoway", ssc = ssc(K.adj = FALSE, G.adj = FALSE))

## ----eval = TRUE, include = FALSE-------------------------------------------------------
is_plm = requireNamespace("plm", quietly = TRUE)

if(!is_plm){
    knitr::opts_chunk$set(eval = FALSE)
    cat("Evaluation of the next chunks requires 'plm' which is not installed.")
} else {
    knitr::opts_chunk$set(eval = TRUE)
    
    library(plm)
    library(sandwich)
}


## ----eval = !is_plm, include = !is_plm--------------------------------------------------
# NOTE:
# Evaluation of the next chunks requires the package 'plm' which is not installed.
# The code output is not reported.

## ---------------------------------------------------------------------------------------
#  library(sandwich)
#  library(plm)
#  
#  data(Grunfeld)
#  
#  # Estimations
#  res_lm    = lm(inv ~ capital, Grunfeld)
#  res_feols = feols(inv ~ capital, Grunfeld)
#  
#  # Same standard-errors
#  rbind(se(res_lm), se(res_feols))
#  
#  # Heteroskedasticity-robust covariance
#  se_lm_hc    = sqrt(diag(vcovHC(res_lm, type = "HC1")))
#  se_feols_hc = se(res_feols, vcov = "hetero")
#  rbind(se_lm_hc, se_feols_hc)

## ---------------------------------------------------------------------------------------
#  
#  # Estimations
#  est_lm    = lm(inv ~ capital + as.factor(firm) + as.factor(year), Grunfeld)
#  est_plm   = plm(inv ~ capital + as.factor(year), Grunfeld,
#                  index = c("firm", "year"), model = "within")
#  # we use panel.id so that panel VCOVs can be applied directly
#  est_feols = feols(inv ~ capital | firm + year, Grunfeld, panel.id = ~firm + year)
#  
#  #
#  # "iid" standard-errors
#  #
#  
#  #  so we need to ask for iid SEs explicitly.
#  rbind(se(est_lm)["capital"], se(est_plm)["capital"], se(est_feols))
#  
#  # p-values:
#  rbind(pvalue(est_lm)["capital"], pvalue(est_plm)["capital"], pvalue(est_feols, vcov = "iid"))
#  

## ---------------------------------------------------------------------------------------
#  # Clustered by firm
#  se_lm_firm    = se(vcovCL(est_lm, cluster = ~firm, type = "HC1"))["capital"]
#  se_plm_firm   = se(vcovHC(est_plm, cluster = "group"))["capital"]
#  se_stata_firm = 0.06328129    # vce(cluster firm)
#  se_feols_firm = se(est_feols, vcov = "cluster")
#  
#  rbind(se_lm_firm, se_plm_firm, se_stata_firm, se_feols_firm)

## ---------------------------------------------------------------------------------------
#  # How to get the lm version
#  se_feols_firm_lm = se(est_feols, ssc = ssc(K.fixef = "full"))
#  rbind(se_lm_firm, se_feols_firm_lm)
#  
#  # How to get the plm version
#  se_feols_firm_plm = se(est_feols, ssc = ssc(K.fixef = "none", G.adj = FALSE))
#  rbind(se_plm_firm, se_feols_firm_plm)

## ---------------------------------------------------------------------------------------
#  #
#  # Newey-west
#  #
#  
#  se_plm_NW   = se(vcovNW(est_plm))["capital"]
#  se_feols_NW = se(est_feols, vcov = "NW")
#  
#  rbind(se_plm_NW, se_feols_NW)
#  
#  # we can replicate plm's by changing the type of SSC:
#  rbind(se_plm_NW,
#        se(est_feols, vcov = NW ~ ssc(K.adj = FALSE, G.adj = FALSE)))
#  
#  #
#  # Driscoll-Kraay
#  #
#  
#  se_plm_DK   = se(vcovSCC(est_plm))["capital"]
#  se_feols_DK = se(est_feols, vcov = "DK")
#  
#  rbind(se_plm_DK, se_feols_DK)
#  
#  # Replicating plm's
#  rbind(se_plm_DK,
#        se(est_feols, vcov = DK ~ ssc(K.adj = FALSE, G.adj = FALSE)))
#  

## ----eval = TRUE, include = FALSE-------------------------------------------------------
is_lfe = requireNamespace("lfe", quietly = TRUE)
is_lfe_plm = is_lfe && is_plm
if(is_lfe){
    # avoids ugly startup messages popping + does not require the use of the not very elegant suppressPackageStartupMessages
    library(lfe)
}

## ----eval = !is_lfe_plm, include = !is_lfe_plm, echo = FALSE----------------------------
if(!is_lfe){
  cat("The evaluation of the next chunks of code requires the package 'lfe' which is not installed")
} else {
  cat("The evaluation of the next chunks of code requires the package 'plm' (for the data set) which is not installed.",
    "\nThe code output is not reported.")
}

## ----eval = is_lfe_plm, warning = FALSE-------------------------------------------------
#  library(lfe)
#  
#  # lfe: clustered by firm
#  est_lfe = felm(inv ~ capital | firm + year | 0 | firm, Grunfeld)
#  se_lfe_firm = se(est_lfe)
#  
#  # The two are different, and it cannot be directly replicated by feols
#  rbind(se_lfe_firm, se_feols_firm)
#  
#  # You have to provide a custom VCOV to replicate lfe's VCOV
#  my_vcov = vcov(est_feols, ssc = ssc(K.adj = FALSE))
#  se(est_feols, vcov = my_vcov * 199/198) # Note that there are 200 observations
#  
#  # Differently from feols, the SEs in lfe are different if year is not a FE:
#  # => now SEs are identical.
#  rbind(se(felm(inv ~ capital + factor(year) | firm | 0 | firm, Grunfeld))["capital"],
#        se(feols(inv ~ capital + factor(year) | firm, Grunfeld))["capital"])
#  
#  # Now with two-way clustered standard-errors
#  est_lfe_2way  = felm(inv ~ capital | firm + year | 0 | firm + year, Grunfeld)
#  se_lfe_2way   = se(est_lfe_2way)
#  se_feols_2way = se(est_feols, vcov = "twoway")
#  rbind(se_lfe_2way, se_feols_2way)
#  
#  # To obtain the same SEs, use G.df = "conventional"
#  sum_feols_2way_conv = summary(est_feols, vcov = twoway ~ ssc(G.df = "conv"))
#  rbind(se_lfe_2way, se(sum_feols_2way_conv))
#  
#  # We also obtain the same p-values
#  rbind(pvalue(est_lfe_2way), pvalue(sum_feols_2way_conv))

## ---------------------------------------------------------------------------------------
#  setFixest_ssc(ssc(K.adj = FALSE))

## ---------------------------------------------------------------------------------------
#  setFixest_vcov(no_FE = "iid", one_FE = "cluster",
#                 two_FE = "hetero", panel = "driscoll_kraay")

