Non-financial Liabilities and Restructuring

Empirical support from 2005 Reform with the North America sample

Author

Hongyi Xu

Published

March 10, 2025

Modified

March 27, 2025

This analysis is suggested by discussant Samuel Antill in 2025 AFA meeting.

In this version, we use debt_ebitda as the measure for leverage.

The previous versions with book_leverage as the dependant variable can be found here.

S1. Download and Load the Raw Dataset

We download the firm-level capital structure from Compustat-CapitalIQ North America. The first measure of executory contracts is from the accounting data which (under U.S. GAAP) cover leases and rental contracts. We use the variables “Debt Equivalent of Operating Leases”, “Capital Leases” and “Net Rental Expenses”.

  • Debt - Capitalized Lease Obligations (dclo): This item represents long-term obligations due in respect of lease finances and hire purchase arrangements. This item includes:

    • Long-term finance lease obligations
    • Long-term lease financing
    • Long-term hire purchase obligations
    • Non-current obligations under capital leases
  • Rental Expense (xrent): This item represents all costs charged to operations for rental, lease, or hire of space and/or equipment. This item includes:

    • Airlines’ landing fees
    • Contingent rentals associated with capitalized leases
    • Lease charges and plant hire

    In the main test, we construct a new variable called total rent, which is defined as the total rental commitment mrc1 + mrc2 + mrc3 + mrc4 + mrc5 + mrct reported in year t.

  • Asset - Total (at): Book value of total assets.

  • Debt in Current Liabilities - Total (dlc) is for the short-term debt and Long-term debt - Total (dltt) is for the long-term debt.

  • Earnings Before Interest (EBITDA): EBITDA.

  • Industry classifications: naics, sic and spcindcd + (Fama-French 30 Industry Classifiers, To Be Added / Definition).

In this version we add a set of new variables:

  • Property, Plant, and Equipment - Leases at Cost (fatl) is the capitalized value of leases and leasehold improvements included in property, plant, and equipment, excluding equipment leased to others, and is not applicable to banks or utilities. > Definition

  • Property, Plant, and Equipment - Buildings at Cost (fatb). > Definition

  • Property, Plant, and Equipment - Land and Improvements at Cost (fatp).

  • Property, Plant, and Equipment - Buildings (Net) (ppenb).

  • Property, Plant, and Equipment - Land and Improvements (Net) (ppenli).

  • Property, Plant and Equipment - Total (Gross) (ppegt).

  • Property, Plant and Equipment - Total (Net) (ppent)

  • Loans/Claims/Advances - Lease (lcal). > Defintion >

Given that the policy shock happens under the US jurisdiction, we expect more significant treatment effect to be detected in this sample. The period used in Samuel’s slides is between 2002 and 2007, which is after the doc.com bubble and before the GFC. The variables in the dataset are:

Show the code
## create the data file path 
data_file <- "jpbdsuonrpztpw8t.csv" 
data_path <- file.path(work_dir, "Data", data_file)

## load the compustat_na data
compustat_na <- as_tibble(read.csv(file = data_path) ) # %>%
  # filter(fic == "USA" | loc == "USA" ) ## keep only US related observations (| fic == "CAN" | loc == "CAN")

## data file record: 
# | Mar 10, 2025 > jpbdsuonrpztpw8t.csv
# | Mar  9, 2025 > nfmss2xkmjgfjonh.csv 
# | Mar  5, 2025 > e3cdfjocaz4aboqh.csv 
# | Mar  3, 2025(2) > tbrl8c4xqurukptl.csv > more variables 
# | Mar  3, 2025(1) > evvvij0nqoe8sshv.csv
# | Feb 24, 2025 > azsyeo1yjmrb2q1v.csv 
# | Jan 14, 2025 > g4f68dkn3beu1iag.csv 

## load the FF_30ind data 
FF_30ind <- as_tibble(read.csv(file = file.path(work_dir, "Data", "ff_30ind.csv")))

## check the variable names 
cat("Variables include:\n\n")
sort(names(compustat_na)) 
cat("\nSample size: \n\n")
dim(compustat_na)
Variables include:

 [1] "act"      "at"       "bkvlps"   "ceq"      "che"      "cik"     
 [7] "conm"     "consol"   "costat"   "csho"     "curcd"    "cusip"   
[13] "datadate" "datafmt"  "dclo"     "dlc"      "dltt"     "dp"      
[19] "dvc"      "dvp"      "ebit"     "ebitda"   "fatb"     "fatl"    
[25] "fatp"     "fic"      "fyear"    "fyr"      "fyrc"     "gvkey"   
[31] "ib"       "indfmt"   "lcal"     "lct"      "loc"      "lt"      
[37] "mrc1"     "mrc2"     "mrc3"     "mrc4"     "mrc5"     "mrct"    
[43] "mrcta"    "naics"    "ni"       "oibdp"    "popsrc"   "ppegt"   
[49] "ppenb"    "ppenli"   "ppenls"   "ppent"    "prcc_f"   "re"      
[55] "revt"     "seq"      "sic"      "spcindcd" "tic"      "txdb"    
[61] "wcap"     "xrent"   

Sample size: 

[1] 165122     62

S2. Data Cleaning and Prep

Two dependent variables are constructed to measure firm’s leverage: (cf. p18 and Table 2 of the paper)

  • Book leverage: we define leverage as the ratio of the sum of short-term debt and long-term debt to assets (we drop observations where this is outside the [0,1] range)*.

  • Debt/EBITDA: we define debt-to-EBITDA as the ratio of the long- and short-term debt to EBITDA (we drop observations where this is outside the [0,15] range)*.

These restrictions are now imposed in all analyses. We use the full set of firms in the Compustat NA. We choose fyear - fiscal year - as the time variable of the dataset.

In this version, we set the base_year == 2004 instead of 2005, which is the year when the treatment happens. Based on the S.256 - Bankruptcy Abuse Prevention and Consumer Protection Act of 2005, the bill was first introduced on February 1, 2025 and was signed into law by President George W. Bush. on April 20, 2005. The act’s provisions applied to bankruptcy cases filed on or after October 17, 2005. > Wikipedia

Therefore, the treatment effects should first appear in the annual reports for the fiscal year 2005, as the treatment occurs in fiscal year 2004.

Then we create a list of variables required for the analysis:

Show the code
## set the base year 
base_year <- 2004 
period_start <- 2002
period_end <- 2007
intensity_measure_year <- 2001 # choose the base year for the intensity measure 
n_pre <- 1 # number of periods before the period_start in the iplot()  

## create leverage and control variables 
data <- compustat_na %>% 
  # filter(at >= 0) %>%
  filter(indfmt == "INDL") %>% ## remove all financial firms
  ## create the lagged `ppent` item: 
  group_by(gvkey) %>%
  arrange(fyear) %>%
  mutate(
    ppent_lag1 = lag(ppent, n = 1), 
    at_thousand_lag1 = lag(at, n = 1) * 10^-3,
    ) %>% 
  ungroup() %>% 
  ## create new variables: 
  mutate(
    ## leverage variables: 
    book_leverage = (dlc + dltt) / at, 
    debt_ebitda = (dlc + dltt) / ebitda, 
    
    ## treatment intensity: 
    totalrent = coalesce(mrc1, 0) + coalesce(mrc2, 0) + coalesce(mrc3, 0) + coalesce(mrc4, 0) + coalesce(mrc5, 0) + coalesce(mrcta, 0), # total rent w/o discount
    # contract_intensity = (dclo + xrent * 3) / at, # executory contract intensity
    contract_intensity = (coalesce(dclo, 0) + totalrent) / at, # executory contract intensity
    
    ### for the total: 
    ppe_lease_intensity = fatl / at, # PPE lease intensity 
    building_intensity = fatb / at, # only for buildings (i.e. properties), but only not only leased ones
    land_intensity = fatp / at, # only land intensity 
    bnl_intensity = building_intensity + land_intensity, 
    
    ### for the net: 
    # net_lease_intensity = ppenls / at, # net PPE lease intensity [not available after 1998]
    # net_building_intensity = ppenb / at, # net PPE building intensity [not available after 1998]  
    net_land_intensity = ppenli / at, # net PPE land intensity 
    
    ### for total PPE: 
    net_PPE_intensity = ppent / at, # net PPE intensity 
    PPE_intensity = ppegt / at, # gross PPE intensity 
    
    ### for lessors: 
    lessor_lease_intensity = lcal / at, # this is outstanding lease intensity to be received. 
    
    ## other variables and controls: 
    dyear = as.integer(substr(datadate, start = 1, stop = 4)), # data year 
    roa = ni / at, # return on asset (ROA) 
    tangibility = ppent / at, # tangibility  
    altman_Z = 
      # (3.3 * revt + 1.4 * re + 1.2 * wcap) / at, # Altman Z-score
      (3.3 * ebit + 1.4 * re + 1.2 * wcap + 0.6 * prcc_f * csho + 0.999 * revt), # Altman Z-score
    kz = -1.001909 * ((ib + dp)/ppent_lag1) + 0.2826389 * ((at + prcc_f*csho - ceq - txdb)/at) + 3.139193 * ((dltt + dlc)/(dltt + dlc + seq)) - 39.3678 * ((dvc + dvp)/ppent_lag1) - 1.314759 * (che/ppent_lag1), # KZ index 
    # hw = , # financial contraints (HW) 
    current_ratio = act / lct, # current ratio: current asset / current liabilities 
    market_book = (prcc_f*csho) / (ceq + txdb) # market-to-book
  ) 

## record the variable names 
cat("Variables Created:\n\n")
sort(setdiff(names(data), names(compustat_na))) 
Variables Created:

 [1] "altman_Z"               "at_thousand_lag1"       "bnl_intensity"         
 [4] "book_leverage"          "building_intensity"     "contract_intensity"    
 [7] "current_ratio"          "debt_ebitda"            "dyear"                 
[10] "kz"                     "land_intensity"         "lessor_lease_intensity"
[13] "market_book"            "net_land_intensity"     "net_PPE_intensity"     
[16] "PPE_intensity"          "ppe_lease_intensity"    "ppent_lag1"            
[19] "roa"                    "tangibility"            "totalrent"             

We propose several noisy measures of the PPE lease contract intensity:

  • ppe_lease_intensity: calculated as the Property, Plant, and Equipment - Leases at Cost (fatl) normalized by the total asset for firm i at year t. It measures the future lease obligations in PPE, but it is a noisy measure as it also includes equipment.

  • building_intensity: calculated as Property, Plant, and Equipment - Buildings at Cost (fatb) normalized by the total asset for firm i at year t.

  • land_intensity: calculated as Property, Plant, and Equipment - Land and Improvements at Cost (fatp) normalized by the total asset for firm i at year t.

  • bnl_intensity: calculated as the sum of Property, Plant, and Equipment - Land and Improvements at Cost (fatp) and Property, Plant, and Equipment - Buildings at Cost (fatb) normalized by the total asset (at) for firm i at year t.

  • oustanding_lease_intensity: calculated as the Loans/Claims/Advances - Lease (lcal) normalized by the total asset for firm i at year t. It measures the amount of lease obgliations to be collected by firm i in the future. You can view this sample as the lessor in the lease contract, while the previous variable, ppe_lease_intensity, captures the sample of lessees.

Although this will contain other items besides non-residential real property lease obligations, we believe that it is a potentially better measure for a firm’s exposure to this policy shock in 2005.

For definitions of controls, please refer to Section 4.

  • kz: KZ index:

-1.001909 \left( \frac{ib + dp}{\text{lagged } ppent} \right) + 0.2826389 \left( \frac{at + \text{prcc_f} \times \text{csho} - ceq - txdb}{at} \right) + 3.139193 \left( \frac{dltt + dlc}{dltt + dlc + seq} \right) - 39.3678 \left( \frac{dvc + dvp}{\text{lagged } ppent} \right) - 1.314759 \left( \frac{che}{\text{lagged } ppent} \right).

s2.1. Summary Statistics

Show the code
## summary statistics: 
data %>% 
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>% 
  filter(at > 0 & ebitda > 0 & ppent_lag1 >= 0 & lct > 0 & (ceq + txdb) > 0) %>% 
  select(
    book_leverage, debt_ebitda, 
    
    altman_Z, current_ratio, debt_ebitda, current_ratio, 
    debt_ebitda, kz, market_book, roa, tangibility, 
    
    contract_intensity, ppe_lease_intensity, bnl_intensity, 
    building_intensity, land_intensity, # lessor_lease_intensity 
    # net_land_intensity, net_PPE_intensity, PPE_intensity, ppent_lag1, 
  ) %>% 
  psych::describe(na.rm = TRUE) %>% 
  select(n, mean, `trimmed mean` = trimmed, median, sd, min, max) %>% 
  round(digits = 2) %>% 
  rownames_to_column(var = "Variable Name") %>% 
  gt() %>% 
  tab_header(
    title = "Table 1. Summary Statistics"
  ) %>% 
  tab_options(
    heading.align = "left"
  ) %>%
  cols_align(
    align = "center",
    columns = c("n", "mean", "trimmed mean", "median", "sd", "min", "max")
  ) 
Table 1. Summary Statistics
Variable Name n mean trimmed mean median sd min max
book_leverage 54519 0.23 0.21 0.21 0.19 0.00 0.96
debt_ebitda 54519 2.28 1.85 1.59 2.51 0.00 14.99
altman_Z 48752 7668.83 1987.90 784.23 32197.73 -93300.83 1267591.18
current_ratio 54092 2.62 1.96 1.74 12.90 0.00 2348.00
kz 49420 -Inf -2.48 -0.84 NaN -Inf 2889.16
market_book 49904 6.77 2.08 1.77 406.19 0.00 87698.50
roa 54518 0.06 0.05 0.04 0.40 -25.25 49.76
tangibility 54515 0.33 0.30 0.25 0.26 0.00 0.99
contract_intensity 54519 0.12 0.06 0.04 0.31 0.00 14.48
ppe_lease_intensity 33950 0.04 0.02 0.01 0.10 0.00 1.68
bnl_intensity 37226 0.11 0.08 0.06 0.17 0.00 2.36
building_intensity 37262 0.09 0.06 0.05 0.14 0.00 1.96
land_intensity 37369 0.02 0.01 0.01 0.06 0.00 2.34

s2.2. plot the distribution of different intensity measures

Show the code
candidate_intensity_measure <- c(
  "contract_intensity", 
  "ppe_lease_intensity", 
  "building_intensity", 
  "land_intensity",
  "bnl_intensity") 

for (measure in candidate_intensity_measure) {
  cat('\n')
  cat('#### ', measure, '   \n')
  cat('\n')
  
  data %>% 
    filter(fic == "USA" | loc == "USA" ) %>% 
    filter(fyear >= period_start & fyear <= period_end) %>% 
    filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>% 
    filter(at > 0 & ebitda > 0 & ppent_lag1 > 0 & lct > 0 & (ceq + txdb) > 0) %>% 
    select(
      gvkey, fyear, 
      book_leverage, debt_ebitda, 
      
      altman_Z, current_ratio, debt_ebitda, current_ratio, 
      debt_ebitda, kz, market_book, roa, tangibility, 
      
      contract_intensity, ppe_lease_intensity, bnl_intensity, 
      building_intensity, land_intensity, # lessor_lease_intensity 
      # net_land_intensity, net_PPE_intensity, PPE_intensity, ppent_lag1, 
    ) %>% 
    na.omit() %>% 
    filter(contract_intensity >= 0) %>% 
    .[[measure]] %>% # selec the variable of interest 
    hist(., 
       prob = TRUE, # density plot
       col = "#E1DEFC",  
       main = "Density Histogram: data from Compustat NA", 
       xlab = paste(measure),
       ylab = "Density", 
       breaks = 100, # xlim = c(0, 8) 
     ) 
  
  # jpeg(filename = paste("Figure1_", id.names[c], ".jpeg", sep = ""), width = 550, height = 350)
  cat('\n')
} 

contract_intensity

ppe_lease_intensity

building_intensity

land_intensity

bnl_intensity

S3. Difference-in-Difference Examination

Then, we construct the dataset for the difference-in-difference analysis.

In this section, we use all observations without missing values in subsequent analyses.

The original dataset (data) contains observations with fiscal year (fyear) range in [1996, 2009] and we restrict the sample to the fiscal year in [2002, 2007].

s3.0. Executory contract intensity

contract_intensity is chosen to measure a firm’s executory contract intensity, which was expected to be impacted by the change in the bankruptcy code in 2005.

Show the code
## choose the group definition: 
intensity_measure_name <- candidate_intensity_measure[1]

data_firm <- data %>% 
  filter(fyear == intensity_measure_year) %>% # use `fyear` may create multiple observations for the same firm. E.g. filter(gvkey == 23535, dyear == 2005) 
  group_by(fyear) %>% 
  ## identify large and small firms based on its total asset in the year 2000 
  mutate(median_at = median(at, na.rm = TRUE)) %>% 
  ungroup() %>% 
  mutate(large = ifelse(at > median_at, 1, 0)) %>% 
  select(gvkey, intensity_2000 = all_of(intensity_measure_name), large) 
  
data_did <- data %>% 
  ## merge the grouping variable 
  left_join(y = data_firm, by = join_by(gvkey) ) %>% 
  ## merge the FF 30 industry classification 
  left_join(y = FF_30ind, by = join_by(sic)) %>% 
  ## exclude certain industries 
  filter(
    ff_30ind != 20, # exclude Utiltiy (number 20) 
    !(sic >= 6000 & sic <= 6199) # exclude banks under Banking, Insurance, Real Estate, Trading (number 29)
  ) %>% 
  ## pre- & post- 
  mutate(
    indexyear = (fyear - base_year), # year index with 2005 as base 0.
    post_2005 = as.numeric(fyear > base_year)  # whether it is after the 2005 reform 
  ) 

## gvkey(s) for balanced panel": 
data_did_balanced_id <- data_did %>% 
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>% 
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>% 
  group_by(gvkey) %>% 
  summarise(count_obs = sum(!is.na(book_leverage) & !is.na(intensity_2000))) %>% 
  ungroup() %>% 
  filter(count_obs == period_end - period_start + 1 + n_pre) %>% 
  .$gvkey 

DiD Analysis:

Variable treated is defined as whether the firm has a positive contract_intensity in year 2004.

Show the code
cat(intensity_measure_name); cat(": \n"); 

did_model_s3z_a <- data_did %>% 
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>% 
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, intensity_2000, post_2005, book_leverage, debt_ebitda, sic, ff_30ind_name, large) %>% 
  filter(fyear >= period_start & fyear <= period_end) %>% 
  mutate( 
    gvkey = as.factor(gvkey), 
    fyear = as.factor(fyear), 
    treated = as.numeric(intensity_2000 > 0) 
  ) %>% 
  fixest::feols(fml = debt_ebitda ~ treated*post_2005 | gvkey + fyear + ff_30ind_name^fyear, data = ., cluster = c("gvkey", "ff_30ind_name")) 
  
did_model_s3z_b <- data_did %>% 
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>% 
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, intensity_2000, post_2005, book_leverage, debt_ebitda, sic, ff_30ind_name, large) %>% 
  filter(fyear >= period_start & fyear <= period_end) %>% 
  mutate( 
    gvkey = as.factor(gvkey), 
    fyear = as.factor(fyear), 
    treated = as.numeric(intensity_2000 > 0) 
  ) %>% 
  fixest::feols(fml = debt_ebitda ~ intensity_2000*post_2005 | gvkey + fyear + ff_30ind_name^fyear, data = ., cluster = c("gvkey", "ff_30ind_name")) 

mget(ls(pattern = "did_model_s3z_")) %>% 
  `names<-`(value = c("(a) treatment", "(b) intensity")) %>% 
  etable() %>% 
  knitr::kable(format = "html", caption = paste("DiD Results with `", intensity_measure_name, "`", sep = "")) %>% 
  kableExtra::kable_styling(
    font_size = 8,       # Smaller font (default is 16px)
    full_width = FALSE,   # Table width fits content 
    bootstrap_options = c("striped", "condensed")
  )
contract_intensity: 
DiD Results with `contract_intensity`
(a) treatment (b) intensity
Dependent Var.: debt_ebitda debt_ebitda
treated x post_2005 -0.1376 (0.0930)
intensity_2000 x post_2005 0.0064 (0.1446)
Fixed-Effects: ---------------- ---------------
gvkey Yes Yes
fyear Yes Yes
ff_30ind_name-fyear Yes Yes
__________________________ ________________ _______________
S.E.: Clustered by: gvkey & ff_3. by: gvkey & ff_3.
Observations 29,480 29,480
R2 0.75575 0.75567
Within R2 0.00031 3.95e-7

s3.1. PPE lease intensity

ppe_lease_intensity is chosen to measure a firm’s long-term exposure to lease contracts, especially non-residential real property lease obligations, which was expected to be impacted by the change in the bankruptcy code in 2005.

Show the code
## choose the group definition:
intensity_measure_name <- candidate_intensity_measure[2]

data_firm <- data %>%
  filter(fyear == intensity_measure_year) %>% # use `fyear` may create multiple observations for the same firm. E.g. filter(gvkey == 23535, dyear == 2005)
  group_by(fyear) %>%
  mutate(median_at = median(at, na.rm = TRUE)) %>%
  ungroup() %>%
  mutate(large = ifelse(at > median_at, 1, 0)) %>%
  select(gvkey, intensity_2000 = all_of(intensity_measure_name), large)

data_did <- data %>%
  ## merge the grouping variable
  left_join(y = data_firm, by = join_by(gvkey) ) %>%
  ## merge the FF 30 industry classification
  left_join(y = FF_30ind, by = join_by(sic)) %>%
  ## exclude certain industries
  filter(
    ff_30ind != 20, # exclude Utiltiy (number 20)
    !(sic >= 6000 & sic <= 6199) # exclude banks under Banking, Insurance, Real Estate, Trading (number 29)
  ) %>%
  ## pre- & post-
  mutate(
    indexyear = (fyear - base_year), # year index with 2005 as base 0.
    post_2005 = as.numeric(fyear > base_year)  # whether it is after the 2005 reform
  )

## gvkey(s) for balanced panel":
data_did_balanced_id <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  group_by(gvkey) %>%
  summarise(count_obs = sum(!is.na(book_leverage) & !is.na(intensity_2000))) %>%
  ungroup() %>%
  filter(count_obs == period_end - period_start + 1 + n_pre) %>%
  .$gvkey

DiD Analysis:

Show the code
cat(intensity_measure_name); cat(": \n");

did_model_s3a_a <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, intensity_2000, post_2005, book_leverage, debt_ebitda, sic, ff_30ind_name, large) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    treated = as.numeric(intensity_2000 > 0)
  ) %>%
  fixest::feols(fml = debt_ebitda ~ treated*post_2005 | gvkey + fyear + ff_30ind_name^fyear, data = ., cluster = c("gvkey", "ff_30ind_name"))

did_model_s3a_b <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, intensity_2000, post_2005, book_leverage, debt_ebitda, sic, ff_30ind_name, large) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    treated = as.numeric(intensity_2000 > 0)
  ) %>%
  fixest::feols(fml = debt_ebitda ~ intensity_2000*post_2005 | gvkey + fyear + ff_30ind_name^fyear, data = ., cluster = c("gvkey", "ff_30ind_name"))

mget(ls(pattern = "did_model_s3a_")) %>%
  `names<-`(value = c("(a) treatment", "(b) intensity")) %>%
  etable() %>%
  knitr::kable(format = "html", caption = paste("DiD Results with `", intensity_measure_name, "`", sep = "")) %>%
  kableExtra::kable_styling(
    font_size = 8,       # Smaller font (default is 16px)
    full_width = FALSE,   # Table width fits content
    bootstrap_options = c("striped", "condensed")
  )
ppe_lease_intensity: 
DiD Results with `ppe_lease_intensity`
(a) treatment (b) intensity
Dependent Var.: debt_ebitda debt_ebitda
treated x post_2005 -0.0337 (0.0813)
intensity_2000 x post_2005 -0.1547 (0.6312)
Fixed-Effects: ---------------- ----------------
gvkey Yes Yes
fyear Yes Yes
ff_30ind_name-fyear Yes Yes
__________________________ ________________ ________________
S.E.: Clustered by: gvkey & ff_3. by: gvkey & ff_3.
Observations 19,586 19,586
R2 0.74788 0.74788
Within R2 2.9e-5 1.77e-5

s3.2. builing intensity

building_intensity is chosen to measure a firm’s long-term exposure to buildings at cost under the PPE.

Show the code
## choose the group definition:
intensity_measure_name <- candidate_intensity_measure[3]

data_firm <- data %>%
  filter(fyear == intensity_measure_year) %>% # use `fyear` may create multiple observations for the same firm. E.g. filter(gvkey == 23535, dyear == 2005)
  group_by(fyear) %>%
  mutate(median_at = median(at, na.rm = TRUE)) %>%
  ungroup() %>%
  mutate(
    large = ifelse(at > median_at, 1, 0), 
    exposed = ifelse(contract_intensity > 0, yes = "With_Contract", no = "Without_Contract")
    ) %>%
  select(gvkey, intensity_2000 = all_of(intensity_measure_name), large, exposed)

data_did <- data %>%
  ## merge the grouping variable
  left_join(y = data_firm, by = join_by(gvkey) ) %>%
  ## merge the FF 30 industry classification
  left_join(y = FF_30ind, by = join_by(sic)) %>%
  ## exclude certain industries
  filter(
    ff_30ind != 20, # exclude Utiltiy (number 20)
    !(sic >= 6000 & sic <= 6199) # exclude banks under Banking, Insurance, Real Estate, Trading (number 29)
  ) %>%
  ## pre- & post-
  mutate(
    indexyear = (fyear - base_year), # year index with 2005 as base 0.
    post_2005 = as.numeric(fyear > base_year)  # whether it is after the 2005 reform
  )

## gvkey(s) for balanced panel":
data_did_balanced_id <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  group_by(gvkey) %>%
  summarise(count_obs = sum(!is.na(book_leverage) & !is.na(intensity_2000))) %>%
  ungroup() %>%
  filter(count_obs == period_end - period_start + 1 + n_pre) %>%
  .$gvkey

DiD Analysis:

Show the code
cat(intensity_measure_name); cat(": \n");

## create the combinations of parameters:
fml_parameters <- expand_grid( 
  choice_treatment = c("intensity_2000", "treated"), # what is the treatment measure: continuous/binary
  controls_inclusion = c(FALSE, TRUE, "Full"),# whether to include controls
  balanced_panel = c(FALSE, TRUE), # whether keep a balanced panel
) %>%
  arrange(balanced_panel) %>%
  cbind.data.frame(.,
    fml = apply(X = ., MARGIN = 1, FUN = function(parameters) {
      ## parameters:
      choice_treatment <- parameters[1]
      add_controls <- parameters[2]
      is_balanced <- parameters[3]

      ## inputs:
      fml_base <- paste("debt_ebitda ~ post_2005*", choice_treatment, sep = "") # the baseline model
      fml_base_controls <- " + roa + altman_Z + tangibility + current_ratio " # the potential controls
      fml_base_controls_full <- " + roa + ebitda_at + log(at_thousand) + altman_Z + tangibility + current_ratio" # the potential controls 
      fml_base_fe <- " | gvkey + indexyear + ff_30ind_name^indexyear" # fixed effects 
      
      ## output formula:
      fml_output <- paste(
        fml_base,
        ifelse(add_controls == TRUE,
               yes = fml_base_controls,
               no = ifelse(add_controls == "Full", yes = fml_base_controls_full, no = "") ),
        fml_base_fe,
        sep = ""
      )
      
      return(fml_output) 
    })
  ) %>%
  as_tibble() %>%
  ## assign a name for each regression:
  mutate(name = paste("(", 1:nrow(.), ")", sep = "")) %>%
  select(name, everything())

## construct the data used for the loop:
data_did_loop <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>% 
  # filter(building_intensity >= 0 & building_intensity <= 1) %>% 
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name, exposed, 
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

data_did_loop_balanced <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>% 
  # filter(building_intensity >= 0 & building_intensity <= 1) %>% 
  filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name, exposed, 
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

## store all results
fml_results <- fml_parameters %>%
  apply(MARGIN = 1, FUN = function(parameters) {
    ## parameters:
    is_balanced <- parameters[4]
    fml_formula <- parameters[5]

    ## data:
    if (is_balanced == TRUE) {
      data <- data_did_loop_balanced
    } else {
      data <- data_did_loop
    }

    ## regression:
    did_model <- fixest::feols(fml = formula(fml_formula),
                  data = data,
                  cluster = c("gvkey", "ff_30ind_name")
                  )
    return(did_model)
  })

### DiD result using post-:
fml_results %>%
  `names<-`(value = unlist(fml_parameters[,1])) %>%
  etable(
    order = "post",
    # keep = "post",
    se.below = TRUE, 
    # fontsize = "scriptsize", 
    extralines = list(
      ## Controls:
      "^_Controls" = ifelse(unlist(fml_parameters[,3]), yes = "Yes", no = "No"),
      ## the identity of the sample:
      "__Sample" = ifelse(unlist(fml_parameters[,4]), yes = "Balanced Panel", no = "Full Sample") # whether used a balanced panel or a full sample.
  )) %>%
  knitr::kable(format = "html", caption = paste("DiD Results with `", intensity_measure_name, "`", sep = "")) %>%
  kableExtra::kable_styling(
    font_size = 8,       # Smaller font (default is 16px)
    full_width = FALSE,   # Table width fits content
    bootstrap_options = c("striped", "condensed")
  )
building_intensity: 
DiD Results with `building_intensity`
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12)
Dependent Var.: debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda
post_2005 x intensity_2000 -0.4971 -0.3320 -0.1554 -0.6522* -0.6032* -0.2238
(0.2534) (0.2997) (0.2951) (0.2630) (0.2763) (0.2511)
post_2005 x treated -0.1313 -0.0733 0.0136 -0.1559* -0.1096 0.0201
(0.0779) (0.0831) (0.0757) (0.0608) (0.0639) (0.0681)
roa 0.0002 -9.76e-5 0.0002 -9.93e-5 -0.0414 -0.1335** -0.0424 -0.1342**
(0.0002) (0.0002) (0.0002) (0.0002) (0.0248) (0.0480) (0.0248) (0.0470)
altman_Z -9.64e-6*** -1.35e-5*** -9.55e-6*** -1.36e-5*** -9.45e-6*** -1.36e-5*** -9.37e-6*** -1.38e-5***
(2.37e-6) (2.64e-6) (2.34e-6) (2.62e-6) (2.51e-6) (2.97e-6) (2.5e-6) (3.02e-6)
tangibility 1.156* 1.017** 1.173* 1.041** 0.1811 0.4149 0.2501 0.4654
(0.4600) (0.3142) (0.4616) (0.3216) (0.4400) (0.3838) (0.4332) (0.3783)
current_ratio -0.0005** -0.0006** -0.0005** -0.0006** -0.0002 -0.0001 -0.0002 -0.0001
(0.0002) (0.0002) (0.0002) (0.0002) (9.53e-5) (9.99e-5) (9.8e-5) (0.0001)
ebitda_at -0.0038* -0.0038* -0.0209 -0.0214
(0.0016) (0.0016) (0.0661) (0.0659)
log(at_thousand) 0.5433*** 0.5451*** 0.7900*** 0.7960***
(0.0813) (0.0810) (0.1215) (0.1234)
Controls No Yes No Yes No Yes No Yes
Fixed-Effects: ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
gvkey Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
indexyear Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
ff_30ind_name-indexyear Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
__________________________ ___________ ___________ ___________ ___________ ___________ ___________ ___________ ___________ ___________ ___________ ___________ ___________
S.E.: Clustered by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3.
Observations 21,161 19,106 19,106 21,161 19,106 19,106 11,460 10,509 10,509 11,460 10,509 10,509
R2 0.74846 0.72222 0.72880 0.74844 0.72220 0.72879 0.73150 0.71539 0.72822 0.73137 0.71520 0.72818
Within R2 0.00050 0.00373 0.02732 0.00043 0.00366 0.02728 0.00134 0.00417 0.04907 0.00087 0.00352 0.04894
Sample Full Sample Full Sample Full Sample Full Sample Full Sample Full Sample Balanced Panel Balanced Panel Balanced Panel Balanced Panel Balanced Panel Balanced Panel

All treatment effect estimates are significantly negative across all specifications.

Next we estimate the yearly treatment effects.

Individual Year Treatment Plots

Important

Different from the previous document with book_leverage as the dependent variable, we do not control for the total asset and ebitda-to-asset ratio in this case.

Show the code
## create the combinations of parameters:
fml_parameters <- expand_grid(
  choice_treatment = c("intensity_2000", "treated"), # what is the treatment measure: continuous/binary
  controls_inclusion = c(FALSE, TRUE, "Full"),# whether to include controls
  balanced_panel = c(FALSE, TRUE), # whether keep a balanced panel
) %>%
  arrange(balanced_panel) %>%
  cbind.data.frame(.,
    fml = apply(X = ., MARGIN = 1, FUN = function(parameters) {
      ## parameters:
      choice_treatment <- parameters[1]
      add_controls <- parameters[2]
      is_balanced <- parameters[3]
      
      ## inputs: 
      fml_base <- paste("debt_ebitda ~ i(indexyear, ", choice_treatment, ", ref = -1)", sep = "") # the baseline model
      fml_base_controls <- " + roa + altman_Z + tangibility + current_ratio " 
        # " + roa + ebitda_at + log(at_thousand) + altman_Z + tangibility + current_ratio" # the potential controls
      fml_base_controls_full <- " + roa + ebitda_at + log(at_thousand) + altman_Z + tangibility + current_ratio" # the potential controls 
      fml_base_fe <- " | gvkey + indexyear + ff_30ind_name^indexyear" # fixed effects

      ## output formula:
      fml_output <- paste(
        fml_base,
        ifelse(add_controls == TRUE,  yes = fml_base_controls,  no = ifelse(add_controls == "Full", yes = fml_base_controls_full, no = "") ),
        fml_base_fe,
        sep = ""
      )

      return(fml_output)
    })
  ) %>%
  as_tibble() %>%
  ## assign a name for each regression:
  mutate(name = paste("(", letters[1:nrow(.)], ")", sep = "")) %>%
  select(name, everything())

fml_parameters
# A tibble: 12 × 5
   name  choice_treatment controls_inclusion balanced_panel fml                 
   <chr> <chr>            <chr>              <lgl>          <chr>               
 1 (a)   intensity_2000   FALSE              FALSE          debt_ebitda ~ i(ind…
 2 (b)   intensity_2000   TRUE               FALSE          debt_ebitda ~ i(ind…
 3 (c)   intensity_2000   Full               FALSE          debt_ebitda ~ i(ind…
 4 (d)   treated          FALSE              FALSE          debt_ebitda ~ i(ind…
 5 (e)   treated          TRUE               FALSE          debt_ebitda ~ i(ind…
 6 (f)   treated          Full               FALSE          debt_ebitda ~ i(ind…
 7 (g)   intensity_2000   FALSE              TRUE           debt_ebitda ~ i(ind…
 8 (h)   intensity_2000   TRUE               TRUE           debt_ebitda ~ i(ind…
 9 (i)   intensity_2000   Full               TRUE           debt_ebitda ~ i(ind…
10 (j)   treated          FALSE              TRUE           debt_ebitda ~ i(ind…
11 (k)   treated          TRUE               TRUE           debt_ebitda ~ i(ind…
12 (l)   treated          Full               TRUE           debt_ebitda ~ i(ind…
Show the code
## construct the data used for the loop:
data_did_loop <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005, exposed, 
         book_leverage, debt_ebitda, sic, ff_30ind_name, building_intensity, 
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity, contract_intensity, 
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  ) %>% 
  group_by(gvkey) %>%
  arrange(fyear) %>%
  mutate(d_building_intensity = building_intensity - lag(building_intensity, n = 1)) %>% 
  ungroup() 

data_did_loop_balanced <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005, exposed, 
         book_leverage, debt_ebitda, sic, ff_30ind_name, building_intensity, 
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity, contract_intensity, 
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  ) %>% 
  group_by(gvkey) %>%
  arrange(fyear) %>%
  mutate(d_building_intensity = building_intensity - lag(building_intensity, n = 1)) %>% 
  ungroup()

## store all results
fml_results <- fml_parameters %>%
  apply(MARGIN = 1, FUN = function(parameters) {
    ## parameters:
    is_balanced <- parameters[4]
    fml_formula <- parameters[5]

    ## data:
    if (is_balanced == TRUE) {
      data <- data_did_loop_balanced
    } else {
      data <- data_did_loop
    }

    ## regression:
    did_model <- fixest::feols(fml = formula(fml_formula),
                  data = data,
                  cluster = c("gvkey", "ff_30ind_name")
                  )
    return(did_model)
  })
NOTE: 2,680 observations removed because of NA and infinite values (RHS: 2,680).
NOTE: 2,680 observations removed because of NA and infinite values (RHS: 2,680).
NOTE: 2,680 observations removed because of NA and infinite values (RHS: 2,680).
NOTE: 2,680 observations removed because of NA and infinite values (RHS: 2,680).
NOTE: 1,167 observations removed because of NA and infinite values (RHS: 1,167).
NOTE: 1,167 observations removed because of NA and infinite values (RHS: 1,167).
NOTE: 1,167 observations removed because of NA and infinite values (RHS: 1,167).
NOTE: 1,167 observations removed because of NA and infinite values (RHS: 1,167).
Show the code
### create the table:
fml_results %>%
  `names<-`(value = unlist(fml_parameters[,1])) %>%
  etable(
    order = "indexyear",
    # keep = "post",
    se.below = TRUE, 
    extralines = list(
      ## Controls:
      "^_Controls" = ifelse(unlist(fml_parameters[,3]), yes = "Yes", no = "No"),
      ## the identity of the sample:
      "__Sample" = ifelse(unlist(fml_parameters[,4]), yes = "Balanced Panel", no = "Full Sample") # whether used a balanced panel or a full sample.
  )) %>%
  knitr::kable(format = "html", caption = paste("DiD Results with `", intensity_measure_name, "`", sep = "")) %>%
  kableExtra::kable_styling(
    font_size = 8,       # Smaller font (default is 16px)
    full_width = FALSE,   # Table width fits content
    bootstrap_options = c("striped", "condensed")
  )
DiD Results with `building_intensity`
(a) (b) (c) (d) (e) (f) (g) (h) (i) (j) (k) (l)
Dependent Var.: debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda
intensity_2000 x indexyear = -3 0.0808 0.0858 0.0478 -0.2813 -0.3391 -0.4156
(0.3389) (0.3220) (0.3309) (0.5596) (0.6605) (0.6672)
intensity_2000 x indexyear = -2 -0.0005 -0.0127 -0.0562 -0.0752 -0.1321 -0.2013
(0.2318) (0.2193) (0.2096) (0.4846) (0.5466) (0.5328)
intensity_2000 x indexyear = 0 -0.5630* -0.3362 -0.2801 -0.8343** -0.8275** -0.6496*
(0.2685) (0.2849) (0.2829) (0.2576) (0.2686) (0.2714)
intensity_2000 x indexyear = 1 -0.7030 -0.4454 -0.3301 -0.9667** -0.8193* -0.5480
(0.3550) (0.3748) (0.3750) (0.2909) (0.3362) (0.3187)
intensity_2000 x indexyear = 2 -0.8305* -0.4649 -0.2703 -0.9485** -0.9321** -0.5693*
(0.3398) (0.3709) (0.3550) (0.2770) (0.2959) (0.2630)
intensity_2000 x indexyear = 3 -0.8485* -0.7160 -0.4682 -0.9507* -0.8997* -0.4361
(0.3605) (0.5041) (0.4957) (0.3693) (0.3343) (0.2960)
treated x indexyear = -3 0.2434*** 0.2043** 0.2057** 0.1246 0.1273 0.1176
(0.0612) (0.0656) (0.0669) (0.0768) (0.0815) (0.0822)
treated x indexyear = -2 0.0808 0.0131 -0.0067 0.0495 0.0167 -0.0090
(0.0588) (0.0631) (0.0587) (0.0681) (0.0777) (0.0755)
treated x indexyear = 0 -0.1494 -0.1443 -0.1185 -0.1842** -0.1756* -0.1049
(0.0761) (0.0870) (0.0855) (0.0657) (0.0693) (0.0618)
treated x indexyear = 1 -0.2103* -0.1896 -0.1206 -0.1663* -0.1345 -0.0245
(0.0889) (0.0926) (0.0901) (0.0797) (0.0835) (0.0738)
treated x indexyear = 2 -0.1934* -0.1443 -0.0522 -0.2236** -0.1669* -0.0364
(0.0884) (0.0966) (0.0912) (0.0673) (0.0649) (0.0592)
treated x indexyear = 3 -0.1260 -0.0847 0.0341 -0.2123* -0.1794 -0.0266
(0.1370) (0.1468) (0.1370) (0.0973) (0.0932) (0.0932)
roa 0.0002 -0.0001 0.0002 -0.0001 -0.0289 0.0266 -0.0294 0.0246
(0.0002) (0.0002) (0.0002) (0.0002) (0.0208) (0.1076) (0.0207) (0.1063)
altman_Z -1.04e-5** -1.45e-5*** -1e-5** -1.45e-5*** -9.2e-6** -1.35e-5*** -8.83e-6** -1.34e-5***
(2.97e-6) (3.41e-6) (2.91e-6) (3.37e-6) (2.74e-6) (3.33e-6) (2.69e-6) (3.34e-6)
tangibility 1.232** 1.061** 1.230** 1.063** 0.4636 0.4681 0.4928 0.4751
(0.3943) (0.3068) (0.3976) (0.3209) (0.3945) (0.4352) (0.3899) (0.4386)
current_ratio -0.0006* -0.0007* -0.0006* -0.0007* -0.0002 -0.0001 -0.0002 -0.0001
(0.0002) (0.0003) (0.0002) (0.0003) (0.0001) (0.0001) (0.0001) (0.0001)
ebitda_at -0.0044* -0.0043* -0.1738 -0.1717
(0.0019) (0.0018) (0.1301) (0.1295)
log(at_thousand) 0.5208*** 0.5207*** 0.7262*** 0.7263***
(0.0706) (0.0696) (0.1117) (0.1120)
Controls No Yes No Yes No Yes No Yes
Fixed-Effects: ----------- ----------- ----------- ----------- -------------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
gvkey Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
indexyear Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
ff_30ind_name-indexyear Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
_______________________________ ___________ ___________ ___________ ___________ ______________ ___________ ___________ ___________ ___________ ___________ ___________ ___________
S.E.: Clustered by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3.
Observations 25,433 22,753 22,753 25,433 22,753 22,753 13,370 12,203 12,203 13,370 12,203 12,203
R2 0.72626 0.70275 0.70978 0.72656 0.70303 0.71003 0.70168 0.68651 0.69967 0.70178 0.68655 0.69967
Within R2 0.00106 0.00479 0.02836 0.00213 0.00574 0.02918 0.00180 0.00465 0.04645 0.00212 0.00479 0.04644
Sample Full Sample Full Sample Full Sample Full Sample Full Sample Full Sample Balanced Panel Balanced Panel Balanced Panel Balanced Panel Balanced Panel Balanced Panel
Show the code
### create the plots:
# fml_parameters[which(unlist(fml_parameters$balanced_panel)), ]
fml_results[which(unlist(fml_parameters$balanced_panel))] %>% # choose the balanced panel
  iplot(.,
        xlab = paste("Time to treatment (Year; 0 = ", base_year, ")", sep = ""),
        main = paste("Treatment Effects by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Balanced Panel",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE,
        xlim = c(period_start - n_pre - base_year - 0.5, period_end - base_year + 0.5)
        ); axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5)); abline(v = 0.5, col = "red", lty = 2, lwd = 3); legend('bottomleft', bty = "n", col = c(1, 2, 3, 4), pch = c(20, 17, 15, 21), legend = c('intensity', 'intensity + controls', 'dummy', 'dummy + controls'));

Show the code
#### intensity only: 
fml_results[which(unlist(fml_parameters$balanced_panel))][1:2] %>% # choose the balanced panel
  iplot(.,
        xlab = paste("Time to treatment (Year; 0 = ", base_year, ")", sep = ""),
        main = paste("Treatment Effects by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Balanced Panel",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE,
        xlim = c(period_start - n_pre - base_year - 0.5, period_end - base_year + 0.5)
        ); axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5)); abline(v = 0.5, col = "red", lty = 2, lwd = 3); legend('bottomleft', bty = "n", col = c(1, 2, 3, 4), pch = c(20, 17, 15, 21), legend = c('intensity', 'intensity + controls', 'dummy', 'dummy + controls')[1:2]);

Show the code
fml_results[which(!unlist(fml_parameters$balanced_panel))] %>% # choose full sample
  iplot(.,
        xlab = paste("Time to treatment (Year; 0 = ", base_year, ")", sep = ""),
        main = paste("Treatment Effect by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Full Sample",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE,
        xlim = c(period_start - n_pre - base_year - 0.5, period_end - base_year + 0.5)
        ); axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5)); abline(v = 0.5, col = "red", lty = 2, lwd = 3); legend('bottomleft', bty = "n", col = c(1, 2, 3, 4), pch = c(20, 17, 15, 21), legend = c('intensity', 'intensity + controls', 'dummy', 'dummy + controls'))

We plot the yearly treatment effect estimates with different model specifications using both the balanced panel and the full sample. As the full sample will contain some firms with extremely high leverage and high building intensity before 2004, we believe that it is more reasonable to use a balanced sample for the analysis.

We conclude that the pre-trend assumption is not violated and we can see a significant negative treatment effect around 2005 (end of fiscal year 2004) and after 2005.

w/ and w/o Executory Contracts:

Show the code
did_model_subsample <- data_did_loop_balanced %>% 
  fixest::feols(fml = debt_ebitda ~ i(fyear, intensity_2000, ref = base_year - 1) +
                  roa + altman_Z + tangibility + current_ratio |
                  gvkey + fyear + ff_30ind_name^fyear,
                data = .,
                cluster = c("gvkey", "ff_30ind_name"),
                split = ~ exposed # large
                ) 

did_model_subsample %>% etable(se.below = TRUE) 

did_model_subsample %>% 
  iplot(.,
        xlab = paste("Time to treatment (Year ", base_year, ")", sep = ""),
        main = paste("Treatment Effects by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Balanced Panel",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE
        # xlim = c(period_start - n_pre - 0.5, period_end + 0.5)
        ); 
# axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5));
abline(v = base_year - (period_start - n_pre) + 1.5, col = "red", lty = 2, lwd = 3); legend('bottomleft', bty = "n", col = c(1, 2), pch = c(20, 17), legend = c('With Executory Contracts', 'Without Executory Contracts'));

Show the code
# Calculate the Wald statistics
model_large <- did_model_subsample[[1]]
model_small <- did_model_subsample[[2]]
## get the name of the coefficient of interests
coef_names <- names(model_large$coefficients) %>%
  .[str_detect(string = ., pattern = "::")]
coef_large <- coef(model_large)[coef_names]
coef_small <- coef(model_small)[coef_names]
# Difference in treatment effects
diff_coef <- coef_large - coef_small
# Variance of the difference
var_diff <- vcov(model_large)[coef_names, coef_names] + vcov(model_small)[coef_names, coef_names]
# Wald statistic for each treatment effect estimate
wald_stat <- (diff_coef)^2 / diag(var_diff)
wald_stat_vector <- c(t(diff_coef) %*% solve(var_diff) %*% (diff_coef))
# Degrees of freedom
df <- 1
df_vector <- length(diff_coef)
# P-value
p_value <- 1 - pchisq(wald_stat, df)
p_value_vector <- 1 - pchisq(wald_stat_vector, df_vector)

convert_p_to_stars <- function(p_values) {
  # Initialize a character vector to store the significance stars
  stars <- character(length(p_values))
  # Assign stars based on p-value thresholds
  stars[p_values < 0.001] <- "***"
  stars[p_values >= 0.001 & p_values < 0.01] <- "**"
  stars[p_values >= 0.01 & p_values < 0.05] <- "*"
  stars[p_values >= 0.05 & p_values < 0.1] <- "."
  stars[p_values >= 0.1] <- ""
  return(stars)
}

# Output results
cat("\n\nWald test for the difference in the treatment effect\n between the firms with and w/o executory contracts: \n\n")
data.frame(
  Diff = diff_coef,
  `Std. Error` = sqrt(diag(var_diff)),
  `Wald stat` = wald_stat,
  `P value` = p_value,
  Star = convert_p_to_stars(p_value)
) %>% 
  rbind.data.frame(., "Multipel Testing:" = c("", "", wald_stat_vector, p_value_vector, convert_p_to_stars(p_value_vector) )) %>% 
  mutate_if(is.numeric, round, digits = 4) 
cat("Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 \n\n")


## Interacting with With/Withou Contracts:

data_did_loop_balanced %>% 
  fixest::feols(fml = debt_ebitda ~ intensity_2000 + post_2005 + exposed + post_2005*exposed + intensity_2000*exposed + intensity_2000:post_2005:i(exposed)
                + roa + altman_Z + tangibility + current_ratio 
                |
                  gvkey + fyear + ff_30ind_name^fyear, data = ., cluster = c("gvkey", "ff_30ind_name")) %>%

  etable()
                                            ..1               ..2
Sample (exposed)                  With_Contract  Without_Contract
Dependent Var.:                     debt_ebitda       debt_ebitda
                                                                 
intensity_2000 x fyear = 2001        -0.4476             0.7865  
                                     (0.7277)           (0.5577) 
intensity_2000 x fyear = 2002        -0.1977             0.7111  
                                     (0.4953)           (1.468)  
intensity_2000 x fyear = 2004        -0.7901**          -1.124   
                                     (0.2458)           (1.010)  
intensity_2000 x fyear = 2005        -0.6199            -1.669   
                                     (0.3244)           (0.9366) 
intensity_2000 x fyear = 2006        -0.8215*           -1.631   
                                     (0.2993)           (0.8817) 
intensity_2000 x fyear = 2007        -0.5943            -2.336** 
                                     (0.3995)           (0.8307) 
roa                                  -0.3687            -0.0021  
                                     (0.1902)           (0.0065) 
altman_Z                             -1.03e-5**         -3.74e-6 
                                     (3.2e-6)           (3.84e-6)
tangibility                          -0.1177             0.6490  
                                     (0.4734)           (0.5387) 
current_ratio                        -0.0167***         -8.98e-5 
                                     (0.0039)           (0.0002) 
Fixed-Effects:                      -----------       -----------
gvkey                                       Yes               Yes
fyear                                       Yes               Yes
ff_30ind_name-fyear                         Yes               Yes
_____________________________       ___________       ___________
S.E.: Clustered               by: gvkey & ff_3. by: gvkey & ff_3.
Observations                             10,761             1,442
R2                                      0.68650           0.75663
Within R2                               0.01060           0.02977
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1


Wald test for the difference in the treatment effect
 between the firms with and w/o executory contracts: 

                                         Diff        Std..Error
fyear::2001:intensity_2000  -1.23410175568837 0.916799149112446
fyear::2002:intensity_2000 -0.908715526218854  1.54892471650765
fyear::2004:intensity_2000  0.334305250861653  1.03941894243352
fyear::2005:intensity_2000   1.04906199201834 0.991211196783058
fyear::2006:intensity_2000  0.809553274572727 0.931088708136322
fyear::2007:intensity_2000   1.74188814518982 0.921746995119689
Multipel Testing:                                              
                                   Wald.stat            P.value Star
fyear::2001:intensity_2000  1.81198057343623   0.17827082400667     
fyear::2002:intensity_2000 0.344187645135528  0.557421949890968     
fyear::2004:intensity_2000 0.103443960958068  0.747735246933118     
fyear::2005:intensity_2000  1.12013381182965  0.289889642622698     
fyear::2006:intensity_2000 0.755977288103978  0.384590359340544     
fyear::2007:intensity_2000  3.57122378973034 0.0587889704341635    .
Multipel Testing:           11.5288004909928 0.0733449898262329    .
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 

                                                                           .
Dependent Var.:                                                  debt_ebitda
                                                                            
roa                                                         -0.0305 (0.0205)
altman_Z                                                -9.32e-6** (2.76e-6)
tangibility                                                  0.4590 (0.3618)
current_ratio                                               -0.0002 (0.0001)
post_2005 x exposedWithout_Contract                         0.2359* (0.1149)
intensity_2000 x post_2005 x exposed = With_Contract        -0.3141 (0.2987)
intensity_2000 x post_2005 x exposed = Without_Contract   -1.966*** (0.4927)
Fixed-Effects:                                          --------------------
gvkey                                                                    Yes
fyear                                                                    Yes
ff_30ind_name-fyear                                                      Yes
________________________________________                ____________________
S.E.: Clustered                                            by: gvkey & ff_3.
Observations                                                          12,203
R2                                                                   0.68663
Within R2                                                            0.00503
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Placebal tests:

Show the code
cat(intensity_measure_name); cat(": \n");

## create the combinations of parameters:
fml_parameters <- expand_grid(
  choice_treatment = c("intensity_2000", "treated"), # what is the treatment measure: continuous/binary
  controls_inclusion = c(FALSE, TRUE, "Full"),# whether to include controls
  balanced_panel = c(FALSE, TRUE), # whether keep a balanced panel
) %>%
  arrange(balanced_panel) %>%
  cbind.data.frame(.,
    fml = apply(X = ., MARGIN = 1, FUN = function(parameters) {
      ## parameters:
      choice_treatment <- parameters[1]
      add_controls <- parameters[2]
      is_balanced <- parameters[3]

      ## inputs:
      fml_base <- paste("ebitda_at ~ post_2005*", choice_treatment, sep = "") # the baseline model
      fml_base_controls <- " + roa + altman_Z + tangibility + current_ratio" # the potential controls 
      fml_base_controls_full <- " + roa + ebitda_at + log(at_thousand) + altman_Z + tangibility + current_ratio" # the potential controls 
      fml_base_fe <- " | gvkey + indexyear + ff_30ind_name^indexyear" # fixed effects

      ## output formula:
      fml_output <- paste(
        fml_base,
        ifelse(add_controls == TRUE,  yes = fml_base_controls,  no = ifelse(add_controls == "Full", yes = fml_base_controls_full, no = "") ),
        fml_base_fe,
        sep = ""
      )

      return(fml_output)
    })
  ) %>%
  as_tibble() %>%
  ## assign a name for each regression:
  mutate(name = paste("(", 1:nrow(.), ")", sep = "")) %>%
  select(name, everything())

## construct the data used for the loop:
data_did_loop <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>% 
  # filter(building_intensity >= 0 & building_intensity <= 1) %>% 
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name, exposed, 
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at, 
    ebitda_ppe = ebitda / ppent, # placebo
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

data_did_loop_balanced <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>% 
  # filter(building_intensity >= 0 & building_intensity <= 1) %>% 
  filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name, exposed, 
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at, 
    ebitda_ppe = ebitda / ppent, # placebo 
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

## store all results
fml_results <- fml_parameters %>%
  apply(MARGIN = 1, FUN = function(parameters) {
    ## parameters:
    is_balanced <- parameters[4]
    fml_formula <- parameters[5]

    ## data:
    if (is_balanced == TRUE) {
      data <- data_did_loop_balanced
    } else {
      data <- data_did_loop
    }

    ## regression:
    did_model <- fixest::feols(fml = formula(fml_formula),
                  data = data,
                  cluster = c("gvkey", "ff_30ind_name")
                  )
    return(did_model)
  })

### DiD result using post-:
fml_results %>%
  `names<-`(value = unlist(fml_parameters[,1])) %>%
  etable(
    order = "post",
    # keep = "post",
    se.below = TRUE, 
    # fontsize = "scriptsize", 
    extralines = list(
      ## Controls:
      "^_Controls" = ifelse(unlist(fml_parameters[,3]), yes = "Yes", no = "No"),
      ## the identity of the sample:
      "__Sample" = ifelse(unlist(fml_parameters[,4]), yes = "Balanced Panel", no = "Full Sample") # whether used a balanced panel or a full sample.
  )) %>%
  knitr::kable(format = "html", caption = paste("DiD Results with `", intensity_measure_name, "`", sep = "")) %>%
  kableExtra::kable_styling(
    font_size = 8,       # Smaller font (default is 16px)
    full_width = FALSE,   # Table width fits content
    bootstrap_options = c("striped", "condensed")
  )
building_intensity: 
DiD Results with `building_intensity`
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12)
Dependent Var.: ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at
post_2005 x intensity_2000 -2.164 -2.439 -4.44e-16 -0.0470 0.0182 6.59e-17
(2.072) (1.861) (6.24e-16) (0.0507) (0.0290) (6.54e-17)
post_2005 x treated -0.4536 -0.5180 -1.67e-16 -0.0477 0.0002 2.08e-17
(0.6082) (0.5698) (2.66e-16) (0.0399) (0.0136) (9.47e-17)
roa 0.1437 1.62e-17 0.1438 3.34e-17 0.9165*** 9.71e-17 0.9166*** -5.57e-16
(0.1584) (2.09e-17) (0.1585) (3.68e-17) (0.0345) (1.74e-16) (0.0345) (1.1e-15)
altman_Z -5.26e-9 -1.06e-21 5.87e-7 5.72e-21 -1.02e-7 1.39e-22 -9.4e-8 3.18e-22
(1.56e-6) (6.69e-21) (2.1e-6) (7.53e-21) (1.17e-7) (3.42e-22) (9.55e-8) (2.08e-21)
tangibility -4.508 -1.94e-15 -4.371 -3.05e-16 0.1726 2.02e-16 0.1693 -1.94e-16
(5.187) (2.69e-15) (5.146) (2.62e-15) (0.1712) (4.3e-16) (0.1703) (2.86e-15)
current_ratio 0.0007 2.17e-19 0.0007 2.81e-19 -5.84e-5 -3.42e-20 -5.85e-5 -1.73e-19
(0.0005) (1.88e-19) (0.0005) (1.85e-19) (3.3e-5) (7.71e-20) (3.28e-5) (3.37e-19)
ebitda_at 1.000*** 1.000*** 1.000*** 1.000***
(2.74e-16) (2.75e-16) (2.8e-16) (1.66e-15)
log(at_thousand) -8.19e-16 -9.23e-16 -1.39e-16 -1.86e-17
(9.33e-16) (9.4e-16) (6.99e-17) (3.68e-16)
Controls No Yes No Yes No Yes No Yes
Fixed-Effects: --------- --------- ---------- --------- --------- ---------- --------- ---------- ---------- --------- ---------- ----------
gvkey Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
indexyear Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
ff_30ind_name-indexyear Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
__________________________ _________ _________ __________ _________ _________ __________ _________ __________ __________ _________ __________ __________
S.E.: Clustered by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3.
Observations 21,161 19,106 19,106 21,161 19,106 19,106 11,460 10,509 10,509 11,460 10,509 10,509
R2 0.99807 0.99836 1 0.99807 0.99836 1 0.66161 0.97118 1 0.66169 0.97118 1
Within R2 0.00029 0.13595 1 0.00016 0.13582 1 2.3e-5 0.91626 1 0.00027 0.91625 1
Sample Full Sample Full Sample Full Sample Full Sample Full Sample Full Sample Balanced Panel Balanced Panel Balanced Panel Balanced Panel Balanced Panel Balanced Panel

For yearly treatment effects and parallel trend analysis,

Show the code
## create the combinations of parameters:
fml_parameters <- expand_grid(
  choice_treatment = c("intensity_2000", "treated"), # what is the treatment measure: continuous/binary
  controls_inclusion = c(FALSE, TRUE, "Full"),# whether to include controls
  balanced_panel = c(FALSE, TRUE), # whether keep a balanced panel
) %>%
  arrange(balanced_panel) %>%
  cbind.data.frame(.,
    fml = apply(X = ., MARGIN = 1, FUN = function(parameters) {
      ## parameters:
      choice_treatment <- parameters[1]
      add_controls <- parameters[2]
      is_balanced <- parameters[3]

      ## inputs:
      fml_base <- paste("ebitda_at ~ i(indexyear, ", choice_treatment, ", ref = -1)", sep = "") # the baseline model
      fml_base_controls <- " + roa + ebitda_at + log(at_thousand) + altman_Z + tangibility + current_ratio" # the potential controls 
      fml_base_controls_full <- " + roa + ebitda_at + log(at_thousand) + altman_Z + tangibility + current_ratio" # the potential controls 
      fml_base_fe <- " | gvkey + indexyear + ff_30ind_name^indexyear" # fixed effects

      ## output formula:
      fml_output <- paste(
        fml_base,
        ifelse(add_controls == TRUE,  yes = fml_base_controls,  no = ifelse(add_controls == "Full", yes = fml_base_controls_full, no = "") ),
        fml_base_fe,
        sep = ""
      )

      return(fml_output)
    })
  ) %>%
  as_tibble() %>%
  ## assign a name for each regression:
  mutate(name = paste("(", letters[1:nrow(.)], ")", sep = "")) %>%
  select(name, everything())

fml_parameters
# A tibble: 12 × 5
   name  choice_treatment controls_inclusion balanced_panel fml                 
   <chr> <chr>            <chr>              <lgl>          <chr>               
 1 (a)   intensity_2000   FALSE              FALSE          ebitda_at ~ i(index…
 2 (b)   intensity_2000   TRUE               FALSE          ebitda_at ~ i(index…
 3 (c)   intensity_2000   Full               FALSE          ebitda_at ~ i(index…
 4 (d)   treated          FALSE              FALSE          ebitda_at ~ i(index…
 5 (e)   treated          TRUE               FALSE          ebitda_at ~ i(index…
 6 (f)   treated          Full               FALSE          ebitda_at ~ i(index…
 7 (g)   intensity_2000   FALSE              TRUE           ebitda_at ~ i(index…
 8 (h)   intensity_2000   TRUE               TRUE           ebitda_at ~ i(index…
 9 (i)   intensity_2000   Full               TRUE           ebitda_at ~ i(index…
10 (j)   treated          FALSE              TRUE           ebitda_at ~ i(index…
11 (k)   treated          TRUE               TRUE           ebitda_at ~ i(index…
12 (l)   treated          Full               TRUE           ebitda_at ~ i(index…
Show the code
## construct the data used for the loop:
data_did_loop <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005, exposed, 
         book_leverage, debt_ebitda, sic, ff_30ind_name, building_intensity, 
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity, contract_intensity, 
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  ) %>% 
  group_by(gvkey) %>%
  arrange(fyear) %>%
  mutate(d_building_intensity = building_intensity - lag(building_intensity, n = 1)) %>% 
  ungroup() 

data_did_loop_balanced <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005, exposed, 
         book_leverage, debt_ebitda, sic, ff_30ind_name, building_intensity, 
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity, contract_intensity, 
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  ) %>% 
  group_by(gvkey) %>%
  arrange(fyear) %>%
  mutate(d_building_intensity = building_intensity - lag(building_intensity, n = 1)) %>% 
  ungroup()

## store all results
fml_results <- fml_parameters %>%
  apply(MARGIN = 1, FUN = function(parameters) {
    ## parameters:
    is_balanced <- parameters[4]
    fml_formula <- parameters[5]

    ## data:
    if (is_balanced == TRUE) {
      data <- data_did_loop_balanced
    } else {
      data <- data_did_loop
    }

    ## regression:
    did_model <- fixest::feols(fml = formula(fml_formula),
                  data = data,
                  cluster = c("gvkey", "ff_30ind_name")
                  )
    return(did_model)
  })
NOTE: 2,680 observations removed because of NA and infinite values (RHS: 2,680).
NOTE: 2,680 observations removed because of NA and infinite values (RHS: 2,680).
NOTE: 2,680 observations removed because of NA and infinite values (RHS: 2,680).
NOTE: 2,680 observations removed because of NA and infinite values (RHS: 2,680).
NOTE: 1,167 observations removed because of NA and infinite values (RHS: 1,167).
NOTE: 1,167 observations removed because of NA and infinite values (RHS: 1,167).
NOTE: 1,167 observations removed because of NA and infinite values (RHS: 1,167).
NOTE: 1,167 observations removed because of NA and infinite values (RHS: 1,167).
Show the code
### create the table:
fml_results %>%
  `names<-`(value = unlist(fml_parameters[,1])) %>%
  etable(
    order = "indexyear",
    # keep = "post",
    se.below = TRUE, 
    extralines = list(
      ## Controls:
      "^_Controls" = ifelse(unlist(fml_parameters[,3]), yes = "Yes", no = "No"),
      ## the identity of the sample:
      "__Sample" = ifelse(unlist(fml_parameters[,4]), yes = "Balanced Panel", no = "Full Sample") # whether used a balanced panel or a full sample.
  )) %>%
  knitr::kable(format = "html", caption = paste("DiD Results with `", intensity_measure_name, "`", sep = "")) %>%
  kableExtra::kable_styling(
    font_size = 8,       # Smaller font (default is 16px)
    full_width = FALSE,   # Table width fits content
    bootstrap_options = c("striped", "condensed")
  )
DiD Results with `building_intensity`
(a) (b) (c) (d) (e) (f) (g) (h) (i) (j) (k) (l)
Dependent Var.: ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at ebitda_at
intensity_2000 x indexyear = -3 -0.5529 9.25e-16* 9.25e-16* 0.0565 1.37e-16 1.37e-16
(0.3423) (4.29e-16) (4.29e-16) (0.0616) (1.98e-16) (1.98e-16)
intensity_2000 x indexyear = -2 0.9541* -3.21e-15** -3.21e-15** 0.1148* 8.35e-17 8.35e-17
(0.4238) (1.02e-15) (1.02e-15) (0.0551) (1.86e-16) (1.86e-16)
intensity_2000 x indexyear = 0 2.988 -1.27e-15 -1.27e-15 0.1182 -3.85e-17 -3.85e-17
(2.385) (6.43e-16) (6.43e-16) (0.0917) (1.17e-16) (1.17e-16)
intensity_2000 x indexyear = 1 -1.941 -8.33e-16 -8.33e-16 -0.0105 -9.48e-17 -9.48e-17
(2.875) (1.15e-15) (1.15e-15) (0.0306) (1.88e-16) (1.88e-16)
intensity_2000 x indexyear = 2 -0.0603 8.5e-17 8.5e-17 0.0085 -1.98e-16 -1.98e-16
(0.3189) (4.89e-16) (4.89e-16) (0.0615) (2.03e-16) (2.03e-16)
intensity_2000 x indexyear = 3 -0.7247 -8.39e-16 -8.39e-16 0.0941 -6.84e-17 -6.84e-17
(0.7378) (7.14e-16) (7.14e-16) (0.0898) (2.85e-16) (2.85e-16)
treated x indexyear = -3 -0.4206 -2.73e-17 -2.73e-17 0.0598 -1.77e-17 -1.77e-17
(0.2369) (9.9e-17) (9.9e-17) (0.0557) (2.96e-16) (2.96e-16)
treated x indexyear = -2 0.3131 5.14e-16* 5.14e-16* 0.0785 -2.82e-17 -2.82e-17
(0.2705) (1.92e-16) (1.92e-16) (0.0424) (3.4e-16) (3.4e-16)
treated x indexyear = 0 0.9261 7.22e-16* 7.22e-16* 0.1343 6.61e-17 6.61e-17
(0.8183) (2.91e-16) (2.91e-16) (0.0987) (2.17e-16) (2.17e-16)
treated x indexyear = 1 -0.2270 -1.59e-16 -1.59e-16 -0.0176 1.98e-17 1.98e-17
(0.8598) (3.84e-16) (3.84e-16) (0.0208) (2.33e-16) (2.33e-16)
treated x indexyear = 2 -0.0524 2.64e-16 2.64e-16 0.0086 3e-17 3e-17
(0.2070) (1.55e-16) (1.55e-16) (0.0399) (1.72e-16) (1.72e-16)
treated x indexyear = 3 -0.1022 5.73e-17 5.73e-17 0.0788 -3.14e-17 -3.14e-17
(0.2196) (1.51e-16) (1.51e-16) (0.0551) (3.26e-16) (3.26e-16)
roa 5.33e-17 5.33e-17 7.84e-17 7.84e-17 -2.72e-15 -2.72e-15 3.72e-15 3.72e-15
(4.73e-17) (4.73e-17) (8.12e-17) (8.12e-17) (1.65e-15) (1.65e-15) (4.07e-15) (4.07e-15)
ebitda_at 1.000*** 1.000*** 1.000*** 1.000*** 1.000*** 1.000*** 1.000*** 1.000***
(2.56e-16) (2.56e-16) (2.57e-16) (2.57e-16) (1.35e-15) (1.35e-15) (4.45e-15) (4.45e-15)
log(at_thousand) 1.57e-16 1.57e-16 -6.07e-16 -6.07e-16 -1.54e-16 -1.54e-16 9.24e-17 9.24e-17
(7.03e-16) (7.03e-16) (7.04e-16) (7.04e-16) (1.73e-16) (1.73e-16) (5.45e-16) (5.45e-16)
altman_Z 4.99e-21 4.99e-21 -1.37e-21 -1.37e-21 8.13e-22 8.13e-22 -4.37e-22 -4.37e-22
(5.51e-21) (5.51e-21) (5.84e-21) (5.84e-21) (8.13e-22) (8.13e-22) (3.27e-21) (3.27e-21)
tangibility 1.59e-15 1.59e-15 -8.29e-16 -8.29e-16 1.17e-16 1.17e-16 -1.54e-16 -1.54e-16
(2.27e-15) (2.27e-15) (1.56e-15) (1.56e-15) (1.55e-15) (1.55e-15) (5.09e-15) (5.09e-15)
current_ratio -2.17e-19 -2.17e-19 8.67e-19 8.67e-19 -1.36e-20 -1.36e-20 -2.3e-19 -2.3e-19
(4.3e-19) (4.3e-19) (4.86e-19) (4.86e-19) (1.96e-19) (1.96e-19) (7.69e-19) (7.69e-19)
Controls No Yes No Yes No Yes No Yes
Fixed-Effects: --------- ----------- ----------- --------- ---------- ---------- --------- ---------- ---------- --------- ------------- -------------
gvkey Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
indexyear Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
ff_30ind_name-indexyear Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
_______________________________ _________ ___________ ___________ _________ __________ __________ _________ __________ __________ _________ _____________ _____________
S.E.: Clustered by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3.
Observations 25,433 22,753 22,753 25,433 22,753 22,753 13,370 12,203 12,203 13,370 12,203 12,203
R2 0.99773 1 1 0.99773 1 1 0.62340 1 1 0.62378 1 1
Within R2 0.00059 1 1 0.00060 1 1 0.00010 1 1 0.00110 1 1
Sample Full Sample Full Sample Full Sample Full Sample Full Sample Full Sample Balanced Panel Balanced Panel Balanced Panel Balanced Panel Balanced Panel Balanced Panel
Show the code
### create the plots:
# fml_parameters[which(unlist(fml_parameters$balanced_panel)), ]
fml_results[which(unlist(fml_parameters$balanced_panel))] %>% # choose the balanced panel
  iplot(.,
        xlab = paste("Time to treatment (Year; 0 = ", base_year, ")", sep = ""),
        main = paste("Treatment Effects by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Balanced Panel",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE,
        xlim = c(period_start - n_pre - base_year - 0.5, period_end - base_year + 0.5)
        ); axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5)); abline(v = 0.5, col = "red", lty = 2, lwd = 3); legend('topleft', bty = "n", col = c(1, 2, 3, 4), pch = c(20, 17, 15, 21), legend = c('intensity', 'intensity + controls', 'dummy', 'dummy + controls'));

Show the code
#### intensity only: 
fml_results[which(unlist(fml_parameters$balanced_panel))][1:2] %>% # choose the balanced panel
  iplot(.,
        xlab = paste("Time to treatment (Year; 0 = ", base_year, ")", sep = ""),
        main = paste("Treatment Effects by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Balanced Panel",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE,
        xlim = c(period_start - n_pre - base_year - 0.5, period_end - base_year + 0.5)
        ); axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5)); abline(v = 0.5, col = "red", lty = 2, lwd = 3); legend('bottomleft', bty = "n", col = c(1, 2, 3, 4), pch = c(20, 17, 15, 21), legend = c('intensity', 'intensity + controls', 'dummy', 'dummy + controls')[1:2]);

Show the code
fml_results[which(!unlist(fml_parameters$balanced_panel))] %>% # choose full sample
  iplot(.,
        xlab = paste("Time to treatment (Year; 0 = ", base_year, ")", sep = ""),
        main = paste("Treatment Effect by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Full Sample",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE,
        xlim = c(period_start - n_pre - base_year - 0.5, period_end - base_year + 0.5)
        ); axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5)); abline(v = 0.5, col = "red", lty = 2, lwd = 3); legend('bottomleft', bty = "n", col = c(1, 2, 3, 4), pch = c(20, 17, 15, 21), legend = c('intensity', 'intensity + controls', 'dummy', 'dummy + controls'))

s3.3. land intensity

land_intensity is chosen to measure a firm’s long-term exposure to land and improvements at cost under the PPE.

Show the code
## choose the group definition:
intensity_measure_name <- candidate_intensity_measure[4]

data_firm <- data %>%
  filter(fyear == intensity_measure_year) %>% # use `fyear` may create multiple observations for the same firm. E.g. filter(gvkey == 23535, dyear == 2005)
  group_by(fyear) %>%
  mutate(median_at = median(at, na.rm = TRUE)) %>%
  ungroup() %>%
  mutate(large = ifelse(at > median_at, 1, 0)) %>%
  select(gvkey, intensity_2000 = all_of(intensity_measure_name), large)

data_did <- data %>%
  ## merge the grouping variable
  left_join(y = data_firm, by = join_by(gvkey) ) %>%
  ## merge the FF 30 industry classification
  left_join(y = FF_30ind, by = join_by(sic)) %>%
  ## exclude certain industries
  filter(
    ff_30ind != 20, # exclude Utiltiy (number 20)
    !(sic >= 6000 & sic <= 6199) # exclude banks under Banking, Insurance, Real Estate, Trading (number 29)
  ) %>%
  ## pre- & post-
  mutate(
    indexyear = (fyear - base_year), # year index with 2005 as base 0.
    post_2005 = as.numeric(fyear > base_year)  # whether it is after the 2005 reform
  )

## gvkey(s) for balanced panel":
data_did_balanced_id <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>% 
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  group_by(gvkey) %>%
  summarise(count_obs = sum(!is.na(book_leverage) & !is.na(intensity_2000))) %>%
  ungroup() %>%
  filter(count_obs == period_end - period_start + 1 + n_pre) %>%
  .$gvkey

DiD Analysis:

Show the code
cat(intensity_measure_name); cat(": \n");

## create the combinations of parameters:
fml_parameters <- expand_grid(
  choice_treatment = c("intensity_2000", "treated"), # what is the treatment measure: continuous/binary
  controls_inclusion = c(FALSE, TRUE),# whether to include controls
  balanced_panel = c(FALSE, TRUE), # whether keep a balanced panel
) %>%
  arrange(balanced_panel) %>%
  cbind.data.frame(.,
    fml = apply(X = ., MARGIN = 1, FUN = function(parameters) {
      ## parameters: 
      choice_treatment <- parameters[1] 
      add_controls <- parameters[2] 
      is_balanced <- parameters[3] 
      
      ## inputs: 
      fml_base <- paste("debt_ebitda ~ post_2005*", choice_treatment, sep = "") # the baseline model
      fml_base_controls <- " + roa + altman_Z + tangibility + current_ratio " # the potential controls
      fml_base_fe <- " | gvkey + indexyear + ff_30ind_name^indexyear" # fixed effects

      ## output formula:
      fml_output <- paste(
        fml_base,
        ifelse(add_controls == TRUE,  yes = fml_base_controls,  no = ifelse(add_controls == "Full", yes = fml_base_controls_full, no = "") ),
        fml_base_fe,
        sep = ""
      )

      return(fml_output)
    })
  ) %>%
  as_tibble() %>%
  ## assign a name for each regression:
  mutate(name = paste("(", 1:nrow(.), ")", sep = "")) %>%
  select(name, everything())

## construct the data used for the loop:
data_did_loop <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name,
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

data_did_loop_balanced <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name,
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

## store all results
fml_results <- fml_parameters %>%
  apply(MARGIN = 1, FUN = function(parameters) {
    ## parameters:
    is_balanced <- parameters[4]
    fml_formula <- parameters[5]

    ## data:
    if (is_balanced == TRUE) {
      data <- data_did_loop_balanced
    } else {
      data <- data_did_loop
    }

    ## regression:
    did_model <- fixest::feols(fml = formula(fml_formula),
                  data = data,
                  cluster = c("gvkey", "ff_30ind_name")
                  )
    return(did_model)
  })

### DiD result using post-:
fml_results %>%
  `names<-`(value = unlist(fml_parameters[,1])) %>%
  etable(
    order = "post",
    # keep = "post",
    extralines = list(
      ## Controls:
      "^_Controls" = ifelse(unlist(fml_parameters[,3]), yes = "Yes", no = "No"),
      ## the identity of the sample:
      "__Sample" = ifelse(unlist(fml_parameters[,4]), yes = "Balanced Panel", no = "Full Sample") # whether used a balanced panel or a full sample.
  )) %>%
  knitr::kable(format = "html", caption = paste("DiD Results with `", intensity_measure_name, "`", sep = "")) %>%
  kableExtra::kable_styling(
    font_size = 8,       # Smaller font (default is 16px)
    full_width = FALSE,   # Table width fits content
    bootstrap_options = c("striped", "condensed")
  )
land_intensity: 
DiD Results with `land_intensity`
(1) (2) (3) (4) (5) (6) (7) (8)
Dependent Var.: debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda
post_2005 x intensity_2000 -0.4074 (0.4067) -1.456* (0.5774) -0.1674 (0.3138) -0.9508 (0.8105)
post_2005 x treated -0.1509. (0.0807) -0.0824 (0.0865) -0.1369. (0.0675) -0.0780 (0.0708)
roa 0.0002 (0.0002) 0.0002 (0.0002) -0.0422. (0.0248) -0.0425. (0.0248)
altman_Z -9.52e-6*** (2.43e-6) -9.52e-6*** (2.34e-6) -9.55e-6*** (2.57e-6) -9.5e-6*** (2.54e-6)
tangibility 1.173* (0.4586) 1.172* (0.4559) 0.2579 (0.4310) 0.2603 (0.4329)
current_ratio -0.0005** (0.0002) -0.0005** (0.0002) -0.0001. (8.41e-5) -0.0002 (9.33e-5)
Controls No Yes No Yes No Yes No Yes
Fixed-Effects: ---------------- --------------------- ----------------- --------------------- ---------------- --------------------- ----------------- --------------------
gvkey Yes Yes Yes Yes Yes Yes Yes Yes
indexyear Yes Yes Yes Yes Yes Yes Yes Yes
ff_30ind_name-indexyear Yes Yes Yes Yes Yes Yes Yes Yes
__________________________ ________________ _____________________ _________________ _____________________ ________________ _____________________ _________________ ____________________
S.E.: Clustered by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3.
Observations 21,244 19,166 21,244 19,166 11,520 10,551 11,520 10,551
R2 0.74889 0.72219 0.74902 0.72213 0.73154 0.71481 0.73172 0.71480
Within R2 7.05e-5 0.00393 0.00057 0.00372 2.49e-5 0.00334 0.00070 0.00333
Sample Full Sample Full Sample Full Sample Full Sample Balanced Panel Balanced Panel Balanced Panel Balanced Panel

From the table results using land_intensity, the treatment effect is indifferent from zero if using the intensity measure and the it is significantly negative if we use the treatment dummy, which is one if the intensity is positive and zero otherwise.

DiD plot:

Show the code
## create the combinations of parameters:
fml_parameters <- expand_grid(
  choice_treatment = c("intensity_2000", "treated"), # what is the treatment measure: continuous/binary
  controls_inclusion = c(FALSE, TRUE),# whether to include controls
  balanced_panel = c(FALSE, TRUE), # whether keep a balanced panel
) %>%
  arrange(balanced_panel) %>%
  cbind.data.frame(.,
    fml = apply(X = ., MARGIN = 1, FUN = function(parameters) {
      ## parameters:
      choice_treatment <- parameters[1]
      add_controls <- parameters[2]
      is_balanced <- parameters[3]

      ## inputs:
      fml_base <- paste("debt_ebitda ~ i(indexyear, ", choice_treatment, ", ref = -1)", sep = "") # the baseline model
      fml_base_controls <- " + roa + altman_Z + tangibility + current_ratio " # the potential controls
      fml_base_fe <- " | gvkey + indexyear + ff_30ind_name^indexyear" # fixed effects

      ## output formula:
      fml_output <- paste(
        fml_base,
        ifelse(add_controls == TRUE,  yes = fml_base_controls,  no = ifelse(add_controls == "Full", yes = fml_base_controls_full, no = "") ),
        fml_base_fe,
        sep = ""
      )

      return(fml_output)
    })
  ) %>%
  as_tibble() %>%
  ## assign a name for each regression:
  mutate(name = paste("(", letters[1:nrow(.)], ")", sep = "")) %>%
  select(name, everything())

fml_parameters
# A tibble: 8 × 5
  name  choice_treatment controls_inclusion balanced_panel fml                  
  <chr> <chr>            <lgl>              <lgl>          <chr>                
1 (a)   intensity_2000   FALSE              FALSE          debt_ebitda ~ i(inde…
2 (b)   intensity_2000   TRUE               FALSE          debt_ebitda ~ i(inde…
3 (c)   treated          FALSE              FALSE          debt_ebitda ~ i(inde…
4 (d)   treated          TRUE               FALSE          debt_ebitda ~ i(inde…
5 (e)   intensity_2000   FALSE              TRUE           debt_ebitda ~ i(inde…
6 (f)   intensity_2000   TRUE               TRUE           debt_ebitda ~ i(inde…
7 (g)   treated          FALSE              TRUE           debt_ebitda ~ i(inde…
8 (h)   treated          TRUE               TRUE           debt_ebitda ~ i(inde…
Show the code
## construct the data used for the loop:
data_did_loop <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name,
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

data_did_loop_balanced <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name,
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

## store all results
fml_results <- fml_parameters %>%
  apply(MARGIN = 1, FUN = function(parameters) {
    ## parameters:
    is_balanced <- parameters[4]
    fml_formula <- parameters[5]

    ## data:
    if (is_balanced == TRUE) {
      data <- data_did_loop_balanced
    } else {
      data <- data_did_loop
    }

    ## regression:
    did_model <- fixest::feols(fml = formula(fml_formula),
                  data = data,
                  cluster = c("gvkey", "ff_30ind_name")
                  )
    return(did_model)
  })
NOTE: 2,709 observations removed because of NA and infinite values (RHS: 2,709).
NOTE: 2,709 observations removed because of NA and infinite values (RHS: 2,709).
NOTE: 1,188 observations removed because of NA and infinite values (RHS: 1,188).
NOTE: 1,188 observations removed because of NA and infinite values (RHS: 1,188).
Show the code
### create the table:
fml_results %>%
  `names<-`(value = unlist(fml_parameters[,1])) %>%
  etable(
    order = "indexyear",
    # keep = "post",
    extralines = list(
      ## Controls:
      "^_Controls" = ifelse(unlist(fml_parameters[,3]), yes = "Yes", no = "No"),
      ## the identity of the sample:
      "__Sample" = ifelse(unlist(fml_parameters[,4]), yes = "Balanced Panel", no = "Full Sample") # whether used a balanced panel or a full sample.
  )) %>%
  knitr::kable(format = "html", caption = paste("DiD Results with `", intensity_measure_name, "`", sep = "")) %>%
  kableExtra::kable_styling(
    font_size = 8,       # Smaller font (default is 16px)
    full_width = FALSE,   # Table width fits content
    bootstrap_options = c("striped", "condensed")
  )
DiD Results with `land_intensity`
(a) (b) (c) (d) (e) (f) (g) (h)
Dependent Var.: debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda
intensity_2000 x indexyear = -3 -0.1954 (0.5236) -1.749 (1.151) -0.2330 (0.3017) -1.147 (0.7594)
intensity_2000 x indexyear = -2 0.1131 (0.4038) -0.2079 (0.7791) 0.0054 (0.1912) -0.1092 (0.6892)
intensity_2000 x indexyear = 0 0.1190 (0.3546) -0.5002 (0.7489) 0.1213 (0.2556) 0.2970 (0.9139)
intensity_2000 x indexyear = 1 -0.8792** (0.3108) -1.845. (0.9207) -0.2506 (0.4077) -0.1466 (1.189)
intensity_2000 x indexyear = 2 -0.0717 (0.4670) -1.106 (0.9582) 0.2293 (0.4936) -0.2942 (1.269)
intensity_2000 x indexyear = 3 -0.5350 (0.8501) -3.662** (1.310) -0.3542 (0.4954) -2.009. (1.127)
treated x indexyear = -3 0.2467** (0.0833) 0.1898* (0.0851) 0.2062* (0.0772) 0.1789* (0.0780)
treated x indexyear = -2 0.0655 (0.0686) -0.0057 (0.0741) 0.0647 (0.0666) 0.0338 (0.0736)
treated x indexyear = 0 -0.1303. (0.0636) -0.1329. (0.0724) -0.1823* (0.0732) -0.1846* (0.0795)
treated x indexyear = 1 -0.2276* (0.0877) -0.2090* (0.0934) -0.1442 (0.0866) -0.1135 (0.0902)
treated x indexyear = 2 -0.2139* (0.0968) -0.1454 (0.1041) -0.1984* (0.0854) -0.1313 (0.0875)
treated x indexyear = 3 -0.1767 (0.1242) -0.1285 (0.1316) -0.1855. (0.0994) -0.1400 (0.1027)
roa 0.0002 (0.0002) 0.0002 (0.0002) -0.0294 (0.0207) -0.0301 (0.0207)
altman_Z -1.04e-5** (3.05e-6) -9.95e-6** (2.89e-6) -9.48e-6** (2.82e-6) -8.86e-6** (2.71e-6)
tangibility 1.301** (0.3846) 1.258** (0.3844) 0.5636 (0.3748) 0.4903 (0.3819)
current_ratio -0.0006* (0.0002) -0.0006** (0.0002) -0.0002 (0.0001) -0.0002. (0.0001)
Controls No Yes No Yes No Yes No Yes
Fixed-Effects: ------------------ -------------------- ----------------- -------------------- ---------------- -------------------- ----------------- --------------------
gvkey Yes Yes Yes Yes Yes Yes Yes Yes
indexyear Yes Yes Yes Yes Yes Yes Yes Yes
ff_30ind_name-indexyear Yes Yes Yes Yes Yes Yes Yes Yes
_______________________________ __________________ ____________________ _________________ ____________________ ________________ ____________________ _________________ ____________________
S.E.: Clustered by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3.
Observations 25,533 22,824 25,533 22,824 13,440 12,252 13,440 12,252
R2 0.72613 0.70240 0.72672 0.70256 0.70160 0.68601 0.70236 0.68641
Within R2 0.00018 0.00532 0.00235 0.00586 0.00012 0.00380 0.00267 0.00507
Sample Full Sample Full Sample Full Sample Full Sample Balanced Panel Balanced Panel Balanced Panel Balanced Panel
Show the code
### create the plots:
# fml_parameters[which(unlist(fml_parameters$balanced_panel)), ]
fml_results[which(unlist(fml_parameters$balanced_panel))] %>% # choose the balanced panel
  iplot(.,
        xlab = paste("Time to treatment (Year; 0 = ", base_year, ")", sep = ""),
        main = paste("Treatment Effects by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Balanced Panel",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE,
        xlim = c(period_start - n_pre - base_year - 0.5, period_end - base_year + 0.5)
        ); axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5)); abline(v = 0.5, col = "red", lty = 2, lwd = 3); legend('bottomleft', bty = "n", col = c(1, 2, 3, 4), pch = c(20, 17, 15, 21), legend = c('intensity', 'intensity + controls', 'dummy', 'dummy + controls'));

Show the code
fml_results[which(!unlist(fml_parameters$balanced_panel))] %>% # choose full sample
  iplot(.,
        xlab = paste("Time to treatment (Year; 0 = ", base_year, ")", sep = ""),
        main = paste("Treatment Effect by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Full Sample",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE,
        xlim = c(period_start - n_pre - base_year - 0.5, period_end - base_year + 0.5)
        ); axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5)); abline(v = 0.5, col = "red", lty = 2, lwd = 3); legend('bottomleft', bty = "n", col = c(1, 2, 3, 4), pch = c(20, 17, 15, 21), legend = c('intensity', 'intensity + controls', 'dummy', 'dummy + controls'))

Results using land_intensity are much noisier. The treatment effects are indifferent from zero when using the intensity measure and are negative when using the treatment dummy. However, there seems to be a pre-trend before the time of treatment. This is further shown in the plots.

s3.4. builindg and land intensity

bnl_intensity is chosen to measure a firm’s long-term exposure to buildings, land and their improvements at cost under the PPE.

Show the code
## choose the group definition:
intensity_measure_name <- candidate_intensity_measure[5]

data_firm <- data %>%
  filter(fyear == intensity_measure_year) %>% # use `fyear` may create multiple observations for the same firm. E.g. filter(gvkey == 23535, dyear == 2005)
  group_by(fyear) %>%
  mutate(
    median_at = median(at, na.rm = TRUE),
    # median_cf = median(debt_ebitda, na.rm = TRUE)
    ) %>%
  ungroup() %>%
  ## different grouping variables in DDD analysis:
  mutate(
    large = ifelse(at > median_at, 1, 0),
    # tangible = ifelse(tangibility > 0, yes = "tangible", no = "non-tangible"),
    # high_cf = ifelse(debt_ebitda < median_cf, yes = "high CF", no = "low CF")
  ) %>%
  select(gvkey, intensity_2000 = all_of(intensity_measure_name), large)

data_did <- data %>%
  ## merge the grouping variable
  left_join(y = data_firm, by = join_by(gvkey) ) %>%
  ## merge the FF 30 industry classification
  left_join(y = FF_30ind, by = join_by(sic)) %>%
  ## exclude certain industries
  filter(
    ff_30ind != 20, # exclude Utiltiy (number 20)
    !(sic >= 6000 & sic <= 6199) # exclude banks under Banking, Insurance, Real Estate, Trading (number 29)
  ) %>%
  ## pre- & post-
  mutate(
    indexyear = (fyear - base_year), # year index with 2005 as base 0.
    post_2005 = as.numeric(fyear > base_year)  # whether it is after the 2005 reform
  )

## gvkey(s) for balanced panel":
data_did_balanced_id <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  group_by(gvkey) %>%
  summarise(count_obs = sum(!is.na(book_leverage) & !is.na(intensity_2000))) %>%
  ungroup() %>%
  filter(count_obs == period_end - period_start + 1 + n_pre) %>%
  .$gvkey

data_intensity_panel <- data %>%
  filter(fyear < 2007) %>%
  select(gvkey, fyear, all_of(intensity_measure_name)) %>%
  pivot_wider(names_from = fyear, values_from = all_of(intensity_measure_name))

DiD Analysis:

In this part of the analysis, I also added the firm-year controls in the DiD and triple difference analyses. The first is called àt_thousand, which is the total asset of firm i in fiscal year t in thousand of dollars. The second is the ebitda_at, which is the EBITDA of firm i in fiscal year t divided by its total asset. Adding both controls positively correlated with the book leverage, they do not have a significant impact on the coefficient estimate of interest, which is the coefficient on treated x post_2005 and intensity_2000 x post_2005.

Show the code
cat(intensity_measure_name); cat(": \n");

## create the combinations of parameters:
fml_parameters <- expand_grid(
  choice_treatment = c("intensity_2000", "treated"), # what is the treatment measure: continuous/binary
  controls_inclusion = c(FALSE, TRUE),# whether to include controls
  balanced_panel = c(FALSE, TRUE), # whether keep a balanced panel
) %>%
  arrange(balanced_panel) %>%
  cbind.data.frame(.,
    fml = apply(X = ., MARGIN = 1, FUN = function(parameters) {
      ## parameters:
      choice_treatment <- parameters[1]
      add_controls <- parameters[2]
      is_balanced <- parameters[3]

      ## inputs:
      fml_base <- paste("debt_ebitda ~ post_2005*", choice_treatment, sep = "") # the baseline model
      fml_base_controls <- " + roa + altman_Z + tangibility + current_ratio " # the potential controls
      fml_base_fe <- " | gvkey + indexyear + ff_30ind_name^indexyear" # fixed effects

      ## output formula:
      fml_output <- paste(
        fml_base,
        ifelse(add_controls == TRUE,  yes = fml_base_controls,  no = ifelse(add_controls == "Full", yes = fml_base_controls_full, no = "") ),
        fml_base_fe,
        sep = ""
      )

      return(fml_output)
    })
  ) %>%
  as_tibble() %>%
  ## assign a name for each regression:
  mutate(name = paste("(", 1:nrow(.), ")", sep = "")) %>%
  select(name, everything())

## construct the data used for the loop:
data_did_loop <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name,
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

data_did_loop_balanced <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name,
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

## store all results
fml_results <- fml_parameters %>%
  apply(MARGIN = 1, FUN = function(parameters) {
    ## parameters:
    is_balanced <- parameters[4]
    fml_formula <- parameters[5]

    ## data:
    if (is_balanced == TRUE) {
      data <- data_did_loop_balanced
    } else {
      data <- data_did_loop
    }

    ## regression:
    did_model <- fixest::feols(fml = formula(fml_formula),
                  data = data,
                  cluster = c("gvkey", "ff_30ind_name")
                  )
    return(did_model)
  })

### DiD result using post-:
fml_results %>%
  `names<-`(value = unlist(fml_parameters[,1])) %>%
  etable(
    order = "post",
    # keep = "post",
    extralines = list(
      ## Controls:
      "^_Controls" = ifelse(unlist(fml_parameters[,3]), yes = "Yes", no = "No"),
      ## the identity of the sample:
      "__Sample" = ifelse(unlist(fml_parameters[,4]), yes = "Balanced Panel", no = "Full Sample") # whether used a balanced panel or a full sample.
  )) %>%
  knitr::kable(format = "html", caption = paste("DiD Results with `", intensity_measure_name, "`", sep = "")) %>%
  kableExtra::kable_styling(
    font_size = 8,       # Smaller font (default is 16px)
    full_width = FALSE,   # Table width fits content
    bootstrap_options = c("striped", "condensed")
  ) %>%
  kableExtra::footnote(
    general = "Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1",
    general_title = "Note:"
  )
bnl_intensity: 
DiD Results with `bnl_intensity`
(1) (2) (3) (4) (5) (6) (7) (8)
Dependent Var.: debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda
post_2005 x intensity_2000 -0.3869* (0.1887) -0.3370 (0.2296) -0.4427. (0.2221) -0.4874. (0.2387)
post_2005 x treated -0.1532. (0.0780) -0.0915 (0.0840) -0.1715** (0.0604) -0.1223. (0.0627)
roa 0.0002 (0.0002) 0.0002 (0.0002) -0.0415 (0.0249) -0.0424. (0.0249)
altman_Z -9.58e-6*** (2.38e-6) -9.5e-6*** (2.34e-6) -9.41e-6*** (2.53e-6) -9.35e-6*** (2.5e-6)
tangibility 1.145* (0.4614) 1.163* (0.4625) 0.1803 (0.4420) 0.2376 (0.4341)
current_ratio -0.0005** (0.0002) -0.0005** (0.0002) -0.0002 (9.4e-5) -0.0002 (0.0001)
Controls No Yes No Yes No Yes No Yes
Fixed-Effects: ----------------- --------------------- ----------------- -------------------- ----------------- --------------------- ------------------ --------------------
gvkey Yes Yes Yes Yes Yes Yes Yes Yes
indexyear Yes Yes Yes Yes Yes Yes Yes Yes
ff_30ind_name-indexyear Yes Yes Yes Yes Yes Yes Yes Yes
__________________________ _________________ _____________________ _________________ ____________________ _________________ _____________________ __________________ ____________________
S.E.: Clustered by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3.
Observations 21,155 19,100 21,155 19,100 11,454 10,503 11,454 10,503
R2 0.74844 0.72221 0.74846 0.72218 0.73132 0.71522 0.73132 0.71508
Within R2 0.00046 0.00382 0.00057 0.00372 0.00098 0.00409 0.00102 0.00361
Sample Full Sample Full Sample Full Sample Full Sample Balanced Panel Balanced Panel Balanced Panel Balanced Panel
Note:
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

DiD analysis:

Show the code
## create the combinations of parameters:
fml_parameters <- expand_grid(
  choice_treatment = c("intensity_2000", "treated"), # what is the treatment measure: continuous/binary
  controls_inclusion = c(FALSE, TRUE),# whether to include controls
  balanced_panel = c(FALSE, TRUE), # whether keep a balanced panel
) %>%
  arrange(balanced_panel) %>% 
  cbind.data.frame(.,
    fml = apply(X = ., MARGIN = 1, FUN = function(parameters) {
      ## parameters:
      choice_treatment <- parameters[1]
      add_controls <- parameters[2]
      is_balanced <- parameters[3]

      ## inputs:
      fml_base <- paste("debt_ebitda ~ i(indexyear, ", choice_treatment, ", ref = -1)", sep = "") # the baseline model
      fml_base_controls <- " + roa + altman_Z + tangibility + current_ratio " # the potential controls
      fml_base_fe <- " | gvkey + indexyear + ff_30ind_name^indexyear" # fixed effects

      ## output formula:
      fml_output <- paste(
        fml_base,
        ifelse(add_controls == TRUE,  yes = fml_base_controls,  no = ifelse(add_controls == "Full", yes = fml_base_controls_full, no = "") ),
        fml_base_fe,
        sep = ""
      )

      return(fml_output)
    })
  ) %>%
  as_tibble() %>%
  ## assign a name for each regression:
  mutate(name = paste("(", letters[1:nrow(.)], ")", sep = "")) %>%
  select(name, everything())

fml_parameters
# A tibble: 8 × 5
  name  choice_treatment controls_inclusion balanced_panel fml                  
  <chr> <chr>            <lgl>              <lgl>          <chr>                
1 (a)   intensity_2000   FALSE              FALSE          debt_ebitda ~ i(inde…
2 (b)   intensity_2000   TRUE               FALSE          debt_ebitda ~ i(inde…
3 (c)   treated          FALSE              FALSE          debt_ebitda ~ i(inde…
4 (d)   treated          TRUE               FALSE          debt_ebitda ~ i(inde…
5 (e)   intensity_2000   FALSE              TRUE           debt_ebitda ~ i(inde…
6 (f)   intensity_2000   TRUE               TRUE           debt_ebitda ~ i(inde…
7 (g)   treated          FALSE              TRUE           debt_ebitda ~ i(inde…
8 (h)   treated          TRUE               TRUE           debt_ebitda ~ i(inde…
Show the code
## construct the data used for the loop:
data_did_loop <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0) %>%
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name,
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    large = ifelse(large, yes = "Large", no = "Small"),
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    # large = ifelse(large, yes = 1, no = 0),
    treated_large = paste(treated, large, sep = "_")
  )

data_did_loop_balanced <- data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0) %>%
  filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005,
         book_leverage, debt_ebitda, sic, ff_30ind_name,
         at, at_thousand_lag1, ebitda, large, roa, ppent, bnl_intensity, ppe_lease_intensity,
         altman_Z, kz, market_book, tangibility, current_ratio) %>%
  filter(fyear >= period_start - n_pre & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
    gvkey = as.factor(gvkey),
    fyear = as.factor(fyear),
    # treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
    treated = ifelse(intensity_2000 > 0, 1, 0),
    ebitda_at = ebitda / at,
    at_thousand = at * 10^-3,
    tangiblity_exbnl = tangibility - bnl_intensity,
    bnl = bnl_intensity * at,
    treated_large = paste(treated, large, sep = "_"),
    ## grouping variables
    large = ifelse(large, yes = "Large", no = "Small")
  )

## store all results
fml_results <- fml_parameters %>%
  apply(MARGIN = 1, FUN = function(parameters) {
    ## parameters:
    is_balanced <- parameters[4]
    fml_formula <- parameters[5]

    ## data:
    if (is_balanced == TRUE) {
      data <- data_did_loop_balanced
    } else {
      data <- data_did_loop
    }

    ## regression:
    did_model <- fixest::feols(fml = formula(fml_formula),
                  data = data,
                  cluster = c("gvkey", "ff_30ind_name")
                  )
    return(did_model)
  })
NOTE: 2,861 observations removed because of NA and infinite values (RHS: 2,861).
NOTE: 2,861 observations removed because of NA and infinite values (RHS: 2,861).
NOTE: 1,167 observations removed because of NA and infinite values (RHS: 1,167).
NOTE: 1,167 observations removed because of NA and infinite values (RHS: 1,167).
Show the code
### create the table:
fml_results %>%
  `names<-`(value = unlist(fml_parameters[,1])) %>%
  etable(
    order = "indexyear",
    # keep = "post",
    extralines = list(
      ## Controls:
      "^_Controls" = ifelse(unlist(fml_parameters[,3]), yes = "Yes", no = "No"),
      ## the identity of the sample:
      "__Sample" = ifelse(unlist(fml_parameters[,4]), yes = "Balanced Panel", no = "Full Sample") # whether used a balanced panel or a full sample.
  )) %>%
  knitr::kable(format = "html", caption = paste("DiD Results with `", intensity_measure_name, "`", sep = "")) %>%
  kableExtra::kable_styling(
    font_size = 8,       # Smaller font (default is 16px)
    full_width = FALSE,   # Table width fits content
    bootstrap_options = c("striped", "condensed")
  )
DiD Results with `bnl_intensity`
(a) (b) (c) (d) (e) (f) (g) (h)
Dependent Var.: debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda debt_ebitda
intensity_2000 x indexyear = -3 -0.0040 (0.2547) -0.0216 (0.2322) -0.2140 (0.3896) -0.3109 (0.5016)
intensity_2000 x indexyear = -2 0.0393 (0.1798) -5.43e-5 (0.1660) -0.0406 (0.3341) -0.0982 (0.4204)
intensity_2000 x indexyear = 0 -0.3854* (0.1879) -0.2821 (0.2386) -0.5031* (0.1968) -0.5654** (0.1935)
intensity_2000 x indexyear = 1 -0.5936* (0.2375) -0.4510 (0.2809) -0.6531* (0.2633) -0.5875* (0.2841)
intensity_2000 x indexyear = 2 -0.5198. (0.2555) -0.3264 (0.3176) -0.5568* (0.2565) -0.6774* (0.2605)
intensity_2000 x indexyear = 3 -0.4692. (0.2629) -0.7461. (0.3992) -0.6620. (0.3245) -0.7632* (0.2873)
treated x indexyear = -3 0.2566*** (0.0669) 0.2446** (0.0756) 0.1538* (0.0735) 0.1576* (0.0761)
treated x indexyear = -2 0.0982. (0.0538) 0.0446 (0.0620) 0.0583 (0.0684) 0.0376 (0.0765)
treated x indexyear = 0 -0.1482* (0.0723) -0.1393 (0.0835) -0.1769* (0.0725) -0.1747* (0.0772)
treated x indexyear = 1 -0.2154* (0.0943) -0.1883. (0.1003) -0.1723* (0.0830) -0.1371 (0.0883)
treated x indexyear = 2 -0.1923* (0.0872) -0.1181 (0.0954) -0.2272** (0.0709) -0.1583* (0.0717)
treated x indexyear = 3 -0.1421 (0.1407) -0.1127 (0.1470) -0.2335* (0.0988) -0.2057* (0.0947)
roa 0.0002 (0.0002) 0.0002 (0.0002) -0.0289 (0.0208) -0.0295 (0.0207)
altman_Z -1.1e-5** (3.03e-6) -1.06e-5** (2.96e-6) -9.16e-6** (2.78e-6) -8.75e-6** (2.68e-6)
tangibility 1.182** (0.3949) 1.174** (0.3951) 0.4703 (0.3951) 0.4744 (0.3897)
current_ratio -0.0006* (0.0002) -0.0006* (0.0002) -0.0002 (0.0001) -0.0002. (0.0001)
Controls No Yes No Yes No Yes No Yes
Fixed-Effects: ----------------- ------------------- ------------------ -------------------- ----------------- -------------------- ------------------ --------------------
gvkey Yes Yes Yes Yes Yes Yes Yes Yes
indexyear Yes Yes Yes Yes Yes Yes Yes Yes
ff_30ind_name-indexyear Yes Yes Yes Yes Yes Yes Yes Yes
_______________________________ _________________ ___________________ __________________ ____________________ _________________ ____________________ __________________ ____________________
S.E.: Clustered by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3. by: gvkey & ff_3.
Observations 25,786 22,925 25,786 22,925 13,363 12,196 13,363 12,196
R2 0.73381 0.70844 0.73421 0.70876 0.70140 0.68625 0.70176 0.68649
Within R2 0.00073 0.00479 0.00224 0.00588 0.00119 0.00435 0.00242 0.00510
Sample Full Sample Full Sample Full Sample Full Sample Balanced Panel Balanced Panel Balanced Panel Balanced Panel
Show the code
### create the plots:
# fml_parameters[which(unlist(fml_parameters$balanced_panel)), ]
fml_results[which(unlist(fml_parameters$balanced_panel))] %>% # choose the balanced panel
  iplot(.,
        xlab = paste("Time to treatment (Year; 0 = ", base_year, ")", sep = ""),
        main = paste("Treatment Effects by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Balanced Panel",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE,
        xlim = c(period_start - n_pre - base_year - 0.5, period_end - base_year + 0.5)
        ); axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5)); abline(v = 0.5, col = "red", lty = 2, lwd = 3); legend('bottomleft', bty = "n", col = c(1, 2, 3, 4), pch = c(20, 17, 15, 21), legend = c('intensity', 'intensity + controls', 'dummy', 'dummy + controls'));

Show the code
fml_results[which(!unlist(fml_parameters$balanced_panel))] %>% # choose full sample
  iplot(.,
        xlab = paste("Time to treatment (Year; 0 = ", base_year, ")", sep = ""),
        main = paste("Treatment Effect by fiscal year: `", intensity_measure_name, "`", sep = ""),
        sub = "Data: Full Sample",
        ref.line = FALSE,
        ref.line.par = list(col = "red", lty = 2),
        pt.join = FALSE,
        xlim = c(period_start - n_pre - base_year - 0.5, period_end - base_year + 0.5)
        ); axis(1, at = (period_start - n_pre - base_year):(period_end - base_year + 0.5)); abline(v = 0.5, col = "red", lty = 2, lwd = 3); legend('bottomleft', bty = "n", col = c(1, 2, 3, 4), pch = c(20, 17, 15, 21), legend = c('intensity', 'intensity + controls', 'dummy', 'dummy + controls'))

Check the trend of movement in the intensity measure:

Show the code
### Observation summary:
cat("#### Number of Observations in Each Group over time (Full Sample): \n")
#### Number of Observations in Each Group over time (Full Sample): 
Show the code
data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  # filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005, book_leverage, debt_ebitda, sic, ff_30ind_name, at, ebitda, large, roa) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
  gvkey = as.factor(gvkey),
  fyear = as.factor(fyear),
  treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
  # treated = ifelse(intensity_2000 > 0, 1, 0),
  ebitda_at = ebitda / at,
  at_thousand = at * 10^-3,
  large = factor(ifelse(large, yes = "Large", no = "Small"), levels = c("Large", "Small") ),
  # large = ifelse(large, yes = 1, no = 0),
  treated_large = paste(treated, large, sep = "_")
  ) %>%
  group_by(treated_large, fyear) %>%
  summarise(n = n()) %>%
  ungroup() %>%
  # mutate(
  #   Treated = str_extract(string = treated_large, pattern = "^[^_]+"),
  #   Size = str_extract(string = treated_large, pattern = "[^_]+$")
  #   ) %>%
  pivot_wider(names_from = treated_large, values_from = n) %>%
  gt(caption = "Number of Observations in each group between 2002 and 2007") %>%
  tab_style(
    style = cell_text(size = "x-small"),  # Reduce font size
    locations = cells_column_labels(columns = everything()) # reduce the size of tab headers
  ) %>%
  tab_style(
    style = cell_text(size = "x-small"),  # Reduce font size
    locations = cells_body()
  )
Number of Observations in each group between 2002 and 2007
fyear Treated_Large Treated_Small Untreated_Large Untreated_Small
2002 1739 710 353 1249
2003 1663 661 351 1177
2004 1623 648 337 1147
2005 1511 584 305 1047
2006 1412 544 281 933
2007 1289 488 250 853
Show the code
cat("#### Number of Observations in Each Group over time (Balanced Panel): \n")
#### Number of Observations in Each Group over time (Balanced Panel): 
Show the code
data_did %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(gvkey %in% data_did_balanced_id) %>%
  # filter(intensity_2000 > 0) %>%
  select(gvkey, fyear, indexyear, intensity_2000, post_2005, book_leverage, debt_ebitda, sic, ff_30ind_name, at, ebitda, large, roa) %>%
  filter(fyear >= period_start & fyear <= period_end) %>%
  filter(!is.na(intensity_2000) & !is.na(at)) %>%
  mutate(
  gvkey = as.factor(gvkey),
  fyear = as.factor(fyear),
  treated = ifelse(intensity_2000 > 0, "Treated", "Untreated"),
  # treated = ifelse(intensity_2000 > 0, 1, 0),
  ebitda_at = ebitda / at,
  at_thousand = at * 10^-3,
  large = factor(ifelse(large, yes = "Large", no = "Small"), levels = c("Large", "Small") ),
  # large = ifelse(large, yes = 1, no = 0),
  treated_large = paste(treated, large, sep = "_")
  ) %>%
  group_by(treated_large, fyear) %>%
  summarise(n = n()) %>%
  ungroup() %>%
  pivot_wider(names_from = treated_large, values_from = n) %>%
  gt(caption = "Number of Observations in each group between 2002 and 2007") %>%
  tab_style(
    style = cell_text(size = "x-small"),  # Reduce font size
    locations = cells_column_labels(columns = everything()) # reduce the size of tab headers
  ) %>%
  tab_style(
    style = cell_text(size = "x-small"),  # Reduce font size
    locations = cells_body()
  )
Number of Observations in each group between 2002 and 2007
fyear Treated_Large Treated_Small Untreated_Large Untreated_Small
2002 1077 315 159 358
2003 1077 315 159 358
2004 1077 315 159 358
2005 1077 315 159 358
2006 1077 315 159 358
2007 1077 315 159 358
Show the code
cat("`bnl_intensity`: \n")
`bnl_intensity`: 
Show the code
data %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(fyear >= intensity_measure_year & fyear <= period_end) %>%
  select(gvkey, fyear, all_of(intensity_measure_name)) %>%
  pivot_wider(names_from = fyear, values_from = all_of(intensity_measure_name)) %>%
  column_to_rownames(var = "gvkey") %>% # convert into rownames
  round(digits = 6) %>%
  na.omit() %>%
  head(20)
         2001     2002     2003     2004     2005     2006     2007
1004 0.108170 0.108367 0.090809 0.080233 0.064026 0.069679 0.084466
1034 0.085633 0.098100 0.109003 0.128727 0.061396 0.115526 0.096297
1050 0.136394 0.155087 0.135856 0.128910 0.131329 0.089732 0.060413
1062 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
1072 0.129059 0.137992 0.146348 0.160801 0.160973 0.156375 0.168714
1078 0.110799 0.112253 0.112998 0.099345 0.103850 0.102737 0.102812
1094 0.000000 0.000000 0.000000 0.002178 0.022419 0.000018 0.015997
1096 0.785170 0.869140 0.862246 0.879633 0.891396 0.746847 0.773825
1104 0.111139 0.141933 0.143785 0.132426 0.110165 0.083864 0.074511
1111 0.007991 0.007761 0.005095 0.004037 0.003540 0.003081 0.002584
1209 0.100494 0.101460 0.102376 0.095156 0.096130 0.090790 0.087199
1234 0.191952 0.167563 0.174638 0.158038 0.245521 0.357150 0.346692
1239 0.108736 0.103892 0.099853 0.111091 0.111724 0.111424 0.109633
1246 0.012099 0.010856 0.009893 0.013562 0.016198 0.012294 0.012392
1254 0.272726 0.266979 0.278409 0.267154 0.249638 0.252332 0.256958
1274 0.031595 0.026682 0.016866 0.013518 0.000000 0.000000 0.000000
1300 0.094279 0.077398 0.078347 0.076718 0.076547 0.079635 0.078480
1356 0.201305 0.194029 0.197092 0.203594 0.200647 0.186994 0.202098
1397 0.206171 0.220253 0.246687 0.225779 0.226116 0.246590 0.261791
1408 0.119055 0.114270 0.103655 0.080915 0.075863 0.077487 0.072452
Show the code
cat("`book_leverage`: \n")
`book_leverage`: 
Show the code
data %>%
  filter(debt_ebitda >= 0 & debt_ebitda <= 15 & book_leverage >= 0 & book_leverage <= 1) %>%
  filter(fyear >= intensity_measure_year & fyear <= period_end) %>%
  select(gvkey, fyear, book_leverage) %>%
  pivot_wider(names_from = fyear, values_from = book_leverage) %>%
  column_to_rownames(var = "gvkey") %>% # convert into rownames
  round(digits = 6) %>%
  na.omit() %>%
  head(20)
         2001     2002     2003     2004     2005     2006     2007
1004 0.366410 0.374171 0.355366 0.315344 0.327808 0.307087 0.389800
1034 0.443761 0.390025 0.350821 0.350195 0.256678 0.000000 0.241454
1050 0.403809 0.392527 0.376197 0.370203 0.336014 0.245173 0.048760
1062 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
1072 0.009064 0.002012 0.000016 0.000000 0.000000 0.000000 0.000000
1075 0.401539 0.387488 0.357503 0.330733 0.265757 0.285440 0.322986
1078 0.312873 0.264751 0.224204 0.235704 0.227633 0.343050 0.307542
1094 0.116427 0.065755 0.026603 0.006680 0.004201 0.003001 0.002785
1096 0.553017 0.562115 0.565844 0.569743 0.651411 0.632386 0.644374
1104 0.283349 0.290962 0.246117 0.064149 0.198163 0.292025 0.241343
1111 0.005908 0.003998 0.000000 0.000000 0.000000 0.000000 0.000000
1166 0.212476 0.224911 0.308825 0.360816 0.316875 0.274541 0.222454
1177 0.039325 0.040782 0.039406 0.038205 0.036193 0.052225 0.064450
1186 0.372343 0.242082 0.000000 0.197023 0.134269 0.000000 0.005912
1209 0.311092 0.283661 0.269999 0.241395 0.245244 0.259742 0.290470
1210 0.181592 0.117639 0.014305 0.051640 0.255779 0.030875 0.022521
1224 0.368912 0.327470 0.226319 0.263710 0.283836 0.268332 0.275758
1225 0.393992 0.403004 0.348215 0.343377 0.345611 0.336841 0.327711
1230 0.303474 0.314264 0.341679 0.312744 0.285496 0.282259 0.289586
1234 0.266384 0.169997 0.071391 0.043556 0.032229 0.119022 0.000000

EndNotes

  • Use small firms with zero bnl_lease as the benchmark.

    • big firms with zero bnl_lease have similar level of leverage over time.

    • small firms with positive bnl_lease have significantly higher leverage before the treatment and significantly lower leverage afterwards.

    • big firms with positive bnl_lease have significantly higher leverage before the treatment and are indifferent from the benchmark after the treatment.

    • parallel trend assumption should hold.

  • For nice plots: ggiplot()

  • Measures for financial constraints are from Appendix A.2 > Section 2

    • Joan Farre-Mensa, Alexander Ljungqvist, Do Measures of Financial Constraints Measure Financial Constraints?, The Review of Financial Studies, Volume 29, Issue 2, February 2016, Pages 271–308, https://doi.org/10.1093/rfs/hhv052
  • Use firms with executory contracts in year 2000 versus firms without executory contracts.