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)
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 datacompustat_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)
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 <-2004period_start <-2002period_end <-2007intensity_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 intensitycontract_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 onesland_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-scorekz =-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)))
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.
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.
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 variableleft_join(y = data_firm, by =join_by(gvkey) ) %>%## merge the FF 30 industry classificationleft_join(y = FF_30ind, by =join_by(sic)) %>%## exclude certain industriesfilter( 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
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 variableleft_join(y = data_firm, by =join_by(gvkey) ) %>%## merge the FF 30 industry classificationleft_join(y = FF_30ind, by =join_by(sic)) %>%## exclude certain industriesfilter( 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/binarycontrols_inclusion =c(FALSE, TRUE, "Full"),# whether to include controlsbalanced_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 resultsfml_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 contentbootstrap_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/binarycontrols_inclusion =c(FALSE, TRUE, "Full"),# whether to include controlsbalanced_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
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 contentbootstrap_options =c("striped", "condensed") )
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.
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 contentbootstrap_options =c("striped", "condensed") )
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 variableleft_join(y = data_firm, by =join_by(gvkey) ) %>%## merge the FF 30 industry classificationleft_join(y = FF_30ind, by =join_by(sic)) %>%## exclude certain industriesfilter( 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/binarycontrols_inclusion =c(FALSE, TRUE),# whether to include controlsbalanced_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 resultsfml_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 contentbootstrap_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/binarycontrols_inclusion =c(FALSE, TRUE),# whether to include controlsbalanced_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
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 contentbootstrap_options =c("striped", "condensed") )
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 variableleft_join(y = data_firm, by =join_by(gvkey) ) %>%## merge the FF 30 industry classificationleft_join(y = FF_30ind, by =join_by(sic)) %>%## exclude certain industriesfilter( 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) %>% .$gvkeydata_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/binarycontrols_inclusion =c(FALSE, TRUE),# whether to include controlsbalanced_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 resultsfml_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 contentbootstrap_options =c("striped", "condensed") ) %>% kableExtra::footnote(general ="Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1",general_title ="Note:" )
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 contentbootstrap_options =c("striped", "condensed") )
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.
Source Code
---title: "Non-financial Liabilities and Restructuring" subtitle: "Empirical support from 2005 Reform with the North America sample" author: "Hongyi Xu"date: "March 10, 2025"date-modified: last-modified format: html: theme: flatly toc: true toc-depth: 4 # Add this line to include 3 levels of TOC code-fold: true code-tools: true code-summary: "Show the code" html-math-method: katex toc-location: left code-block-bg: true code-block-border-left: "#31BAE9" execute: output: trueeditor: visualeditor_options: chunk_output_type: console---```{=html}<style type="text/css">body, td { font-size: 16px;}code.r{ font-size: 12px;}pre { /* For appearance of output blocks */ font-size: 12px; background-color: #f0f0f0; /* Light grey background */ padding: 5px; <!-- border-radius: 5px; /* border corner */ -->} .gt_table .gt_caption { font-size: 16px; display: flex; justify-content: space-between; align-items: center;}/* Middle column: Main content */.content-column { flex: 2; /* Takes remaining space */ margin-right: 20px; /* Spacing between columns */}/* Right column: Outputs */.output-column { flex: 0 0 10%; /* Fixed width for outputs */ position: sticky; top: 0; height: 100vh; /* Full height */ overflow-y: auto; /* Scrollable if content is long */}</style>``````{r setup, include=FALSE}knitr::opts_chunk$set(echo = TRUE)rm(list = ls())library(haven) library(tidyverse) library(ggplot2) library(scales) library(gt)library(fixest)library(patchwork) # Get system informationsys_info <- Sys.info()# Check the operating systemif (sys_info['sysname'] == 'Windows') { work_dir <- "C:/Users/13613/OneDrive - Handelshögskolan i Stockholm/Projects_2024/BeckerJosephsonXu_2025/AFA_meeting_response" print("You are running R on Windows.")} else if (sys_info['sysname'] == 'Darwin') { work_dir <- "~/Library/CloudStorage/OneDrive-HandelshögskolaniStockholm/Projects_2024/BeckerJosephsonXu_2025/AFA_meeting_response" print("You are running R on Mac.")} else { print("You are running R on a different operating system.") }setwd(work_dir)list.files()## > Windows: C:/Users/13613/OneDrive - Handelshögskolan i Stockholm/Projects_2024## > Mac: ~/Library/CloudStorage/OneDrive-HandelshögskolaniStockholm/Projects_2024```::: callout-important#### 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](http://hongyileoxu.github.io/research/Purchase_contract_10Ks/AFA_test_2005_PPE_clean.html).:::## S1. Download and Load the Raw Dataset {#sec-s1-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, <mark>[To Be Added](https://github.com/Wenzhi-Ding/FamaFrenchIndustry) / [Definition](https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/Data_Library/det_30_ind_port.html)</mark>).<mark>In this version we add a set of new variables</mark>:- `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](https://livehhsse-my.sharepoint.com/:u:/r/personal/65570_student_hhs_se/Documents/Projects_2024/BeckerJosephsonXu_2025/AFA_meeting_response/Test/2005_test/Variable%20Def%20Compustat/Wharton%20Research%20Data%20Services%20-%20fatl.html?csf=1&web=1&e=CdIDnC)- `Property, Plant, and Equipment - Buildings at Cost (fatb)`. \>[Definition](https://livehhsse-my.sharepoint.com/:u:/r/personal/65570_student_hhs_se/Documents/Projects_2024/BeckerJosephsonXu_2025/AFA_meeting_response/Test/2005_test/Variable%20Def%20Compustat/Wharton%20Research%20Data%20Services%20-%20fatb.html?csf=1&web=1&e=mKw61J)- `Property, Plant, and Equipment - Land and Improvements at Cost (fatp)`.<!-- - `Property, Plant, and Equipment - Leases (Net) (ppenls)`. [no longer available] -->- `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](https://livehhsse-my.sharepoint.com/:u:/g/personal/65570_student_hhs_se/EcYuzHO66GFCohXiCmFrdFMBPcI2FNxqePqRXsd5SwSZXg?e=muF6fe)\><!-- ::: {#nte-company-location .callout-note .column-margin collapse="TRUE"} -->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:```{r s1-load-data, echo=TRUE, results='hold'}## create the data file path data_file <- "jpbdsuonrpztpw8t.csv" data_path <- file.path(work_dir, "Data", data_file)## load the compustat_na datacompustat_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)```## S2. Data Cleaning and Prep {#sec-s2-clean-prep}Two dependent variables are constructed to measure firm's leverage: (<u>cf. p18 and Table 2 of the paper</u>)- `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](https://www.congress.gov/bill/109th-congress/senate-bill/256), 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](https://en.wikipedia.org/wiki/Bankruptcy_Abuse_Prevention_and_Consumer_Protection_Act?utm_source=chatgpt.com)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:```{r s2-clean-prep, echo=TRUE, results='hold'}## set the base year base_year <- 2004 period_start <- 2002period_end <- 2007intensity_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))) ```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.<mark>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.</mark>For definitions of controls, please refer to @sec-EndNotes.- `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```{r s2-summary-stat, echo=TRUE}## 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") ) ```### s2.2. plot the distribution of different intensity measures {.tabset}```{r s2-plots, echo=TRUE, results='asis'}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')} ```## S3. Difference-in-Difference Examination {#sec-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 `r paste("[", paste(range(data$fyear, na.rm = TRUE), collapse = ", "), "]", sep = "")` and we restrict the sample to the fiscal year in \[2002, 2007\].### s3.0. Executory contract intensity {#sec-s3z-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.```{r s3z-did-data, echo=TRUE, results='hold'}## 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 `r intensity_measure_name` in year `r base_year`.```{r s3z-did-test, echo=TRUE, warning=FALSE, message=FALSE, results='hold'}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") )```### s3.1. PPE lease intensity {#sec-s3a-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.```{r s3a-did-data, echo=TRUE, results='hold'}## 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:```{r s3a-did-test, echo=TRUE, warning=FALSE, message=FALSE, results='hold'}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") )```### s3.2. builing intensity {#sec-s3b-building-intensity}`building_intensity` is chosen to measure a firm's long-term exposure to buildings at cost under the PPE.```{r s3b-did-data, echo=TRUE, results='hold'}## 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:```{r s3b-did-test, echo=TRUE, warning=FALSE, message=FALSE, results='hold'}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 resultsfml_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") )```All treatment effect estimates are significantly negative across all specifications.Next we estimate the yearly treatment effects.#### Individual Year Treatment Plots::: callout-importantDifferent 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.:::```{r s3b-did-plot, echo=TRUE}## 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## 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 resultsfml_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) })### 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") )### 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'));#### 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]);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:```{r testing, echo=TRUE, include=TRUE, results='hold', message=FALSE, warning=FALSE}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'));# Calculate the Wald statisticsmodel_large <- did_model_subsample[[1]]model_small <- did_model_subsample[[2]]## get the name of the coefficient of interestscoef_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 effectsdiff_coef <- coef_large - coef_small# Variance of the differencevar_diff <- vcov(model_large)[coef_names, coef_names] + vcov(model_small)[coef_names, coef_names]# Wald statistic for each treatment effect estimatewald_stat <- (diff_coef)^2 / diag(var_diff)wald_stat_vector <- c(t(diff_coef) %*% solve(var_diff) %*% (diff_coef))# Degrees of freedomdf <- 1df_vector <- length(diff_coef)# P-valuep_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 resultscat("\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()```#### Placebal tests:```{r s3b-placebal-test, echo=TRUE, warning=FALSE, message=FALSE, results='hold'}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 resultsfml_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") )```For yearly treatment effects and parallel trend analysis,```{r s3b-placebal-plot, echo=TRUE}## 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## 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 resultsfml_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) })### 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") )### 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'));#### 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]);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 {#sec-s3c-land-intensity}`land_intensity` is chosen to measure a firm's long-term exposure to land and improvements at cost under the PPE.```{r s3c-did-data, echo=TRUE, results='hold'}## 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:```{r s3c-did-test, echo=TRUE, warning=FALSE, message=FALSE, results='hold'}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 resultsfml_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") )```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:```{r s3c-did-plot, echo=TRUE}## 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## 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 resultsfml_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) })### 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") )### 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'));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 {#sec-s3c-building-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.```{r s3d-did-data, echo=TRUE, results='hold'}## 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) %>% .$gvkeydata_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`.```{r s3d-did-test, echo=TRUE, warning=FALSE, message=FALSE, results='hold'}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 resultsfml_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:" )```DiD analysis:```{r s3d-did-plot, echo=TRUE}## 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## 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 resultsfml_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) })### 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") )### 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'));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'))```<!-- Other tests and summary stat: --><!-- ```{r s3d-test-run, echo=TRUE, results='asis'} --><!-- cat('#### ', "Big versus Small", ' \n') --><!-- did_model_subsample <- data_did_loop_balanced %>% --><!-- fixest::feols(fml = debt_ebitda ~ i(fyear, intensity_2000, ref = base_year - 1) + --><!-- roa + ebitda_at + log(at_thousand) + --><!-- altman_Z + tangibility + current_ratio | --><!-- gvkey + fyear + ff_30ind_name^fyear, --><!-- data = ., --><!-- cluster = c("gvkey", "ff_30ind_name"), --><!-- split = ~ large # large --><!-- ) --><!-- did_model_subsample %>% etable(se.below = TRUE) --><!-- { --><!-- # Calculate the Wald statistics --><!-- model_large <- did_model_subsample[[1]] --><!-- model_small <- did_model_subsample[[2]] --><!-- ## get the name of the coefficnet 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("Wald test for the difference in the treatment effect\n between the Large firms and Small firms: \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) --><!-- ) --><!-- cat("Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 \n") --><!-- ## Interacting with Large/Small: --><!-- data_did_loop_balanced %>% --><!-- fixest::feols(fml = debt_ebitda ~ intensity_2000 + post_2005 + large + post_2005*large + intensity_2000*large + intensity_2000:post_2005:i(large) --><!-- + roa + ebitda_at + log(at_thousand) + altman_Z + tangibility + current_ratio --><!-- | --><!-- gvkey + fyear + ff_30ind_name^fyear, data = ., cluster = c("gvkey", "ff_30ind_name")) %>% --><!-- etable() --><!-- ``` -->Check the trend of movement in the intensity measure:```{r s3d-trend, echo=TRUE, warning=FALSE, message=FALSE}### Observation summary:cat("#### Number of Observations in Each Group over time (Full Sample): \n")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() )cat("#### Number of Observations in Each Group over time (Balanced Panel): \n")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() )cat("`bnl_intensity`: \n")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)cat("`book_leverage`: \n")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)```------------------------------------------------------------------------## EndNotes {#sec-EndNotes}- [ ] If the land and building lease obligations (`bnl_lease`) are not constantly renewed, it will decrease over time. Therefore, the lease intensity should go down over time as well. Relative to those untreated firms, i.e. w/o `bnl_lease`, treated firms should generally have a higher leverage.- 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()`](https://grantmcdermott.com/ggfixest/articles/ggiplot.html)- Measures for financial constraints are from [Appendix A.2](https://academic.oup.com/rfs/article/29/2/271/1902640?searchresult=1#114343035)\> @sec-s2-clean-prep - 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>- [x] Should we still use `fyear = 2005` as the base year with `indexyear = 0`? As it came into effect in Oct 2005, most of the treatment effect will show up in 2005. <mark>Should we choose 2004 as the base year</mark>?- Use firms with executory contracts in year 2000 versus firms without executory contracts.