flowchart TD
subgraph inputs [Packaged data inputs]
loansPanel[tstm_loans_panel]
assetLoan[tstm_asset_loan]
end
subgraph gateway [Gateway run]
gw[ffp_hfid_invest_loan_linked_abc_investloan_char_gateway]
end
loansPanel --> gw
assetLoan --> gw
subgraph outputs [Eight regenerated tstm objects]
o1[tstm_loans_pn_nd]
o2[tstm_loans_hooks]
o3[tstm_loans_bridges_type]
o4[tstm_invdates_uniq]
o5[tstm_invest]
o6[tstm_roster_invest_loan_linked]
o7[tstm_roster_invest2loan2bridge]
o8[tstm_invest2loan2bridge_chars]
end
gw --> o1
gw --> o2
gw --> o3
gw --> o4
gw --> o5
gw --> o6
gw --> o7
gw --> o8
subgraph deliver [Save and tabulate]
saveRda[save to data or data-temp]
tabs[investloan_type m4 brg_m5 m8 tables]
tex[res_bridge_type latex tables]
end
o1 --> saveRda
o8 --> saveRda
o8 --> tabs
o7 --> tabs
o8 --> tex
This vignette implements PrjThaiHFID-#32.
It runs the investment–loan–bridge gateway (ffp_hfid_invest_loan_linked_abc_investloan_char_gateway), optionally writes eight regenerated tstm_* objects to data/ or data-temp/, and produces summary tables from gateway outputs.
Unit of observation: investment-loan-bridge linkages — investment-level investloan_type_* categories keyed on household hhid_Num x asset ivars x investment counter hh_inv_asset_ctr.
Outputs at a glance
This vignette regenerates eight gateway datasets, written to data/ when bl_replace_data_output <- TRUE, otherwise to the gitignored data-temp/ for safe validation. Use the links below to jump to each rendered data documentation page:
| Object | Data page | Role |
|---|---|---|
tstm_loans_pn_nd |
reference | Non-duplicate monthly loan panel (Set A loans) |
tstm_loans_hooks |
reference | Hooked loan pairs (Set A + B) |
tstm_loans_bridges_type |
reference | Loan bridges with formal/informal type |
tstm_invdates_uniq |
reference | Unique investment dates |
tstm_invest |
reference | Investment spells by asset ivars
|
tstm_roster_invest_loan_linked |
reference | Investment-to-loan roster |
tstm_roster_invest2loan2bridge |
reference | Investment-to-loan-to-bridge roster |
tstm_invest2loan2bridge_chars |
reference | Investment-level linkage characteristics |
These objects are documented in R/data-res.R. The two inputs tstm_loans_panel and tstm_asset_loan are documented in R/data.R and R/data-res.R.
Tables and figures (not saved as data): an investment-type-by-asset wide table with paper-style row labels, investment-level counts and shares for investloan_type_m4 / investloan_type_brg_m5 / investloan_type_m8, and roster diagnostic tallies. Each table is gated by its own ls_save_res[["<name>"]] switch (all FALSE by default); flip one on to write its LaTeX/CSV (including example_table) to res/res_bridge_type/ via ffp_save_res_table().
What ships vs. what is generated locally
- Shipped with the installed package: the packaged datasets in
data/(lazy-loaded inputststm_loans_panel,tstm_asset_loan).- Generated locally when this vignette runs (neither pushed to GitHub nor shipped in the package): the eight gateway
.rdawritten todata/(ordata-temp/); theirinst/extdata/*.csv/*.dtaexports; and any tables written tores/res_bridge_type/(.tex/.csv, only when the matchingls_save_rescontrol isTRUE). Theinst/extdata/andres/artifacts are git-ignored, saved only for local convenience.
Required packaged inputs
The gateway loads only two objects from the package data/ folder (must exist locally when knitting):
| Object | Role |
|---|---|
tstm_loans_panel |
Monthly loan panel (Group A) |
tstm_asset_loan |
Household-month asset and loan aggregates (Group B) |
All other pipeline objects are computed in this run.
Pipeline structure
Control parameters
library(PrjThaiHFID)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
library(tidyr)
library(glue)
library(kableExtra)
#>
#> Attaching package: 'kableExtra'
#> The following object is masked from 'package:dplyr':
#>
#> group_rows
bs_style <- c("striped", "hover", "condensed", "responsive")
options(kable_styling_bootstrap_options = bs_style)
verbose <- TRUE
it_file_code <- 494318
# TRUE: overwrite canonical data/*.rda; FALSE: write to data-temp/ (gitignored)
bl_replace_data_output <- FALSE
st_kableformat <- "html"
# MBF timing and size cuts (same as R-script/ffs_bridge_count/ffs_bridge_count_mbf.R)
it_mth_inv_start_min_cut <- 14
it_mth_inv_start_max_cut <- 144
fl_min_invest_size_cut <- 10000
# Three paper asset variables (Table 4)
ar_st_vars_to_keep <- c("agg_BS_1021", "agg_BS_1012", "agg_BS_1011")
ar_ivars_paper <- ar_st_vars_to_keep
# here::here() anchors on the temporary _quarto.yml pkgdown writes under
# vignettes/ during a quarto render; find the package root explicitly so paths
# resolve under both Quarto and knitr.
spn_pkg_root <- rprojroot::find_root(rprojroot::has_file("DESCRIPTION"))
spn_res_bridge_type <- file.path(
spn_pkg_root, "res", "res_bridge_type",
fsep = .Platform$file.sep
)
spt_res <- file.path(spn_pkg_root, "res", "res_bridge_type")
st_data_out <- file.path(
spn_pkg_root,
if (bl_replace_data_output) "data" else "data-temp",
fsep = .Platform$file.sep
)
st_extdata_dir <- file.path(spn_pkg_root, "inst", "extdata")
# Per-table .tex/.csv save switches; all FALSE by default (display always shown).
ls_save_res <- list(
example_table = FALSE,
tab_inv_m4_counts = FALSE,
tab_inv_m4_shares = FALSE,
tab_inv_brg_m5_counts = FALSE,
tab_inv_brg_m5_shares = FALSE,
tab_inv_m8_counts = FALSE,
tab_inv_m8_shares = FALSE,
tab_roster_ivars = FALSE,
tab_chars_m8 = FALSE,
tab_roster_bl_informal = FALSE,
tab_roster_m8_informal = FALSE
)
dir.create(spn_res_bridge_type, recursive = TRUE, showWarnings = FALSE)
for (st_dir in c(st_data_out, st_extdata_dir)) {
if (!dir.exists(st_dir)) {
dir.create(st_dir, recursive = TRUE)
}
}
ar_tstm_save <- c(
"tstm_loans_pn_nd",
"tstm_loans_hooks",
"tstm_loans_bridges_type",
"tstm_invdates_uniq",
"tstm_invest",
"tstm_roster_invest_loan_linked",
"tstm_roster_invest2loan2bridge",
"tstm_invest2loan2bridge_chars"
)
ffv_save_gateway_tstm <- function(obj, name, out_dir, extdata_dir = st_extdata_dir) {
if (!dir.exists(out_dir)) {
dir.create(out_dir, recursive = TRUE)
}
if (!dir.exists(extdata_dir)) {
dir.create(extdata_dir, recursive = TRUE)
}
st_rda <- file.path(out_dir, paste0(name, ".rda"))
st_csv <- file.path(extdata_dir, paste0(name, ".csv"))
st_dta <- file.path(extdata_dir, paste0(name, ".dta"))
tmp_env <- new.env(parent = emptyenv())
tmp_env[[name]] <- obj
save(list = name, file = st_rda, envir = tmp_env)
readr::write_csv(obj, st_csv)
# Local-only .dta export (git-ignored). Stata caps variable names at 32
# characters, so truncate long names (uniquely) for the .dta copy only; the
# canonical .rda and the full-name .csv are unaffected. Never let a Stata
# name/format edge case break the knit -> skip the .dta with a message.
if (requireNamespace("haven", quietly = TRUE)) {
tryCatch(
{
obj_dta <- obj
nm <- names(obj_dta)
if (any(nchar(nm) > 32)) {
nm <- substr(nm, 1, 32)
nm <- make.unique(nm, sep = "_")
nm <- substr(nm, 1, 32)
names(obj_dta) <- nm
}
haven::write_dta(obj_dta, st_dta)
},
error = function(e) {
message(glue::glue(
"skip .dta for {name}: {conditionMessage(e)} (csv + rda still written)"
))
st_dta <<- NA_character_
}
)
} else {
message("package 'haven' not installed: skipping .dta export (csv + rda still written)")
st_dta <- NA_character_
}
invisible(list(rda = st_rda, csv = st_csv, dta = st_dta))
}
ffv_inv_type_by_ivars <- function(df, type_var) {
df %>%
dplyr::group_by(ivars, .data[[type_var]]) %>%
dplyr::tally(name = "n") %>%
tidyr::pivot_wider(names_from = ivars, values_from = n, values_fill = 0)
}
ffv_inv_type_share_by_ivars <- function(df, type_var) {
df %>%
dplyr::group_by(ivars, .data[[type_var]]) %>%
dplyr::tally(name = "n") %>%
dplyr::group_by(ivars) %>%
dplyr::mutate(share = n / sum(n)) %>%
dplyr::select(-n) %>%
tidyr::pivot_wider(
id_cols = dplyr::all_of(type_var),
names_from = ivars,
values_from = share
)
}
ffv_m8_cell <- function(tb, m8, ivar, kind = c("n", "pct")) {
kind <- match.arg(kind)
col <- paste0(ivar, if (kind == "n") "_n" else "_share")
if (!m8 %in% tb$investloan_type_m8) {
return(if (kind == "n") "0" else "0.0\\%")
}
val <- tb[[col]][tb$investloan_type_m8 == m8][1]
if (kind == "n") {
as.character(as.integer(val))
} else {
sprintf("%.1f\\%%", val * 100)
}
}
ffv_m8_data_row <- function(tb, m8) {
ivars <- c("agg_BS_1021", "agg_BS_1012", "agg_BS_1011")
vals <- unlist(lapply(ivars, function(iv) {
c(ffv_m8_cell(tb, m8, iv, "n"), ffv_m8_cell(tb, m8, iv, "pct"))
}))
paste0("& ", paste(vals, collapse = " \n& "), "\\\\")
}
# Write example_table.tex with fixed layout from res/res_bridge_type/example_table_ori.tex
ffv_write_example_table_tex <- function(tb, name = "example_table",
spn_out = spt_res, df = NULL,
bl_save = FALSE) {
rows <- list(
"1-investment-no-loan",
"2-investment-loan-a",
"3-investment-loan-hook",
"4-brg-single-lender",
"5-brg-baac-vilfund-combo",
"6-brg-informal-quasifor-combo",
"7-brg-has-informal-bridge",
"8-brg-has-informal-in-bridge"
)
body_rows <- vapply(rows, function(m8) ffv_m8_data_row(tb, m8), character(1))
tex <- c(
"% Auto-generated from vignettes/ffv_invest_loan_bridge.qmd",
"% Styling matches res/res_bridge_type/example_table_ori.tex",
"% it_gap_LBL_IL_min <- -6 horizon",
"\\begin{tabular}[t]{",
">{\\centering\\arraybackslash}p{3.0cm}",
">{\\centering\\arraybackslash}p{2.0cm}",
">{\\centering\\arraybackslash}p{2.0cm}",
">{\\centering\\arraybackslash}p{2.0cm}",
">{\\centering\\arraybackslash}p{2.0cm}",
">{\\centering\\arraybackslash}p{2.0cm}",
">{\\centering\\arraybackslash}p{2.0cm}}",
"\\toprule",
"& \\multicolumn{6}{c}{",
"\\textbf{Alternative investment definitions}",
"}\\\\",
"\\cmidrule(l{3pt}r{3pt}){2-7}",
"\\multicolumn{1}{c}{ } & ",
"\\multicolumn{2}{p{4cm}}{",
"\\centering\\small Agricultural and business assets investments",
"} & ",
"\\multicolumn{2}{p{4cm}}{",
"\\centering\\small Agricultural, business, and land assets investments",
"} & ",
"\\multicolumn{2}{p{4cm}}{",
"\\centering\\small Agricultural, business, land, and household assets investments",
"}\\\\",
"\\cmidrule(l{3pt}r{3pt}){2-3} \\cmidrule(l{3pt}r{3pt}){4-5} \\cmidrule(l{3pt}r{3pt}){6-7}",
"& \\small{\\#} & \\multicolumn{1}{p{2cm}}{\\centering\\small{\\%}} ",
"& \\small{\\#} & \\multicolumn{1}{p{2cm}}{\\centering\\small{\\%}}",
"& \\small{\\#} & \\multicolumn{1}{p{2cm}}{\\centering\\small{\\%}}\\\\",
"\\midrule",
"\\addlinespace[0.5em]",
"\\multicolumn{7}{l}{\\textbf{",
"Investments \\emph{not} time-linked to loan bridges",
"}}\\\\",
"\\multicolumn{7}{l}{",
"\\hspace{1em}",
"Invest. \\emph{not} time-linked any loans",
"}\\\\",
"\\addlinespace[0.1em]",
body_rows[1],
"\\addlinespace[0.2em]",
"\\multicolumn{7}{l}{",
"\\hspace{1em}",
"Invest. time-linked to \\emph{standalone} loans (set A loans only)",
"}\\\\",
"\\addlinespace[0.1em]",
body_rows[2],
"\\addlinespace[0.2em]",
"\\multicolumn{7}{l}{",
"\\hspace{1em}",
"Invest. time-linked to \\emph{``hooked''} loans (set A and B loans only)",
"}\\\\",
"\\addlinespace[0.1em]",
body_rows[3],
"\\addlinespace[0.2em]",
"\\cmidrule(l{10pt}r{3pt}){1-7}",
"\\multicolumn{7}{l}{\\textbf{",
"Investments time-linked to \\emph{only} formal \\emph{or} \\emph{only} informal loan bridges",
"}}\\\\",
"\\multicolumn{7}{l}{",
"\\hspace{1.0em}",
"\\emph{Single lender} type only investment-loan bridge",
"}\\\\",
"\\addlinespace[0.1em]",
body_rows[4],
"\\addlinespace[0.2em]",
"\\multicolumn{7}{l}{",
"\\hspace{1.0em}",
"\\emph{Multiple formal} lenders investment-loan bridge",
"}\\\\",
"\\addlinespace[0.1em]",
body_rows[5],
"\\addlinespace[0.2em]",
"\\multicolumn{7}{l}{",
"\\hspace{1.0em}",
"\\emph{Multiple informal} lender types investment-loan bridge",
"}\\\\",
"\\addlinespace[0.1em]",
body_rows[6],
"\\addlinespace[0.2em]",
"\\cmidrule(l{10pt}r{3pt}){1-7}",
"\\multicolumn{7}{l}{\\textbf{",
"Investments time-linked to \\emph{joint} formal \\emph{and} informal investment-loan bridges",
"}}\\\\",
"\\multicolumn{7}{l}{",
"\\hspace{1.0em}",
"Contains \\emph{formal---informal---formal} loan bridges",
"}\\\\",
"\\addlinespace[0.1em]",
body_rows[7],
"\\addlinespace[0.2em]",
"\\multicolumn{7}{l}{",
"\\hspace{1.0em}",
"Do not contain formal---informal---formal loan bridges, but includes \\emph{informal links} in bridges",
"}\\\\",
"\\addlinespace[0.1em]",
body_rows[8],
"\\addlinespace[0.2em]",
"\\bottomrule",
"\\end{tabular}"
)
ffp_save_res_table(tex, name, spn_out, df = df, bl_save = bl_save)
invisible(tex)
}
ffv_render_table <- function(
df,
caption,
name = NULL,
bl_save = FALSE,
spn_res = spt_res,
st_format = st_kableformat) {
kt <- kbl(
df,
format = st_format,
booktabs = TRUE,
caption = caption,
digits = 4
) %>%
kable_styling(
bootstrap_options = bs_style,
full_width = FALSE,
position = "left"
)
if (isTRUE(bl_save) && !is.null(name)) {
tex <- knitr::kable(
df,
format = "latex",
booktabs = TRUE,
caption = caption,
label = name,
digits = 4
)
ffp_save_res_table(tex, name, spn_res, df = df, bl_save = bl_save)
}
kt
}
if (verbose) {
print(glue::glue("f-{it_file_code}, controls"))
print(glue::glue(" bl_replace_data_output: {bl_replace_data_output} -> {st_data_out}/"))
print(glue::glue(" st_extdata_dir: {st_extdata_dir}"))
print(glue::glue(" ls_save_res TRUE: {paste(names(which(unlist(ls_save_res))), collapse = ', ')}"))
print(glue::glue(" it_mth_inv_start_min_cut: {it_mth_inv_start_min_cut}"))
print(glue::glue(" it_mth_inv_start_max_cut: {it_mth_inv_start_max_cut}"))
print(glue::glue(" fl_min_invest_size_cut: {fl_min_invest_size_cut}"))
print(glue::glue(" ar_st_vars_to_keep: {paste(ar_st_vars_to_keep, collapse = ', ')}"))
}
#> f-494318, controls
#> bl_replace_data_output: FALSE -> /home/runner/work/PrjThaiHFID/PrjThaiHFID/data-temp/
#> st_extdata_dir: /home/runner/work/PrjThaiHFID/PrjThaiHFID/inst/extdata
#> ls_save_res TRUE:
#> it_mth_inv_start_min_cut: 14
#> it_mth_inv_start_max_cut: 144
#> fl_min_invest_size_cut: 10000
#> ar_st_vars_to_keep: agg_BS_1021, agg_BS_1012, agg_BS_1011Run gateway
Same call as R-script/ffs_bridge_count/ffs_bridge_count_mbf.R.
if (verbose) {
print(glue::glue("f-{it_file_code}, gateway: calling ffp_hfid_invest_loan_linked_abc_investloan_char_gateway"))
}
#> f-494318, gateway: calling ffp_hfid_invest_loan_linked_abc_investloan_char_gateway
ls_gateway_result <- PrjThaiHFID::ffp_hfid_invest_loan_linked_abc_investloan_char_gateway(
svr_lender_var = "forinfm4",
svr_principal = "bf5klm_bm6h_joint",
svr_principal_last = "bm6h",
svr_principal_interest_sum = "bm6b",
bl_filter_bridge_grvgr0 = TRUE,
it_ll_grv_min = -1,
bl_filter_loan_duration_a = FALSE,
bl_filter_loan_duration_b = FALSE,
bl_filter_lender_type = FALSE,
bl_filter_bridge_informal = FALSE,
bl_filter_loan_size = FALSE,
bl_filter_loan_duration_more = FALSE,
fl_sd_ithres = stats::qnorm(0.99),
it_thres_invest_mth_gap = 2,
it_gap_LBL_IL_min = -6,
ar_st_vars_to_keep = ar_st_vars_to_keep,
fl_min_invest_size = fl_min_invest_size_cut,
it_mth_inv_start_min = it_mth_inv_start_min_cut,
it_mth_inv_start_max = it_mth_inv_start_max_cut,
bl_drop_afrombc = TRUE,
bl_drop_cfromb = TRUE,
bl_compare2baserda = FALSE,
verbose = verbose,
verbose_detail = FALSE,
it_verbose_detail_nrow = 100
)
#>
#> ── char_gateway ────────────────────────────────────────────────────────────────
#> ℹ A.1 Loan non-duplicate
#> ✔ A.1 Loan non-duplicate [14ms]
#>
#> ✔ tstm_loans_pn_nd: 19587 rows
#> ℹ A.2 Hook pairs
#> ✔ A.2 Hook pairs [6ms]
#>
#> ✔ tstm_loans_hooks: 47754 rows
#> ℹ A.3 Bridges from hooks
#> ✔ A.3 Bridges from hooks [6ms]
#>
#> ✔ tstm_loans_bridges: 94907 rows
#> ℹ A.4 Bridge type
#> ✔ A.4 Bridge type [6ms]
#>
#> ✔ tstm_loans_bridges_type: 94907 rows
#> ℹ B Investment gateway
#> ✔ B Investment gateway [9ms]
#>
#> ℹ Group B: processing 3 asset ivar(s): agg_BS_1021, agg_BS_1012, agg_BS_1011
#> ✔ tstm_invest: 4694 rows
#> ℹ C.1 Bridge roster
#> ✔ C.1 Bridge roster [6ms]
#>
#> Adding missing grouping variables: `br_type`, `br_type_id`
#> ✔ tstm_roster_invest_loan_bridge: 82593 rows
#> ℹ C.2 Linker
#> ✔ C.2 Linker [6ms]
#>
#> ✔ tstm_roster_invest_loan_linker: 4120 rows
#> ℹ C.3 Invest-loan linked
#> ✔ C.3 Invest-loan linked [6ms]
#>
#> ✔ tstm_roster_invest_loan_linked: 145746 rows
#> ℹ D.1 abc_distinct filter
#> ✔ D.1 abc_distinct filter [6ms]
#>
#> ✔ tstm_roster_invest2loan2bridge_clean: 10449 rows
#> ℹ D.1b NA synchronization
#> ✔ D.1b NA synchronization [6ms]
#>
#> ℹ D.2 Bridge char
#> ✔ D.2 Bridge char [6ms]
#>
#> ✔ tstm_roster_invest2loan2bridge: 10449 rows
#> ℹ D.3 Investment char
#> ✔ D.3 Investment char [6ms]
#>
#> ✔ tstm_invest2loan2bridge_chars: 2990 rows
#> ℹ E Invest typing summary
#> ✔ E Invest typing summary [6ms]
#>
#> ── Group E: invest typing summary
#> ──────────────────────────────────────────────
#> ℹ Thresholds: capital_invest >= 10000; mth_inv_start in [14, 144]
#>
#> ── Invest rows not in bridge chars
#> Count not in chars: 1704
#> By exclusion reason (mutually exclusive):
#> # A tibble: 3 × 3
#> st_unmatched_reason n share
#> <chr> <int> <dbl>
#> 1 fail_size_and_start 190 0.112
#> 2 fail_size_only 966 0.567
#> 3 fail_start_only 548 0.322
#> 2x2 cross-tab (bl_meets_size x bl_meets_start):
#> # A tibble: 3 × 3
#> bl_meets_size bl_meets_start n
#> <lgl> <lgl> <int>
#> 1 FALSE FALSE 190
#> 2 FALSE TRUE 966
#> 3 TRUE FALSE 548
#>
#> ── Pipeline consistency (per ivars)
#> # A tibble: 3 × 11
#> ivars n_invest n_pass_typing n_in_chars n_not_in_linked n_pass_not_in_linked
#> <chr> <int> <int> <int> <int> <int>
#> 1 agg_BS… 1390 736 736 0 0
#> 2 agg_BS… 1414 821 821 0 0
#> 3 agg_BS… 1890 1433 1433 0 0
#> # ℹ 5 more variables: n_pass_not_in_chars <int>,
#> # n_capital_mismatch_invest_roster <int>,
#> # n_start_mismatch_invest_roster <int>, n_ctr_mismatch_invest_roster <int>,
#> # n_capital_mismatch_chars_roster <int>
#> ✔ GATEWAY INVEST PIPELINE CONSISTENCY: PASS (all checks OK for ar_st_vars_to_keep)
for (nm in ar_tstm_save) {
assign(nm, ls_gateway_result[[nm]], envir = .GlobalEnv)
}
tstm_loans_bridges_type <- ls_gateway_result$tstm_loans_bridges_type
if (verbose) {
print(glue::glue("f-{it_file_code}, gateway: unpacked {length(ar_tstm_save)} tstm objects"))
for (nm in ar_tstm_save) {
obj <- ls_gateway_result[[nm]]
print(glue::glue(" {nm}: {nrow(obj)} rows"))
}
}
#> f-494318, gateway: unpacked 8 tstm objects
#> tstm_loans_pn_nd: 19587 rows
#> tstm_loans_hooks: 47754 rows
#> tstm_loans_bridges_type: 94907 rows
#> tstm_invdates_uniq: 3066 rows
#> tstm_invest: 4694 rows
#> tstm_roster_invest_loan_linked: 145746 rows
#> tstm_roster_invest2loan2bridge: 10449 rows
#> tstm_invest2loan2bridge_chars: 2990 rowsSave regenerated tstm_* objects
for (nm in ar_tstm_save) {
ffv_save_gateway_tstm(
obj = ls_gateway_result[[nm]],
name = nm,
out_dir = st_data_out
)
}
if (verbose) {
if (bl_replace_data_output) {
print(glue::glue("f-{it_file_code}, save: replaced canonical outputs under {st_data_out}/"))
} else {
print(glue::glue("f-{it_file_code}, save: wrote regenerated outputs to {st_data_out}/ (data/ unchanged)"))
}
}
#> f-494318, save: wrote regenerated outputs to /home/runner/work/PrjThaiHFID/PrjThaiHFID/data-temp/ (data/ unchanged)Table: investment type by asset (wide)
Reproduces the summary in R-dev/ffs_hfid_gateway_ilhb.R (lines 477–511): counts and shares of investloan_type_m8 by ivars, pivoted wide.
tb_inv_m8_wide <- tstm_invest2loan2bridge_chars %>%
dplyr::select(
hhid_Num, ivars, hh_inv_asset_ctr,
investloan_type_m8
) %>%
dplyr::distinct() %>%
dplyr::filter(ivars %in% ar_ivars_paper) %>%
dplyr::group_by(ivars, investloan_type_m8) %>%
dplyr::tally(name = "n") %>%
dplyr::group_by(ivars) %>%
dplyr::mutate(share = n / sum(n)) %>%
dplyr::ungroup() %>%
tidyr::pivot_wider(
names_from = ivars,
values_from = c(n, share),
names_glue = "{ivars}_{.value}",
values_fill = list(n = 0, share = 0)
) %>%
dplyr::mutate(
n_total = agg_BS_1021_n + agg_BS_1012_n + agg_BS_1011_n
) %>%
dplyr::mutate(
dplyr::across(dplyr::ends_with("_share"), ~ round(.x, 4))
) %>%
dplyr::select(
investloan_type_m8,
n_total,
agg_BS_1021_n,
agg_BS_1021_share,
agg_BS_1012_n,
agg_BS_1012_share,
agg_BS_1011_n,
agg_BS_1011_share
) %>%
dplyr::arrange(investloan_type_m8)
# HTML preview: paper-style row labels (same order as example_table_ori.tex)
ar_m8_paper_rows <- data.frame(
investloan_type_m8 = c(
"1-investment-no-loan",
"2-investment-loan-a",
"3-investment-loan-hook",
"4-brg-single-lender",
"5-brg-baac-vilfund-combo",
"6-brg-informal-quasifor-combo",
"7-brg-has-informal-bridge",
"8-brg-has-informal-in-bridge"
),
row_label = c(
"Invest. not time-linked any loans",
"Invest. time-linked to standalone loans (set A only)",
"Invest. time-linked to hooked loans (set A and B only)",
"Single lender type only investment-loan bridge",
"Multiple formal lenders investment-loan bridge",
"Multiple informal lender types investment-loan bridge",
"Contains formal-informal-formal loan bridges",
"Informal links in bridges (not formal-informal-formal)"
),
stringsAsFactors = FALSE
)
tb_inv_m8_html <- tb_inv_m8_wide %>%
dplyr::left_join(ar_m8_paper_rows, by = "investloan_type_m8") %>%
dplyr::transmute(
Category = row_label,
`Ag+biz #` = agg_BS_1021_n,
`Ag+biz %` = sprintf("%.1f", agg_BS_1021_share * 100),
`Ag+biz+land #` = agg_BS_1012_n,
`Ag+biz+land %` = sprintf("%.1f", agg_BS_1012_share * 100),
`Ag+biz+land+hh #` = agg_BS_1011_n,
`Ag+biz+land+hh %` = sprintf("%.1f", agg_BS_1011_share * 100)
)
kbl(
tb_inv_m8_html,
format = st_kableformat,
booktabs = TRUE,
caption = "Investment–loan–bridge types by asset definition (counts and %)"
) %>%
kable_styling(
bootstrap_options = bs_style,
full_width = FALSE,
position = "left"
)| Category | Ag+biz # | Ag+biz % | Ag+biz+land # | Ag+biz+land % | Ag+biz+land+hh # | Ag+biz+land+hh % |
|---|---|---|---|---|---|---|
| Invest. not time-linked any loans | 206 | 28.0 | 244 | 29.7 | 424 | 29.6 |
| Invest. time-linked to standalone loans (set A only) | 118 | 16.0 | 131 | 16.0 | 272 | 19.0 |
| Invest. time-linked to hooked loans (set A and B only) | 49 | 6.7 | 54 | 6.6 | 109 | 7.6 |
| Single lender type only investment-loan bridge | 28 | 3.8 | 27 | 3.3 | 61 | 4.3 |
| Multiple formal lenders investment-loan bridge | 29 | 3.9 | 31 | 3.8 | 41 | 2.9 |
| Multiple informal lender types investment-loan bridge | 2 | 0.3 | 1 | 0.1 | 4 | 0.3 |
| Contains formal-informal-formal loan bridges | 176 | 23.9 | 189 | 23.0 | 295 | 20.6 |
| Informal links in bridges (not formal-informal-formal) | 128 | 17.4 | 144 | 17.5 | 227 | 15.8 |
ffv_write_example_table_tex(
tb_inv_m8_wide,
name = "example_table",
spn_out = spt_res,
df = tb_inv_m8_wide,
bl_save = ls_save_res[["example_table"]]
)Tables: investment-level m4, brg_m5, and m8
Investment-level tabulations (same structure as R-script/ffs_bridge_type/ffs_bridge_type.R, Section A, it_ctr == 1).
Four categories (investloan_type_m4)
tb_inv_m4_counts <- ffv_inv_type_by_ivars(
tstm_invest2loan2bridge_chars, "investloan_type_m4"
)
tb_inv_m4_shares <- ffv_inv_type_share_by_ivars(
tstm_invest2loan2bridge_chars, "investloan_type_m4"
)
ffv_render_table(
tb_inv_m4_counts,
caption = "Investment-level counts by investloan_type_m4 and ivars",
name = "tab_inv_m4_counts",
bl_save = ls_save_res[["tab_inv_m4_counts"]]
)| investloan_type_m4 | agg_BS_1011 | agg_BS_1012 | agg_BS_1021 |
|---|---|---|---|
| 1-investment-no-loan | 424 | 244 | 206 |
| 2-investment-loan-a | 272 | 131 | 118 |
| 3-investment-loan-hook | 109 | 54 | 49 |
| 4-investment-loan-bridge | 628 | 392 | 363 |
ffv_render_table(
tb_inv_m4_shares,
caption = "Investment-level shares by investloan_type_m4 and ivars",
name = "tab_inv_m4_shares",
bl_save = ls_save_res[["tab_inv_m4_shares"]]
)| investloan_type_m4 | agg_BS_1011 | agg_BS_1012 | agg_BS_1021 |
|---|---|---|---|
| 1-investment-no-loan | 0.2959 | 0.2972 | 0.2799 |
| 2-investment-loan-a | 0.1898 | 0.1596 | 0.1603 |
| 3-investment-loan-hook | 0.0761 | 0.0658 | 0.0666 |
| 4-investment-loan-bridge | 0.4382 | 0.4775 | 0.4932 |
Five bridge categories (investloan_type_brg_m5)
tb_inv_brg_m5_counts <- ffv_inv_type_by_ivars(
tstm_invest2loan2bridge_chars, "investloan_type_brg_m5"
)
tb_inv_brg_m5_shares <- ffv_inv_type_share_by_ivars(
tstm_invest2loan2bridge_chars, "investloan_type_brg_m5"
)
ffv_render_table(
tb_inv_brg_m5_counts,
caption = "Investment-level counts by investloan_type_brg_m5 and ivars",
name = "tab_inv_brg_m5_counts",
bl_save = ls_save_res[["tab_inv_brg_m5_counts"]]
)| investloan_type_brg_m5 | agg_BS_1011 | agg_BS_1012 | agg_BS_1021 |
|---|---|---|---|
| 1-brg-single-lender | 61 | 27 | 28 |
| 2-brg-baac-vilfund-combo | 41 | 31 | 29 |
| 3-brg-informal-quasifor-combo | 4 | 1 | 2 |
| 4-brg-has-informal-bridge | 295 | 189 | 176 |
| 5-brg-has-informal-in-bridge | 227 | 144 | 128 |
| Not triply-bridged | 805 | 429 | 373 |
ffv_render_table(
tb_inv_brg_m5_shares,
caption = "Investment-level shares by investloan_type_brg_m5 and ivars",
name = "tab_inv_brg_m5_shares",
bl_save = ls_save_res[["tab_inv_brg_m5_shares"]]
)| investloan_type_brg_m5 | agg_BS_1011 | agg_BS_1012 | agg_BS_1021 |
|---|---|---|---|
| 1-brg-single-lender | 0.0426 | 0.0329 | 0.0380 |
| 2-brg-baac-vilfund-combo | 0.0286 | 0.0378 | 0.0394 |
| 3-brg-informal-quasifor-combo | 0.0028 | 0.0012 | 0.0027 |
| 4-brg-has-informal-bridge | 0.2059 | 0.2302 | 0.2391 |
| 5-brg-has-informal-in-bridge | 0.1584 | 0.1754 | 0.1739 |
| Not triply-bridged | 0.5618 | 0.5225 | 0.5068 |
Eight categories (investloan_type_m8)
tb_inv_m8_counts <- ffv_inv_type_by_ivars(
tstm_invest2loan2bridge_chars, "investloan_type_m8"
)
tb_inv_m8_shares <- ffv_inv_type_share_by_ivars(
tstm_invest2loan2bridge_chars, "investloan_type_m8"
)
ffv_render_table(
tb_inv_m8_counts,
caption = "Investment-level counts by investloan_type_m8 and ivars",
name = "tab_inv_m8_counts",
bl_save = ls_save_res[["tab_inv_m8_counts"]]
)| investloan_type_m8 | agg_BS_1011 | agg_BS_1012 | agg_BS_1021 |
|---|---|---|---|
| 1-investment-no-loan | 424 | 244 | 206 |
| 2-investment-loan-a | 272 | 131 | 118 |
| 3-investment-loan-hook | 109 | 54 | 49 |
| 4-brg-single-lender | 61 | 27 | 28 |
| 5-brg-baac-vilfund-combo | 41 | 31 | 29 |
| 6-brg-informal-quasifor-combo | 4 | 1 | 2 |
| 7-brg-has-informal-bridge | 295 | 189 | 176 |
| 8-brg-has-informal-in-bridge | 227 | 144 | 128 |
ffv_render_table(
tb_inv_m8_shares,
caption = "Investment-level shares by investloan_type_m8 and ivars",
name = "tab_inv_m8_shares",
bl_save = ls_save_res[["tab_inv_m8_shares"]]
)| investloan_type_m8 | agg_BS_1011 | agg_BS_1012 | agg_BS_1021 |
|---|---|---|---|
| 1-investment-no-loan | 0.2959 | 0.2972 | 0.2799 |
| 2-investment-loan-a | 0.1898 | 0.1596 | 0.1603 |
| 3-investment-loan-hook | 0.0761 | 0.0658 | 0.0666 |
| 4-brg-single-lender | 0.0426 | 0.0329 | 0.0380 |
| 5-brg-baac-vilfund-combo | 0.0286 | 0.0378 | 0.0394 |
| 6-brg-informal-quasifor-combo | 0.0028 | 0.0012 | 0.0027 |
| 7-brg-has-informal-bridge | 0.2059 | 0.2302 | 0.2391 |
| 8-brg-has-informal-in-bridge | 0.1584 | 0.1754 | 0.1739 |
Tables: roster diagnostics
Light tallies from gateway outputs (no triply-linked df_wrk prep). Merge investment-level types onto the loan-level roster for investloan_type_m8 tabulations.
tstm_roster_with_types <- tstm_roster_invest2loan2bridge %>%
dplyr::left_join(
tstm_invest2loan2bridge_chars %>%
dplyr::select(
hhid_Num, ivars, hh_inv_asset_ctr,
investloan_type_m4, investloan_type_m8
),
by = c("hhid_Num", "ivars", "hh_inv_asset_ctr")
)
tb_roster_ivars <- tstm_roster_invest2loan2bridge %>%
dplyr::group_by(ivars) %>%
dplyr::tally(name = "n") %>%
dplyr::arrange(ivars)
tb_chars_m8 <- tstm_invest2loan2bridge_chars %>%
dplyr::group_by(investloan_type_m8) %>%
dplyr::tally(name = "n") %>%
dplyr::arrange(investloan_type_m8)
tb_roster_bl_informal <- tstm_roster_invest2loan2bridge %>%
dplyr::group_by(bl_bridge_informal) %>%
dplyr::tally(name = "n")
tb_roster_m8_informal <- tstm_roster_with_types %>%
dplyr::group_by(investloan_type_m8, bl_bridge_informal) %>%
dplyr::tally(name = "n") %>%
dplyr::arrange(investloan_type_m8, bl_bridge_informal)
ffv_render_table(
tb_roster_ivars,
caption = "Roster row counts by ivars",
name = "tab_roster_ivars",
bl_save = ls_save_res[["tab_roster_ivars"]]
)| ivars | n |
|---|---|
| agg_BS_1011 | 4876 |
| agg_BS_1012 | 2929 |
| agg_BS_1021 | 2644 |
ffv_render_table(
tb_chars_m8,
caption = "Bridge-chars investment counts by investloan_type_m8",
name = "tab_chars_m8",
bl_save = ls_save_res[["tab_chars_m8"]]
)| investloan_type_m8 | n |
|---|---|
| 1-investment-no-loan | 874 |
| 2-investment-loan-a | 521 |
| 3-investment-loan-hook | 212 |
| 4-brg-single-lender | 116 |
| 5-brg-baac-vilfund-combo | 101 |
| 6-brg-informal-quasifor-combo | 7 |
| 7-brg-has-informal-bridge | 660 |
| 8-brg-has-informal-in-bridge | 499 |
ffv_render_table(
tb_roster_bl_informal,
caption = "Roster counts by bl_bridge_informal",
name = "tab_roster_bl_informal",
bl_save = ls_save_res[["tab_roster_bl_informal"]]
)| bl_bridge_informal | n |
|---|---|
| FALSE | 7105 |
| TRUE | 1766 |
| NA | 1578 |
ffv_render_table(
tb_roster_m8_informal,
caption = "Roster counts by investloan_type_m8 and bl_bridge_informal",
name = "tab_roster_m8_informal",
bl_save = ls_save_res[["tab_roster_m8_informal"]]
)| investloan_type_m8 | bl_bridge_informal | n |
|---|---|---|
| 1-investment-no-loan | NA | 874 |
| 2-investment-loan-a | FALSE | 381 |
| 2-investment-loan-a | TRUE | 78 |
| 2-investment-loan-a | NA | 386 |
| 3-investment-loan-hook | FALSE | 447 |
| 3-investment-loan-hook | TRUE | 71 |
| 3-investment-loan-hook | NA | 38 |
| 4-brg-single-lender | FALSE | 188 |
| 5-brg-baac-vilfund-combo | FALSE | 301 |
| 5-brg-baac-vilfund-combo | TRUE | 1 |
| 5-brg-baac-vilfund-combo | NA | 6 |
| 6-brg-informal-quasifor-combo | FALSE | 17 |
| 6-brg-informal-quasifor-combo | NA | 3 |
| 7-brg-has-informal-bridge | FALSE | 3125 |
| 7-brg-has-informal-bridge | TRUE | 1616 |
| 7-brg-has-informal-bridge | NA | 162 |
| 8-brg-has-informal-in-bridge | FALSE | 2646 |
| 8-brg-has-informal-in-bridge | NA | 109 |
Session info
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8
#> [4] LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
#> [7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
#> [10] LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] kableExtra_1.4.0 glue_1.8.1 tidyr_1.3.2 dplyr_1.2.1
#> [5] PrjThaiHFID_0.2.0
#>
#> loaded via a namespace (and not attached):
#> [1] utf8_1.2.6 generics_0.1.4 xml2_1.6.0 stringi_1.8.7
#> [5] hms_1.1.4 digest_0.6.39 magrittr_2.0.5 evaluate_1.0.5
#> [9] RColorBrewer_1.1-3 fastmap_1.2.0 rprojroot_2.1.1 jsonlite_2.0.0
#> [13] purrr_1.2.2 viridisLite_0.4.3 scales_1.4.0 textshaping_1.0.5
#> [17] cli_3.6.6 rlang_1.2.0 crayon_1.5.3 bit64_4.8.2
#> [21] withr_3.0.3 yaml_2.3.12 otel_0.2.0 tools_4.6.1
#> [25] parallel_4.6.1 tzdb_0.5.0 forcats_1.0.1 vctrs_0.7.3
#> [29] R6_2.6.1 lifecycle_1.0.5 stringr_1.6.0 bit_4.6.0
#> [33] vroom_1.7.1 pkgconfig_2.0.3 pillar_1.11.1 systemfonts_1.3.2
#> [37] haven_2.5.5 xfun_0.59 tibble_3.3.1 tidyselect_1.2.1
#> [41] rstudioapi_0.19.0 knitr_1.51 farver_2.1.2 htmltools_0.5.9
#> [45] rmarkdown_2.31 svglite_2.2.2 readr_2.2.0 compiler_4.6.1