Compensation application and tolerance toward wild boars

Statistical consulting artifact for Mengxi Kou · Fresh R-first analysis release · 17 September 2026

A browsable record of the complete path from the cleaned workbook through EDA, measurement, structural models, robustness checks, visualisations, reports, and presentation.

Executive result

625matched respondents
277 / 348applicants / non-applicants
−0.142PLS direct path (95% bootstrap CI −0.194 to −0.083)
0proposed indirect intervals excluding zero

Application is negatively associated with several management-related tolerance dimensions. The four questions do not form one interchangeable scale; the safety item behaves differently. The defensible conclusion is a qualified association, not proof that compensation causes lower tolerance.

Guardrail: CE0 records application, not verified payment. County and survey period are confounded. Mediation, moderation, and AIPW-style results depend on assumptions that this cross-sectional design cannot establish.

Full HTML report

1. Data foundation and EDA

The authoritative workbook has a 625-row Input Data sheet and a 626-row Raw data sheet containing a header/response layer. All IDs match one-to-one. The duplicate Python workbook is byte-identical. The retained data contain 160 Baoxing and 465 Qingchuan respondents; reasons for excluding 49 initial interviews are not available.

Preparation choices

metricvalue
respondents625
applicants277
counties2
townships25
villages178
inside_park105
missing_village1
invalid_minimum_ratio9
invalid_desired_ratio4
damage_exceeds_area7
prevention_nonusers83
alpha_four0.337777445913655
alpha_three0.501882397127206
Application proportions differ strongly between the two counties.
The four tolerance questions measure distinct substantive dimensions.
Observed applicant/non-applicant differences motivate explicit adjustment and sensitivity checks.

Complete EDA tables cover distributions, missingness, category frequencies, correlations, county/application/park profiles, crop portfolios, raw question families, and descriptive words.

2. Measurement: EFA, CFA, and PCA

The measurement programme tests whether the proposed constructs are meaningful before using them in structural paths. EFA uses development-partition polychoric correlations, minimum-residual extraction, parallel analysis, and oblimin rotation. CFA uses ordinal WLSMV for theory models evaluated on a village-disjoint validation partition and the full sample.

Parallel analysis for the eight core attitude/cost items.
factorsRMSRTLIRMSEAadmissibledevelopment_ncomplete_nparallel_suggested
10.04482039529570470.8101226749622050.0847999943600945TRUE3162384
20.02900085783824690.9302271289961060.0512132980514669FALSE3162384
30.01943004195156261.004459251872110TRUE3162384
partitionmodelnconvergedadmissiblechisq.scaleddf.scaledcfi.scaledtli.scaledrmsea.scaledsrmr
validationtwo_factor_four309TRUETRUE45.0225714351190.9115560063840020.8696614830922130.06668420009179920.0642721291739103
validationtwo_factor_three309TRUETRUE22.2968615840679130.9670088619304250.9467066231183790.04818603015931560.0507995776059653
validationone_factor309TRUETRUE45.3634400154017200.9137962236977010.8793147131767820.06416729354540240.0656526074609448
fulltwo_factor_four625TRUETRUE62.7306928452069190.9318158829208520.8995181432517820.06073290902493320.053868972294894
fulltwo_factor_three625TRUETRUE40.6685490982776130.957067342404840.9306472454232040.05840220198360020.0483118564378772
fullone_factor625TRUETRUE62.802223102653200.9332635363997220.906568950959610.05856334444610020.0542682018826479
comparisonhtmt
Tolerance4 vs IC reflective hypothesis1.07389356252364
Tolerance3 vs IC reflective hypothesis0.92695663491981
Institutions vs IC (NOT applicable to formative blocks)

Parallel analysis suggests four factors among eight items, but the item pool cannot support a defensible four-factor CFA with three indicators per factor. The two-factor EFA has an ultra-Heywood warning. CFA shows overlap between tolerance and the proposed cost factor, while formative institutional behaviors should not be forced through reflective HTMT thresholds. The historical HTMT 1.112 is therefore a warning to inspect indicator meaning, not a reason to merge constructs automatically.

componentvariancecumulative
10.2533991715466650.253399171546665
20.1487511733426110.402150344889275
30.1262486510922080.528398995981483
40.1239971554042750.652396151385758
50.1051996943690490.757595845754807
60.1031568777510950.860752723505902
70.07890168262943640.939654406135338
80.06034559386466171
PCA variance profile: descriptive variance reduction, not latent validation.

3. Statistical analysis choices and outputs

Ordinal and score models

Each tolerance item is analyzed separately with cumulative-logit models. Adjustment families proceed from unadjusted to background, resources, and explanatory contemporaneous variables. Township-clustered uncertainty is primary; village clustering is sensitivity. Holm correction is applied within adjustment families.

outcomeadjustmentnestimatelowhighp_holm
tol1unadjusted624-0.98217234603998-1.40940089840024-0.5549437936797190.000317850535333678
tol1background624-0.633898557977934-1.00888431070471-0.2589128052511550.00757381033244225
tol1resources624-0.667679961053495-1.05206850873873-0.2832914133682610.00596930136062374
tol1explanatory622-0.468636515166197-0.899068275484797-0.03820475484759690.082621276858077
tol2unadjusted625-0.634709401776367-1.03898457944658-0.2304342241061530.0104491365099402
tol2background625-0.48444431506672-0.909138232593615-0.05975039753982490.0812399148746044
tol2resources625-0.560545523179427-0.968661646093486-0.1524294002653670.0274727650914517
tol2explanatory623-0.517287350590499-0.972274972382959-0.06229972879803920.082621276858077
tol3unadjusted6250.3957352006448840.1142109138912710.6772594873984960.0156761990919237
tol3background6250.0660896047478136-0.2586784894554420.3908576989510690.678222555065737
tol3resources6250.100021580166425-0.2384412160893130.4384843764221630.547648377855641
tol3explanatory6230.225138093238928-0.1475031427736890.5977793292515450.224450982943583
tol4unadjusted625-0.00193676683875867-0.366970819795840.3630972861183220.991353492265559
tol4background625-0.304378175612071-0.6172051619695420.008448810745400830.112017711923748
tol4resources625-0.362802702829127-0.644313032430077-0.08129237322817670.0274727650914517
tol4explanatory623-0.407464138254615-0.720741196757274-0.09418707975195580.0518450000054982
Item-level application associations with township-clustered intervals.
outcomeadjustmentestimatelowhighp
tolerance3unadjusted-0.248017678813548-0.40595401016176-0.09008134746533540.00347656546377917
tolerance3unadjusted-0.248017678813548-0.390904384615027-0.1051309730120680.000762925483329929
tolerance3background-0.284439618325466-0.452170388154703-0.1167088484962290.00184245062981851
tolerance3background-0.284439618325466-0.440087923450538-0.1287913132003940.000403646091196077
tolerance3resources-0.325253448668089-0.482622549417448-0.1678843479187310.000268722735659171
tolerance3resources-0.325253448668089-0.484083918675344-0.1664229786608347.91760109763636e-05
tolerance3explanatory-0.251936269529421-0.376990216544225-0.1268823225146170.000353224913665285
tolerance3explanatory-0.251936269529421-0.399037021097494-0.1048355179613480.000892088873753424
tolerance4unadjusted-0.113091241819314-0.2852747359186980.05909225228006940.187852536044303
tolerance4unadjusted-0.113091241819314-0.2666581054642180.04047562182558940.147907523410449
tolerance4background-0.232168998595313-0.403579736833116-0.06075826035751050.0100342161042492
tolerance4background-0.232168998595313-0.383855436141618-0.08048256104900760.00289683761136176
tolerance4resources-0.263714545764518-0.434098645940767-0.09333044558826940.00389281466208053
tolerance4resources-0.263714545764518-0.42360258080849-0.1038265107205460.00135878564166448
tolerance4explanatory-0.16880904161493-0.320622619241006-0.01699546398885330.0307817971283124
tolerance4explanatory-0.16880904161493-0.325598399131771-0.01201968409808830.0349958028145067

Bayesian complement

Four cumulative-logit township-random-intercept models use weakly informative priors and posterior predictive checks. All four passed the prespecified convergence checks.

outcomemax_rhatmin_bulk_essmin_tail_essdivergencesdiagnostics_pass
tol11.005233027069881249.544060587322062.815471040180TRUE
tol21.00288549045753849.7176564184491655.986007233330TRUE
tol31.00407938614313932.7222212304651765.343000470170TRUE
tol41.00356202703873785.6077788476831023.325124245680TRUE
outcomenmedianlowhighprob_positivediagnostics_pass
tol1624-0.625915417760975-0.978190948484404-0.2547836574699260.00025TRUE
tol2624-0.462066102778309-0.818216317961119-0.1068942823650020.005TRUE
tol36240.144156506481865-0.1772409210332810.4741695501334450.808TRUE
tol4624-0.283547740961159-0.5900458814424860.0365128274661220.044TRUE

PLS-SEM and mechanisms

PLS-SEM compares baseline, mediation, extended, four-item, and IC1-only specifications. Formative blocks are evaluated with weights/VIF; reflective blocks with loadings and reliability; structural output includes R², f², SRMR, direct paths, indirect products, and the application-by-cost interaction.

modelnadmissibleR2_TolSRMR
baseline622TRUE0.2115815718462770.0749295044818594
mediation622TRUE0.2134781508294920.090961267542986
extended622TRUE0.2335225274960350.0743030966311556
four_items622TRUE0.2176598413764050.0908943056088911
ic1_only622TRUE0.187485207900460.0923308575942925
parameterestimatelowhighp_centeredsuccessful
direct-0.142375714280746-0.1941453581561-0.09336532643906710.0004997501249375312000
indirect_IC-0.0248147144260674-0.06516272176016140.01941510184232920.2458770614692652000
indirect_PS0.0242449449234779-0.002039389826947370.04934012395125320.06596701649175412000
total-0.142945483783336-0.189623792165052-0.08282093881812340.0004997501249375312000
IC_to_Tol-0.364901886647823-0.43903521084551-0.2592634664856770.0004997501249375312000
PS_to_Tol0.0716627767800155-0.005775285758412890.1494700725932150.07296351824087962000
IB_to_Tol0.185807603456150.1108289217761670.2623163629334960.0004997501249375312000
TC_to_Tol0.0595725862437899-0.06327232261705430.09646327631310530.2183908045977012000
interaction0.100452061648737-0.06953683359172920.2650860340976340.2473763118440782000
interaction_f20.002856038439203357.07747944036374e-060.02038777153646270.315842078960522000
direct-0.142375714280746-0.193473253236042-0.09238789251420322e-044999
indirect_IC-0.0248147144260674-0.06529863997007150.01952895355360930.24844999
indirect_PS0.0242449449234779-0.00207932091988230.04897737351236480.06244999
total-0.142945483783336-0.194038160095021-0.08336814323221532e-044999
IC_to_Tol-0.364901886647823-0.439675122373746-0.2603461943290452e-044999
PS_to_Tol0.0716627767800155-0.005810661755875030.148324067809520.074999
IB_to_Tol0.185807603456150.1133706419248130.2616066486048192e-044999
TC_to_Tol0.0595725862437899-0.06880162577846550.09725088704935670.22344999
interaction0.100452061648737-0.07358878692278920.263686922169810.25364999
interaction_f20.002856038439203357.97181290944361e-060.02005828718746110.3194999
Measurement-and-structural PLS bootstrap intervals.

4. Secondary analysis, prediction, and stress tests

The secondary programme uses applicant experience, agricultural dependence, prevention adoption/effectiveness, insurance preferences, reporting contacts, information channels, crop-specific damage, seasonality, and original descriptive words. Missingness and structural skips are retained explicitly.

analysisnestimatelowhighp_BH_exploratory
application_selection6250.0867660870714014-0.03105935621636010.2045915303591630.300933327588465
applicant_timeliness2750.0129957361038684-0.09738261910541060.1233740913131470.860700071858826
applicant_satisfaction276-0.0182786380766397-0.1025119026460620.06595462649278270.746035119971714
applicant_both_experiences274-0.0433736433052398-0.1776631863114150.09091589970093520.746035119971714
livelihood_dependence6240.2503756486931210.1030199396311880.3977313577550530.030796149915641
damage_burden624-0.170855179616903-0.3493452576476640.007634898413858140.169447715037264
income_loss_burden605-0.00401220019234847-0.02151765031009410.01349324992539720.746035119971714
prevention_adoption6251.134143407240720.3579625012020771.910324313279360.0353476094539341
prevention_effectiveness_users5410.1317477731725860.04104414703487450.2224513993102970.0353476094539341
insurance_positive_wtp6250.5237850545926120.06684685926413710.9807232499210880.0897862861063989
insurance_positive_amount4920.0815702510797327-0.1350650513992640.2982055535587290.746035119971714
minimum_ratio_validated6160.00027927104636343-0.03213418587339010.03269272796611690.98595950125688
minimum_ratio_retain_flagged625-0.10657085697524-0.2461959995347180.0330542855842380.300933327588465
desired_ratio_validated6210.0125684224050953-0.03885990688546420.06399675169565470.746035119971714
desired_ratio_retain_flagged6250.0151700472510932-0.04030067969857060.07064077420075690.746035119971714
reporting_contacts6220.1304833634603260.02493067429510920.2360360526255420.074468925324147
information_channels622-0.0467977790408624-0.1375052450355990.0439096869538740.562057211090065
methodraw_questionusersnonusersmean_effectiveness_usersrecorded_cost_nmedian_recorded_cost
A现有针对野猪的事前预防策略的实施效果如何?成本如何(元/年)? - 设置障碍物(电围栏)2483772.1532258064516155500
B现有针对野猪的事前预防策略的实施效果如何?成本如何(元/年)? - 利用干扰技术,如:爆闪灯、音响等3912342.02557544757033115200
C现有针对野猪的事前预防策略的实施效果如何?成本如何(元/年)? - 人工看守3392862.9085545722713930
D现有针对野猪的事前预防策略的实施效果如何?成本如何(元/年)? - 改变作物结构(换种/弃种)565692.892857142857140
E现有针对野猪的事前预防策略的实施效果如何?成本如何(元/年)? - 生物防治,如:豢养犬只等1474782.34013605442177140
F现有针对野猪的事前预防策略的实施效果如何?成本如何(元/年)? - 异地安置或狩猎106151.10
G现有针对野猪的事前预防策略的实施效果如何?成本如何(元/年)? - 移民搬迁66191.333333333333330

Prediction and adjustment

Nested township-grouped cross-validation compares a mean benchmark, elastic net, GAM, random forest, and boosting. Fold-local preprocessing avoids leakage. Repeated township cross-fitting estimates an AIPW-style adjusted contrast; overlap and effective sample size are reported.

methodnRMSEMAER2
boosting6240.5375133802617970.4086747617160330.191919870353864
elastic_net6240.5367716938629260.4138834511220340.194148386194006
GAM6240.5406445241303360.4177095624562570.182477929779763
mean6240.5983367871882710.45228239512654-0.00130706142684667
random_forest6240.5380246869098940.4064211404914530.190381775587424
Out-of-fold predictive performance for the raw three-item score.
repetitionestimate_rawselowhighmin_propensitymax_propensityclippedeffective_sample_sizeestimand
1-0.1982683468548290.049199118500615-0.299810336761615-0.09672635694804290.1223751588679440.8714747124220810547.406612935433Cross-fitted adjusted contrast; causal interpretation requires unverified assumptions
2-0.1985591276767870.0473236988229838-0.296230441608462-0.1008878137451130.1065280587308150.8798256965256970532.453988269421Cross-fitted adjusted contrast; causal interpretation requires unverified assumptions
3-0.1931069918494180.0509899753453468-0.298345128622128-0.08786885507670850.1241606073248140.8677767793025680536.464047230177Cross-fitted adjusted contrast; causal interpretation requires unverified assumptions
4-0.1948330537690350.0496987063885076-0.297406142399049-0.09225996513902050.1023153452002880.8878085110541630538.326722795135Cross-fitted adjusted contrast; causal interpretation requires unverified assumptions
5-0.2163446859944150.0510413444626457-0.32168884341443-0.11100052857440.08912202766498990.8676947395599570535.990333158659Cross-fitted adjusted contrast; causal interpretation requires unverified assumptions
Out-of-fold application propensity overlap.

5. Specification curve and p-hacking safeguards

The specification curve varies prespecified outcomes, measurement summaries, adjustment families, economic transformations, anomaly handling, missingness sensitivity, and clustering. Exact duplicate inputs are deduplicated. Leave-one-township-out and county checks show influence and transport sensitivity.

Reasonable analytical choices shown separately by outcome; this is not proof that p-hacking is absent.
outcomeadjustmentspecificationsminmedianmaxnegative_fraction
tol1background6-0.293353291610317-0.285929664813424-0.2845377797536041
tol2background6-0.258296459555991-0.255211460041032-0.251928422515551
tol3background60.03576460532322320.03917881868583320.04946981126833260
tol4background6-0.149358486208858-0.140154015846863-0.1387361406727541
tolerance3background6-0.296172395307589-0.285041711486886-0.2844396183254661
tolerance4background6-0.235282697396808-0.232168998595313-0.2318179057556281
tol1conflict12-0.251214974130296-0.239457322548729-0.2301692086693131
tol2conflict12-0.256166869922759-0.244815052907951-0.2317377319905461
tol3conflict120.07695588509625270.08830635913748020.0971969494807810
tol4conflict12-0.153497097423365-0.143516268186744-0.1338430335308831
tolerance3conflict12-0.278740605421622-0.266626906747134-0.2528999106246991
tolerance4conflict12-0.197130594706364-0.189265905326293-0.1843625595553951
tol1explanatory24-0.17811902366503-0.170880312096222-0.1624742244006821
tol2explanatory24-0.230715030350684-0.224618965732867-0.2144185322238391
tol3explanatory240.08961139021621130.1079951832712990.1220961320674280
tol4explanatory24-0.190631774771841-0.182262976195127-0.1776326469117651
tolerance3explanatory24-0.260309485592029-0.254043650490881-0.2505990472996951
tolerance4explanatory24-0.177021511329323-0.17095115864786-0.1659886985620061
tol1none6-0.425622453614695-0.424069982177935-0.4196429999332481
tol2none6-0.318060468887704-0.308392062395252-0.3049108622544151
tol3none60.209453089780770.2153336753345510.2264496315203170
tol4none60.02376702043093080.02747631410972680.03187403819165940
tolerance3none6-0.259684722077729-0.254538607239035-0.2480176788135481
tolerance4none6-0.126699188242459-0.11338349651607-0.1130912418193141

Showing 24 rows; full CSV.

termestimateselowhighpnclusterscounty
application-0.3810748029688160.145830840408551-0.7859661260080190.02381652007038710.05922498961044911605Baoxing
application-0.3024621056173670.0914510015567174-0.493871251675309-0.1110529595594260.0037033612083945446420Qingchuan

A dated decision register, complete result tables, explicit failures, multiplicity handling, and transparent outcome definitions make selective reporting auditable. Nonsignificant MGA differences are reported as no strong evidence of difference, not equivalence.

6. Code, line by line

Open each source below to inspect its complete line-numbered implementation. The modules run in this order: preparation, EDA, measurement, regression, structural models, Bayesian models, secondary analyses, robustness, adjustment, prediction, reporting, validation.

src/fresh/common.R (33 lines)

How this script helps: Defines shared paths, packages, seeds, helpers, and the common data/model conventions used by every downstream module.

LineSource codeWhat the line does for the analysis
0001ROOT <- normalizePath(Sys.getenv("WILDBOAR_ROOT", "."), mustWork=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002.libPaths(c(file.path(ROOT, ".r-library"), .libPaths()))Executes a supporting calculation, option, or output step for this module.
0003if(!requireNamespace("digest",quietly=TRUE)) stop("digest is required; run Rscript run_project.R --restore")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0004OUT <- file.path(ROOT, "results", "fresh")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0005dir.create(OUT, recursive=TRUE, showWarnings=FALSE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0006for (s in c("tables", "figures", "models", "logs", "report", "presentation")) dir.create(file.path(OUT,s), showWarnings=FALSE)Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0007SEED <- 20260917LCreates or updates an analysis object; this stores an intermediate result used by later lines.
0008set.seed(SEED)Executes a supporting calculation, option, or output step for this module.
0009options(stringsAsFactors=FALSE, warn=1)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0010save_table <- function(x,n) {write.csv(x,file.path(OUT,"tables",paste0(n,".csv")),row.names=FALSE,na=""); invisible(x)}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0011save_model <- function(x,n) saveRDS(x,file.path(OUT,"models",paste0(n,".rds")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0012log_event <- function(stage,status,message) {Creates or updates an analysis object; this stores an intermediate result used by later lines.
0013 cat(paste(format(Sys.time(),tz="UTC"),stage,status,gsub("[\r\n]+"," ",message),sep="\t"),"\n",file=file.path(OUT,"logs","events.tsv"),append=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0014}Executes a supporting calculation, option, or output step for this module.
0015attempt <- function(label,expr) tryCatch(withCallingHandlers(expr,warning=function(w) {log_event(label,"warning",conditionMessage(w));invokeRestart("muffleWarning")}),error=function(e){log_event(label,"failed",conditionMessage(e));NULL})Creates or updates an analysis object; this stores an intermediate result used by later lines.
0016z <- function(x) as.numeric(scale(x))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0017mean_available <- function(x) {v<-rowMeans(x,na.rm=TRUE);v[!is.finite(v)]<-NA_real_;v}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0018numeric_safely <- function(x) suppressWarnings(as.numeric(x))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0019plot_save <- function(n,p,w=9,h=5) ggplot2::ggsave(file.path(OUT,"figures",paste0(n,".png")),p,width=w,height=h,dpi=160,bg="white")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0020fmt <- function(x,k=3) ifelse(is.finite(x),formatC(x,digits=k,format="f"),"NA")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0021BG <- c("county","np","age","gender","education","household_size")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0022RES <- c("log_income","agri_share","log_area","log_livestock","log_assets")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0023EXPL <- c("conflict_wb","conflict_all","log_damage","log_loss","ic","benefit","report_count","info_count","prevention_used","prevention_eff0")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0024TOLS <- c("tol1","tol2","tol3","tol4")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0025cluster_coef <- function(fit,d,term="application",group="township") {Creates or updates an analysis object; this stores an intermediate result used by later lines.
0026 v<-sandwich::vcovCL(fit,cluster=d[[group]],type="HC1",cadjust=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0027 b<-coef(fit)[term];s<-sqrt(diag(v))[term];df<-length(unique(d[[group]]))-1Creates or updates an analysis object; this stores an intermediate result used by later lines.
0028 data.frame(term=term,estimate=unname(b),se=unname(s),low=unname(b-qt(.975,df)*s),high=unname(b+qt(.975,df)*s),p=2*pt(-abs(b/s),df),n=nrow(d),clusters=df+1)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0029}Executes a supporting calculation, option, or output step for this module.
0030bootstrap_indices <- function(d,b) {Creates or updates an analysis object; this stores an intermediate result used by later lines.
0031 set.seed(SEED+b)Executes a supporting calculation, option, or output step for this module.
0032 unlist(lapply(split(seq_len(nrow(d)),d$county),function(ii){g<-unique(d$township[ii]);draw<-sample(g,length(g),TRUE);unlist(lapply(draw,function(a)ii[d$township[ii]==a]),use.names=FALSE)}),use.names=FALSE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0033}Executes a supporting calculation, option, or output step for this module.
src/fresh/prepare.R (71 lines)

How this script helps: Reads the cleaned workbook, applies only documented transformations, creates analysis variables, and writes the auditable analysis dataset.

LineSource codeWhat the line does for the analysis
0001prepare_data <- function() {Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002 source(file.path(ROOT,"src/fresh/common.R"))Imports shared functions and settings from another project module.
0003 p<-file.path(ROOT,"data/3_Data.xlsx")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0004 x<-as.data.frame(readxl::read_excel(p,sheet="Input Data"))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0005 for(v in setdiff(names(x),c("Q1_County","Q1_Township","Q1_Village")))x[[v]]<-numeric_safely(x[[v]])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0006 rr<-as.data.frame(readxl::read_excel(p,sheet="Raw data",.name_repair="unique"))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0007 labels<-as.character(rr[1,]);raw<-rr[-1,]; raw$ID<-numeric_safely(raw$ID)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0008 stopifnot(!anyDuplicated(x$ID),!anyDuplicated(raw$ID),setequal(x$ID,raw$ID))Executes a supporting calculation, option, or output step for this module.
0009 raw<-raw[match(x$ID,raw$ID),];stopifnot(identical(as.numeric(x$ID),raw$ID))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0010 raw_inventory<-data.frame(field=names(raw),label=labels,missing=vapply(raw,function(v)sum(is.na(v)|trimws(as.character(v))==""),numeric(1)),unique=vapply(raw,function(v)length(unique(na.omit(v))),integer(1)))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0011 save_table(raw_inventory,"raw_field_inventory")Executes a supporting calculation, option, or output step for this module.
0012 changes<-list(); record<-function(field,old,new,reason) {Creates or updates an analysis object; this stores an intermediate result used by later lines.
0013 changed<-xor(is.na(old),is.na(new))|(!is.na(old)&!is.na(new)&as.character(old)!=as.character(new))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0014 if(any(changed)) changes[[length(changes)+1]]<<-data.frame(ID=x$ID[changed],field=field,original=as.character(old[changed]),derived=as.character(new[changed]),reason=reason)Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0015 }Executes a supporting calculation, option, or output step for this module.
0016 d<-data.frame(ID=x$ID,county=factor(x$Q1_County),township=paste(x$Q1_County,x$Q1_Township,sep="/"),Creates or updates an analysis object; this stores an intermediate result used by later lines.
0017 village=paste(x$Q1_County,x$Q1_Township,ifelse(is.na(x$Q1_Village),paste0("missing_",x$ID),x$Q1_Village),sep="/"),Creates or updates an analysis object; this stores an intermediate result used by later lines.
0018 application=x$CE0,np=x$Q3_InNP,age=x$Q5_Age,gender=x$Q4_Gender,education=factor(x$Q6_Education),household_size=x$Q7_HouseholdPop,Creates or updates an analysis object; this stores an intermediate result used by later lines.
0019 income=x$Q8_AnnualIncome,agri_share=x$Q9_AgriProportion/100,area=x$Q11_TotalArea,livestock=x$Q13_TotalLivestock,assets=x$Q14_HouseholdAsset,Creates or updates an analysis object; this stores an intermediate result used by later lines.
0020 damage=x$TC1_DamagedArea,loss=x$TC2_EconomicLoss,benefit=x$IB,ic1=x$IC1,info_count=x$PS2,Creates or updates an analysis object; this stores an intermediate result used by later lines.
0021 minimum_ratio=x$CA1,desired_ratio=x$CA2,insurance_wtp=x$CA3,timeliness=x$CE1,satisfaction=x$CE2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0022 map<-c("非常不同意"=1,"不同意"=2,"一般"=3,"同意"=4,"非常同意"=5)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0023 for(i in 1:4) {Executes a supporting calculation, option, or output step for this module.
0024 col<-c("Tol1_5","Tol2_1","Tol3_1","Tol4_5")[i];q<-c("Q30_5","Q30_4","Q30_3","Q30_2")[i]Creates or updates an analysis object; this stores an intermediate result used by later lines.
0025 expected<-unname(map[as.character(raw[[q]])]);if(i%in%c(2,3))expected<-6-expectedCreates or updates an analysis object; this stores an intermediate result used by later lines.
0026 stopifnot(all(x[[col]][!is.na(expected)]==expected[!is.na(expected)]))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0027 d[[paste0("tol",i)]]<-x[[col]];d[[paste0("tol",i)]][is.na(raw[[q]])]<-NACreates or updates an analysis object; this stores an intermediate result used by later lines.
0028 record(paste0("tol",i),x[[col]],d[[paste0("tol",i)]],"Restore raw nonresponse; stored orientation retained")Executes a supporting calculation, option, or output step for this module.
0029 }Executes a supporting calculation, option, or output step for this module.
0030 for(i in 1:3){v<-x[[paste0("IC2_",i)]];v[v==0]<-NA;d[[paste0("word",i)]]<-v;record(paste0("word",i),x[[paste0("IC2_",i)]],v,"Zero encodes missing descriptive word")}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0031 d$word_count<-rowSums(!is.na(d[paste0("word",1:3)]));d$word_mean<-mean_available(d[paste0("word",1:3)])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0032 d$ic<-mean_available(data.frame(z(d$ic1),z(d$word_mean)))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0033 d$conflict_wb<-rowMeans(x[paste0("CP_WB",1:4)])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0034 d$conflict_all<-rowMeans(x[paste0("CP_A",1:3)])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0035 institutions<-c("保险公司","村两委","林业部门","狩猎队")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0036 reporting<-as.character(raw$Q17)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0037 for(j in seq_along(institutions))d[[paste0("report_",j)]]<-ifelse(is.na(reporting),NA,as.integer(grepl(institutions[j],reporting,fixed=TRUE)))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0038 d$report_count<-rowSums(d[paste0("report_",1:4)])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0039 d$report_contradiction<-!is.na(reporting)&grepl("不上报",reporting,fixed=TRUE)&d$report_count>0Creates or updates an analysis object; this stores an intermediate result used by later lines.
0040 record("report_count",x$PS1,d$report_count,"Reconstructed increasing count from raw choices; replaces reverse-direction PS1")Executes a supporting calculation, option, or output step for this module.
0041 for(v in c("minimum_ratio","desired_ratio")) {d[[paste0(v,"_original")]]<-d[[v]];d[[paste0(v,"_flag")]]<-d[[v]]>1|d[[v]]<0;old<-d[[v]];d[[v]][d[[paste0(v,"_flag")]]]<-NA;record(v,old,d[[v]],"Unresolved percentage outside 0..100%; retained in original field")}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0042 for(v in c("timeliness","satisfaction")){q<-if(v=="timeliness")"Q14" else "Q15";old<-d[[v]];d[[v]][is.na(raw[[q]])|d$application==0]<-NA;record(v,old,d[[v]],"Restore raw/structural nonresponse")}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0043 for(j in 1:7){ix<-which(labels==paste0("PE_",LETTERS[j]));v<-if(length(ix))numeric_safely(raw[[ix[1]]]) else rep(NA,nrow(d));d[[paste0("prevention_",LETTERS[j])]]<-vCreates or updates an analysis object; this stores an intermediate result used by later lines.
0044 # Q36 method order in raw differs from translated codebook; retain raw labels.Comment documenting the intent or an analytical decision; it does not execute.
0045 d[[paste0("prevention_cost_",j)]]<-numeric_safely(raw[[paste0("Q36_",j,"_TEXT")]])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0046 }Executes a supporting calculation, option, or output step for this module.
0047 pe<-d[paste0("prevention_",LETTERS[1:7])]Creates or updates an analysis object; this stores an intermediate result used by later lines.
0048 d$prevention_n<-rowSums(pe>0,na.rm=TRUE);d$prevention_used<-as.integer(d$prevention_n>0)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0049 pe[pe==0]<-NA;d$prevention_eff<-mean_available(pe);d$prevention_eff0<-ifelse(d$prevention_used==0,0,d$prevention_eff)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0050 record("prevention_eff",x$PE,d$prevention_eff,"Mean of used preventive methods; non-use is undefined effectiveness")Executes a supporting calculation, option, or output step for this module.
0051 for(v in c("income","area","livestock","assets","damage","loss"))d[[paste0("log_",v)]]<-log1p(d[[v]])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0052 d$tolerance3<-rowMeans(d[c("tol1","tol2","tol4")]);d$tolerance4<-rowMeans(d[TOLS])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0053 d$damage_exceeds_area<-d$damage>d$areaCreates or updates an analysis object; this stores an intermediate result used by later lines.
0054 d$damage_share<-ifelse(d$area>0,d$damage/d$area,NA)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0055 d$loss_income_share<-ifelse(d$income>0,d$loss/d$income,NA)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0056 # Search deterministic village allocations for a balanced internal validation split.Comment documenting the intent or an analytical decision; it does not execute.
0057 g<-unique(d$village);best<-Inf;allocation<-NULL;set.seed(SEED)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0058 for(k in 1:2000){dev<-sample(g,round(length(g)/2));a<-d$village%in%devCreates or updates an analysis object; this stores an intermediate result used by later lines.
0059 counts<-table(d$county,d$application);devcounts<-table(factor(d$county[a],levels=levels(d$county)),factor(d$application[a],levels=0:1))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0060 score<-sum(((devcounts-.5*counts)/pmax(counts,1))^2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0061 if(score<best){best<-score;allocation<-a}}Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0062 d$partition<-ifelse(allocation,"development","validation")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0063 stopifnot(length(intersect(d$village[allocation],d$village[!allocation]))==0,all(is.na(d$timeliness[d$application==0])))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0064 dir.create(file.path(ROOT,"data/derived"),showWarnings=FALSE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0065 write.csv(d,file.path(ROOT,"data/derived/analysis.csv"),row.names=FALSE,na="")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0066 write.csv(do.call(rbind,changes),file.path(ROOT,"data/derived/transformation_log.csv"),row.names=FALSE,na="")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0067 save_model(list(data=d,input=x,raw=raw,labels=labels),"prepared")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0068 save_table(as.data.frame(table(d$county,d$application,d$partition)),"split_balance")Executes a supporting calculation, option, or output step for this module.
0069 save_table(data.frame(field=names(d),class=vapply(d,function(v)class(v)[1],character(1)),missing=vapply(d,function(v)sum(is.na(v)),integer(1))),"derived_dictionary")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0070 log_event("prepare","success",paste(nrow(d),"respondents; village-disjoint validation split"));file.path(OUT,"models/prepared.rds")Executes a supporting calculation, option, or output step for this module.
0071}Executes a supporting calculation, option, or output step for this module.
src/fresh/eda.R (24 lines)

How this script helps: Profiles sample composition, missingness, distributions, item associations, county/application balance, and secondary questionnaire fields.

LineSource codeWhat the line does for the analysis
0001run_eda<-function(prepared) {Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002 a<-readRDS(prepared);d<-a$data;x<-a$input;raw<-a$rawCreates or updates an analysis object; this stores an intermediate result used by later lines.
0003 nums<-names(d)[vapply(d,is.numeric,logical(1))]Creates or updates an analysis object; this stores an intermediate result used by later lines.
0004 profile<-do.call(rbind,lapply(nums,function(v){y<-d[[v]];q<-quantile(y,c(0,.25,.5,.75,1),na.rm=TRUE);data.frame(variable=v,n=sum(!is.na(y)),missing=sum(is.na(y)),mean=mean(y,na.rm=TRUE),sd=sd(y,na.rm=TRUE),min=q[1],q25=q[2],median=q[3],q75=q[4],max=q[5])}))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0005 save_table(profile,"eda_numeric")Executes a supporting calculation, option, or output step for this module.
0006 categorical<-do.call(rbind,lapply(names(d),function(v){y<-d[[v]];if(length(unique(y))<=15)data.frame(variable=v,value=names(table(y,useNA="ifany")),n=as.vector(table(y,useNA="ifany")))else NULL}))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0007 save_table(categorical,"eda_categories")Executes a supporting calculation, option, or output step for this module.
0008 groups<-do.call(rbind,lapply(c("county","application","np"),function(g)do.call(rbind,lapply(nums,function(v)do.call(rbind,lapply(unique(d[[g]]),function(l){y<-d[[v]][d[[g]]==l];data.frame(grouping=g,group=as.character(l),variable=v,n=sum(!is.na(y)),mean=mean(y,na.rm=TRUE),median=median(y,na.rm=TRUE),sd=sd(y,na.rm=TRUE))}))))))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0009 save_table(groups,"eda_group_profiles")Executes a supporting calculation, option, or output step for this module.
0010 balance<-do.call(rbind,lapply(setdiff(nums,c("ID","application")),function(v){y0<-d[[v]][d$application==0];y1<-d[[v]][d$application==1];data.frame(variable=v,smd=(mean(y1,na.rm=TRUE)-mean(y0,na.rm=TRUE))/sqrt((var(y1,na.rm=TRUE)+var(y0,na.rm=TRUE))/2))}))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0011 save_table(balance,"application_balance")Executes a supporting calculation, option, or output step for this module.
0012 items<-c(TOLS,"ic1","word1","word2","word3","benefit","report_count","info_count","conflict_wb","conflict_all")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0013 for(method in c("pearson","spearman")){cc<-cor(d[items],use="pairwise.complete.obs",method=method);save_table(data.frame(variable=rownames(cc),cc),paste0("correlation_",method))}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0014 freq<-reshape(d[c("ID","application",TOLS)],varying=TOLS,v.names="response",timevar="item",times=TOLS,direction="long")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0015 p<-ggplot2::ggplot(freq,ggplot2::aes(factor(response),fill=factor(application)))+ggplot2::geom_bar(position="dodge")+ggplot2::facet_wrap(~item,scales="free_y")+ggplot2::labs(x="Stored response: higher = greater tolerance / less safety concern",y="Respondents",fill="Applied",title="Four distinct tolerance questions")+ggplot2::theme_minimal(base_size=12)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0016 plot_save("tolerance_distributions",p)Executes a supporting calculation, option, or output step for this module.
0017 plot_save("application_by_county",ggplot2::ggplot(d,ggplot2::aes(county,fill=factor(application)))+ggplot2::geom_bar(position="fill")+ggplot2::labs(y="Proportion",x=NULL,fill="Applied",title="Application rates differ strongly by county")+ggplot2::theme_minimal(base_size=13))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0018 plot_save("balance",ggplot2::ggplot(subset(balance,is.finite(smd)),ggplot2::aes(smd,reorder(variable,smd)))+ggplot2::geom_point()+ggplot2::geom_vline(xintercept=0,lty=2)+ggplot2::labs(x="Unadjusted standardized mean difference",y=NULL,title="Applicants and non-applicants differ on observed characteristics")+ggplot2::theme_minimal(base_size=10),9,9)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0019 for(q in c("Q10","Q18","Q23","Q27","Q28","Q29","Q38")){s<-as.character(raw[[q]]);terms<-unlist(strsplit(s[!is.na(s)],"[,,]"));tb<-sort(table(trimws(terms)),decreasing=TRUE);save_table(data.frame(response=names(tb),n=as.vector(tb)),paste0("raw_",q,"_frequencies"))}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0020 words<-unlist(raw[paste0("Q35_",1:3)],use.names=FALSE);tb<-sort(table(trimws(words[!is.na(words)])),decreasing=TRUE);save_table(data.frame(word=names(tb),n=as.vector(tb)),"descriptive_words")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0021 crops<-names(x)[grepl("^Q10_",names(x))];save_table(data.frame(crop=crops,households=sapply(x[crops],function(v)sum(v>0)),total_recorded_area=sapply(x[crops],sum),median_recorded_area=sapply(x[crops],median)),"crop_portfolio")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0022 metrics<-data.frame(metric=c("respondents","applicants","counties","townships","villages","inside_park","missing_village","invalid_minimum_ratio","invalid_desired_ratio","damage_exceeds_area","prevention_nonusers","alpha_four","alpha_three"),value=c(nrow(d),sum(d$application),nlevels(d$county),length(unique(d$township)),length(unique(d$village)),sum(d$np),sum(is.na(x$Q1_Village)),sum(d$minimum_ratio_flag),sum(d$desired_ratio_flag),sum(d$damage_exceeds_area),sum(d$prevention_used==0),psych::alpha(d[TOLS],check.keys=FALSE,warnings=FALSE)$total$raw_alpha,psych::alpha(d[c("tol1","tol2","tol4")],check.keys=FALSE,warnings=FALSE)$total$raw_alpha))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0023 save_table(metrics,"sample_metrics");log_event("eda","success","All derived variables and raw question families profiled");file.path(OUT,"tables/eda_numeric.csv")Executes a supporting calculation, option, or output step for this module.
0024}Executes a supporting calculation, option, or output step for this module.
src/fresh/measurement.R (44 lines)

How this script helps: Tests the proposed constructs with polychoric correlations, PCA, EFA, ordinal CFA, reliability, and discriminant-validity diagnostics.

LineSource codeWhat the line does for the analysis
0001run_measurement<-function(prepared) {Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002 d<-readRDS(prepared)$data;it<-c(TOLS,"ic1","word1","word2","word3")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0003 dev<-d[d$partition=="development",it];val<-d[d$partition=="validation",it]Creates or updates an analysis object; this stores an intermediate result used by later lines.
0004 pc<-attempt("polychoric",psych::polychoric(dev,correct=0,global=FALSE));save_model(pc,"polychoric_development")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0005 fits<-list();rows<-list();parallel_n<-NACreates or updates an analysis object; this stores an intermediate result used by later lines.
0006 if(!is.null(pc)) {Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0007 save_table(data.frame(item=it,pc$rho),"polychoric_development")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0008 png(file.path(OUT,"figures/parallel_analysis.png"),width=1000,height=650,res=130)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0009 pa<-attempt("parallel_analysis",psych::fa.parallel(dev,fa="fa",fm="minres",cor="poly",correct=0,n.iter=100,plot=TRUE,show.legend=TRUE));dev.off()Creates or updates an analysis object; this stores an intermediate result used by later lines.
0010 if(!is.null(pa))parallel_n<-pa$nfactControls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0011 for(k in 1:3){e<-attempt(paste0("EFA",k),psych::fa(pc$rho,nfactors=k,n.obs=sum(complete.cases(dev)),fm="minres",rotate="oblimin"));fits[[paste0("efa",k)]]<-eCreates or updates an analysis object; this stores an intermediate result used by later lines.
0012 if(!is.null(e)){ll<-unclass(e$loadings);save_table(data.frame(item=rownames(ll),ll,communality=e$communality),paste0("efa_loadings_",k));rows[[length(rows)+1]]<-data.frame(factors=k,RMSR=e$rms,TLI=e$TLI,RMSEA=e$RMSEA[1],admissible=all(e$communality<=1 & e$communality>=0),development_n=nrow(dev),complete_n=sum(complete.cases(dev)),parallel_suggested=parallel_n)}}Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0013 }Executes a supporting calculation, option, or output step for this module.
0014 if(length(rows))save_table(do.call(rbind,rows),"efa_comparison")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0015 pca<-prcomp(na.omit(d[it]),center=TRUE,scale.=TRUE);save_model(pca,"pca");save_table(data.frame(component=seq_along(pca$sdev),variance=pca$sdev^2/sum(pca$sdev^2),cumulative=cumsum(pca$sdev^2/sum(pca$sdev^2))),"pca_variance");save_table(data.frame(item=rownames(pca$rotation),pca$rotation),"pca_loadings")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0016 models<-list(two_factor_four="Tolerance =~ tol1 + tol2 + tol3 + tol4\nIntangible =~ ic1 + word1 + word2 + word3",Creates or updates an analysis object; this stores an intermediate result used by later lines.
0017 two_factor_three="Tolerance =~ tol1 + tol2 + tol4\nIntangible =~ ic1 + word1 + word2 + word3",Creates or updates an analysis object; this stores an intermediate result used by later lines.
0018 one_factor="Common =~ tol1 + tol2 + tol3 + tol4 + ic1 + word1 + word2 + word3")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0019 # Freeze a development-derived loading pattern before validation; no modification-index edits.Comment documenting the intent or an analytical decision; it does not execute.
0020 if(is.finite(parallel_n)&&parallel_n%in%1:3&&!is.null(fits[[paste0("efa",parallel_n)]])){Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0021 L<-unclass(fits[[paste0("efa",parallel_n)]]$loadings);membership<-max.col(abs(L));strong<-apply(abs(L),1,max)>=.4Creates or updates an analysis object; this stores an intermediate result used by later lines.
0022 groups<-split(rownames(L)[strong],membership[strong]);groups<-groups[lengths(groups)>=3]Creates or updates an analysis object; this stores an intermediate result used by later lines.
0023 if(length(groups))models$efa_frozen<-paste(vapply(seq_along(groups),function(i)paste0("F",i," =~ ",paste(groups[[i]],collapse=" + ")),character(1)),collapse="\n")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0024 else log_event("EFA_to_CFA","not_identified","No factor has >=3 primary loadings >=.4; no EFA-derived CFA fitted")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0025 }Executes a supporting calculation, option, or output step for this module.
0026 if(is.finite(parallel_n)&&parallel_n>3)log_event("EFA_to_CFA","unsupported","Parallel analysis suggests >3 factors among only eight items; no identified >=3-indicator-per-factor CFA inferred")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0027 save_table(data.frame(model=names(models),syntax=unlist(models)),"cfa_prespecified_syntax")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0028 cfrows<-list();loadings<-list()Creates or updates an analysis object; this stores an intermediate result used by later lines.
0029 for(part in c("validation","full"))for(n in names(models)){Executes a supporting calculation, option, or output step for this module.
0030 dd<-if(part=="validation")d[d$partition=="validation",] else dCreates or updates an analysis object; this stores an intermediate result used by later lines.
0031 fit<-attempt(paste("CFA",part,n),lavaan::cfa(models[[n]],data=dd,ordered=intersect(it,lavaan::lavNames(lavaan::lavaanify(models[[n]]),type="ov")),estimator="WLSMV",std.lv=TRUE,missing="pairwise"))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0032 if(!is.null(fit)){Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0033 fits[[paste(part,n,sep="_")]]<-fit;ok<-isTRUE(lavaan::lavInspect(fit,"converged"));admissible<-attempt("CFA_postcheck",lavaan::lavInspect(fit,"post.check"))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0034 fm<-attempt("CFA_fitmeasures",lavaan::fitMeasures(fit,c("chisq.scaled","df.scaled","cfi.scaled","tli.scaled","rmsea.scaled","srmr")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0035 if(!is.null(fm))cfrows[[length(cfrows)+1]]<-data.frame(partition=part,model=n,n=lavaan::lavInspect(fit,"nobs"),converged=ok,admissible=isTRUE(admissible),as.list(fm),check.names=FALSE)Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0036 pe<-attempt("CFA_parameters",lavaan::parameterEstimates(fit,standardized=TRUE));if(!is.null(pe)){pe$model<-n;pe$partition<-part;loadings[[length(loadings)+1]]<-pe}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0037 }Executes a supporting calculation, option, or output step for this module.
0038 }Executes a supporting calculation, option, or output step for this module.
0039 if(length(cfrows))save_table(do.call(rbind,cfrows),"cfa_fit");if(length(loadings))save_table(do.call(rbind,loadings),"cfa_parameters")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0040 # HTMT is a descriptive diagnostic for the proposed reflective cost/tolerance blocks only.Comment documenting the intent or an analytical decision; it does not execute.
0041 htmt<-function(a,b){C<-abs(cor(d[c(a,b)],use="pairwise.complete.obs"));na<-length(a);nb<-length(b);A<-C[seq_len(na),seq_len(na)];B<-C[na+seq_len(nb),na+seq_len(nb)];mean(C[seq_len(na),na+seq_len(nb)])/sqrt(mean(A[lower.tri(A)])*mean(B[lower.tri(B)]))}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0042 save_table(data.frame(comparison=c("Tolerance4 vs IC reflective hypothesis","Tolerance3 vs IC reflective hypothesis","Institutions vs IC (NOT applicable to formative blocks)"),htmt=c(htmt(TOLS,c("ic1","word1","word2","word3")),htmt(c("tol1","tol2","tol4"),c("ic1","word1","word2","word3")),NA)),"htmt_scope")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0043 save_model(fits,"measurement_fits");log_event("measurement","success","EFA/PCA and frozen theory/validation CFA attempted; consult diagnostics");file.path(OUT,"models/measurement_fits.rds")Executes a supporting calculation, option, or output step for this module.
0044}Executes a supporting calculation, option, or output step for this module.
src/fresh/regression.R (40 lines)

How this script helps: Fits item-level and score-level ordinal/linear association models with prespecified adjustment families and clustered uncertainty.

LineSource codeWhat the line does for the analysis
0001run_regression<-function(prepared) {Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002 d<-readRDS(prepared)$data;rows<-list();probs<-list();nominal<-list();fits<-list()Creates or updates an analysis object; this stores an intermediate result used by later lines.
0003 sets<-list(unadjusted=character(),background=BG,resources=c(BG,RES),explanatory=c(BG,RES,EXPL))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0004 for(y in TOLS)for(s in names(sets)){Executes a supporting calculation, option, or output step for this module.
0005 vars<-unique(c(y,"application",sets[[s]],"township","village"));dd<-d[complete.cases(d[vars]),vars];dd[[y]]<-ordered(dd[[y]])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0006 f<-reformulate(c("application",sets[[s]]),response=y)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0007 fit<-attempt(paste("ordinal",y,s),MASS::polr(f,data=dd,Hess=TRUE,method="logistic"))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0008 if(!is.null(fit)){Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0009 fits[[paste(y,s,sep="_")]]<-fit;r<-attempt("ordinal_cluster",cluster_coef(fit,dd));if(!is.null(r)){r$outcome<-y;r$adjustment<-s;r$model<-"cumulative_logit";rows[[length(rows)+1]]<-r}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0010 a<-dd;b<-dd;a$application<-0;b$application<-1Creates or updates an analysis object; this stores an intermediate result used by later lines.
0011 p0<-predict(fit,a,type="probs");p1<-predict(fit,b,type="probs")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0012 probs[[length(probs)+1]]<-data.frame(outcome=y,adjustment=s,category=colnames(p0),p_no_application=colMeans(p0),p_application=colMeans(p1),difference=colMeans(p1-p0))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0013 }Executes a supporting calculation, option, or output step for this module.
0014 if(s=="background"){Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0015 cl<-attempt(paste("clm",y),do.call(ordinal::clm,list(formula=f,data=dd)));nt<-if(!is.null(cl))attempt("proportional_odds",ordinal::nominal_test(cl,scope=~application)) else NULLCreates or updates an analysis object; this stores an intermediate result used by later lines.
0016 if(!is.null(nt)){nt<-as.data.frame(nt);nt$term<-rownames(nt);nt$outcome<-y;nominal[[length(nominal)+1]]<-ntControls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0017 # Application-specific nonparallel alternative is fixed in advance; do not change all slopes on p-values.Comment documenting the intent or an analytical decision; it does not execute.
0018 alt<-attempt(paste("partial_PO",y),do.call(ordinal::clm,list(formula=f,nominal=~application,data=dd)));fits[[paste0(y,"_partial_PO")]]<-altCreates or updates an analysis object; this stores an intermediate result used by later lines.
0019 if(!is.null(alt)){pa<-summary(alt)$coefficients;save_table(data.frame(term=rownames(pa),pa),paste0("partial_PO_",y))}Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0020 }Executes a supporting calculation, option, or output step for this module.
0021 }Executes a supporting calculation, option, or output step for this module.
0022 }Executes a supporting calculation, option, or output step for this module.
0023 if(length(rows)){rr<-do.call(rbind,rows);rr$p_holm<-ave(rr$p,rr$adjustment,FUN=function(p)p.adjust(p,"holm"));rr$odds_ratio<-exp(rr$estimate);save_table(rr,"ordinal_associations")}Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0024 if(length(probs))save_table(do.call(rbind,probs),"ordinal_probabilities")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0025 if(length(nominal))save_table(do.call(rbind,nominal),"proportional_odds_tests")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0026 rr<-list()Creates or updates an analysis object; this stores an intermediate result used by later lines.
0027 for(y in c("tolerance3","tolerance4"))for(s in names(sets)){Executes a supporting calculation, option, or output step for this module.
0028 vars<-unique(c(y,"application",sets[[s]],"township","village"));dd<-d[complete.cases(d[vars]),vars];dd[[y]]<-z(dd[[y]])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0029 fit<-lm(reformulate(c("application",sets[[s]]),y),dd);fits[[paste(y,s,sep="_")]]<-fitCreates or updates an analysis object; this stores an intermediate result used by later lines.
0030 for(g in c("township","village")){r<-cluster_coef(fit,dd,group=g);r$outcome<-y;r$adjustment<-s;r$covariance<-g;rr[[length(rr)+1]]<-r}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0031 if(s=="resources"){Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0032 gam<-attempt(paste("GAM",y),mgcv::gam(as.formula(paste(y,"~ application + county + np + gender + education + household_size + s(age,k=5) + s(log_income,k=5) + agri_share + s(log_area,k=5) + log_livestock + log_assets")),data=dd,method="REML"));fits[[paste0(y,"_gam")]]<-gamCreates or updates an analysis object; this stores an intermediate result used by later lines.
0033 if(!is.null(gam)){sm<-summary(gam);save_table(data.frame(term=rownames(sm$p.table),sm$p.table),paste0("gam_",y,"_parametric"));save_table(data.frame(term=rownames(sm$s.table),sm$s.table),paste0("gam_",y,"_smooths"))}Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0034 }Executes a supporting calculation, option, or output step for this module.
0035 }Executes a supporting calculation, option, or output step for this module.
0036 rr<-do.call(rbind,rr);save_table(rr,"score_associations")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0037 plot_save("primary_ordinal",ggplot2::ggplot(subset(do.call(rbind,rows),adjustment=="background"),ggplot2::aes(estimate,outcome,xmin=low,xmax=high))+ggplot2::geom_pointrange()+ggplot2::geom_vline(xintercept=0,lty=2)+ggplot2::labs(x="Application log odds ratio (95% township-clustered CI)",y=NULL,title="Item-level associations need not share the same direction")+ggplot2::theme_minimal(base_size=12))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0038 plot_save("score_associations",ggplot2::ggplot(subset(rr,covariance=="township"),ggplot2::aes(estimate,adjustment,xmin=low,xmax=high,color=outcome))+ggplot2::geom_pointrange(position=ggplot2::position_dodge(width=.4))+ggplot2::geom_vline(xintercept=0,lty=2)+ggplot2::labs(x="Application contrast in outcome SD",y=NULL,title="Composite associations depend on outcome and adjustment")+ggplot2::theme_minimal(base_size=12))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0039 save_model(fits,"regression_fits");file.path(OUT,"models/regression_fits.rds")Executes a supporting calculation, option, or output step for this module.
0040}Executes a supporting calculation, option, or output step for this module.
src/fresh/structural.R (74 lines)

How this script helps: Estimates PLS-SEM measurement and structural paths, bootstrap intervals, mediation products, moderation, and model-quality diagnostics.

LineSource codeWhat the line does for the analysis
0001pls_model_syntax<-function(kind="mediation") {Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002 measurement<-"Tol =~ tol1 + tol2 + tol4\nIC <~ ic1 + word_mean\nPS <~ report_count + info_count\nTC <~ log_damage + log_loss\nIB <~ benefit\nCE <~ application"Creates or updates an analysis object; this stores an intermediate result used by later lines.
0003 if(kind=="four_items")measurement<-sub("Tol =~ tol1 + tol2 + tol4","Tol =~ tol1 + tol2 + tol3 + tol4",measurement,fixed=TRUE)Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0004 if(kind=="ic1_only")measurement<-sub("IC <~ ic1 + word_mean","IC <~ ic1",measurement,fixed=TRUE)Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0005 structure<-"Tol ~ CE + IC + PS + TC + IB"Creates or updates an analysis object; this stores an intermediate result used by later lines.
0006 if(kind!="baseline")structure<-paste(structure,"IC ~ CE\nPS ~ CE",sep="\n")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0007 if(kind=="extended"){Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0008 measurement<-paste(measurement,"Conflict <~ conflict_wb + conflict_all\nUse <~ prevention_used\nEff <~ prevention_eff0",sep="\n")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0009 structure<-"Tol ~ CE + IC + PS + TC + IB + Conflict + Use + Eff\nIC ~ CE + Conflict + Use + Eff\nPS ~ CE + Conflict\nTC ~ Conflict\nIB ~ Conflict"Creates or updates an analysis object; this stores an intermediate result used by later lines.
0010 }Executes a supporting calculation, option, or output step for this module.
0011 paste(measurement,structure,sep="\n")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0012}Executes a supporting calculation, option, or output step for this module.
0013pls_fit<-function(dd,syntax) cSEM::csem(.data=dd,.model=syntax,.disattenuate=FALSE,.iter_max=300)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0014oriented<-function(f,dd){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0015 scores<-f$Estimates$Construct_scores;P<-f$Estimates$Path_estimatesCreates or updates an analysis object; this stores an intermediate result used by later lines.
0016 anchors<-c(Tol="tol1",IC="ic1",PS="report_count",TC="log_loss",IB="benefit",CE="application",Conflict="conflict_wb",Use="prevention_used",Eff="prevention_eff0")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0017 signs<-sapply(colnames(scores),function(n){v<-cor(scores[,n],dd[[anchors[[n]]]]);ifelse(is.finite(v)&&v<0,-1,1)})Creates or updates an analysis object; this stores an intermediate result used by later lines.
0018 scores<-sweep(scores,2,signs,"*");P<-P*outer(signs[rownames(P)],signs[colnames(P)])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0019 list(scores=as.data.frame(scores),paths=P)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0020}Executes a supporting calculation, option, or output step for this module.
0021pls_statistics<-function(f,dd){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0022 o<-oriented(f,dd);P<-o$paths;s<-o$scoresCreates or updates an analysis object; this stores an intermediate result used by later lines.
0023 # Two-stage observed product of newly estimated scores in every bootstrap.Comment documenting the intent or an analytical decision; it does not execute.
0024 s$application<-dd$application;s$ic_center<-s$IC-mean(s$IC)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0025 base<-lm(Tol~application+IC+PS+TC+IB,data=s)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0026 mod<-lm(Tol~application+IC+PS+TC+IB+application:ic_center,data=s)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0027 r0<-summary(base)$r.squared;r1<-summary(mod)$r.squaredCreates or updates an analysis object; this stores an intermediate result used by later lines.
0028 c(direct=P["Tol","CE"],indirect_IC=P["IC","CE"]*P["Tol","IC"],indirect_PS=P["PS","CE"]*P["Tol","PS"],Creates or updates an analysis object; this stores an intermediate result used by later lines.
0029 total=P["Tol","CE"]+P["IC","CE"]*P["Tol","IC"]+P["PS","CE"]*P["Tol","PS"],Creates or updates an analysis object; this stores an intermediate result used by later lines.
0030 IC_to_Tol=P["Tol","IC"],PS_to_Tol=P["Tol","PS"],IB_to_Tol=P["Tol","IB"],TC_to_Tol=P["Tol","TC"],Creates or updates an analysis object; this stores an intermediate result used by later lines.
0031 interaction=unname(coef(mod)["application:ic_center"]),interaction_f2=(r1-r0)/(1-r1))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0032}Executes a supporting calculation, option, or output step for this module.
0033run_structural<-function(prepared){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0034 d<-readRDS(prepared)$dataCreates or updates an analysis object; this stores an intermediate result used by later lines.
0035 fields<-c("tol1","tol2","tol3","tol4","ic1","word_mean","report_count","info_count","log_damage","log_loss","benefit","application","conflict_wb","conflict_all","prevention_used","prevention_eff0","township","county")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0036 dd<-d[complete.cases(d[fields]),fields];fits<-list();paths<-list();quality<-list()Creates or updates an analysis object; this stores an intermediate result used by later lines.
0037 for(kind in c("baseline","mediation","extended","four_items","ic1_only")){Executes a supporting calculation, option, or output step for this module.
0038 f<-attempt(paste("PLS",kind),pls_fit(dd,pls_model_syntax(kind)));if(is.null(f))next;fits[[kind]]<-fCreates or updates an analysis object; this stores an intermediate result used by later lines.
0039 P<-oriented(f,dd)$paths;ix<-which(f$Information$Model$structural!=0,arr.ind=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0040 paths[[kind]]<-data.frame(model=kind,to=rownames(P)[ix[,1]],from=colnames(P)[ix[,2]],estimate=P[ix])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0041 a<-attempt("PLS_assessment",cSEM::assess(f,.quality_criterion=c("r2","f2","ave","reliability","vifmodeB","srmr")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0042 save_model(a,paste0("pls_assessment_",kind));capture.output(print(a),file=file.path(OUT,"logs",paste0("pls_assessment_",kind,".txt")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0043 quality[[kind]]<-data.frame(model=kind,n=nrow(dd),admissible=!any(cSEM::verify(f)),R2_Tol=f$Estimates$R2["Tol"],SRMR=if(!is.null(a))a$SRMR else NA)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0044 save_table(data.frame(construct=rownames(f$Estimates$Weight_estimates),f$Estimates$Weight_estimates),paste0("pls_weights_",kind))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0045 save_table(data.frame(construct=rownames(f$Estimates$Loading_estimates),f$Estimates$Loading_estimates),paste0("pls_loadings_",kind))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0046 }Executes a supporting calculation, option, or output step for this module.
0047 save_table(do.call(rbind,paths),"pls_paths");save_table(do.call(rbind,quality),"pls_quality");save_model(fits,"pls_fits")Executes a supporting calculation, option, or output step for this module.
0048 f<-fits$mediation;if(is.null(f))stop("Primary PLS fit failed")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0049 point<-pls_statistics(f,dd);B<-5000LCreates or updates an analysis object; this stores an intermediate result used by later lines.
0050 bp<-file.path(OUT,"models/pls_cluster_bootstrap.rds")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0051 if(file.exists(bp))boots<-readRDS(bp)else{Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0052 boots<-parallel::mclapply(seq_len(B),function(b){idx<-bootstrap_indices(dd,b);db<-dd[idx,];Creates or updates an analysis object; this stores an intermediate result used by later lines.
0053 tryCatch({ff<-suppressWarnings(pls_fit(db,pls_model_syntax()));if(any(cSEM::verify(ff)))stop("Inadmissible PLS fit");list(values=pls_statistics(ff,db),failure="")},error=function(e)list(values=setNames(rep(NA,length(point)),names(point)),failure=conditionMessage(e)))},mc.cores=8,mc.set.seed=FALSE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0054 saveRDS(boots,bp)Persists a table, model, figure, or report artifact so results are inspectable outside R.
0055 }Executes a supporting calculation, option, or output step for this module.
0056 bm<-do.call(rbind,lapply(boots,`[[`,"values"));save_table(data.frame(replicate=seq_len(B),bm,failure=vapply(boots,`[[`,character(1),"failure")),"pls_bootstrap_replicates")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0057 ci<-do.call(rbind,lapply(c(2000,5000),function(n)do.call(rbind,lapply(names(point),function(p){v<-bm[seq_len(n),p];good<-is.finite(v);q<-quantile(v[good],c(.025,.975));data.frame(parameter=p,estimate=point[p],low=q[1],high=q[2],p_centered=(1+sum(abs(v[good]-point[p])>=abs(point[p])))/(sum(good)+1),requested=n,successful=sum(good),failure_rate=mean(!good))}))))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0058 ci$p_centered[ci$parameter=="interaction_f2"]<-NA_real_Creates or updates an analysis object; this stores an intermediate result used by later lines.
0059 save_table(ci,"pls_bootstrap_summary")Executes a supporting calculation, option, or output step for this module.
0060 plot_save("pls_paths",ggplot2::ggplot(subset(ci,requested==5000&parameter!="interaction_f2"),ggplot2::aes(estimate,reorder(parameter,estimate),xmin=low,xmax=high))+ggplot2::geom_pointrange()+ggplot2::geom_vline(xintercept=0,lty=2)+ggplot2::labs(x="PLS path / two-stage interaction (different scales; see report)",y=NULL,title="Cluster-bootstrap uncertainty includes measurement estimation")+ggplot2::theme_minimal(base_size=11))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0061 # Assessment of compositional invariance is a conventional individual-permutation diagnostic.Comment documenting the intent or an analytical decision; it does not execute.
0062 gm<-"Tol =~ tol1 + tol2 + tol4\nIC <~ ic1 + word_mean\nPS <~ report_count + info_count\nTC <~ log_damage + log_loss\nIB <~ benefit\nTol ~ IC + PS + TC + IB"Creates or updates an analysis object; this stores an intermediate result used by later lines.
0063 gs<-split(dd,dd$application);multi<-attempt("MGA_base",cSEM::csem(.data=gs,.model=gm,.disattenuate=FALSE,.iter_max=300))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0064 if(!is.null(multi)){Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0065 mic<-attempt("MICOM",cSEM::testMICOM(multi,.R=999,.seed=SEED,.verbose=FALSE,.handle_inadmissibles="drop"));save_model(mic,"micom");capture.output(print(mic),file=file.path(OUT,"logs/micom.txt"))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0066 # Cluster bootstrap path differences; grouping exposure is deliberately excluded.Comment documenting the intent or an analytical decision; it does not execute.
0067 extract<-function(db){g<-split(db,db$application);if(length(g)!=2)stop("Absent group");p<-lapply(g,function(a)oriented(pls_fit(a,gm),a)$paths["Tol",c("IC","PS","TC","IB")]);p[[2]]-p[[1]]}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0068 delta<-extract(dd)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0069 bootg<-parallel::mclapply(1:2000,function(b)tryCatch(suppressWarnings(extract(dd[bootstrap_indices(dd,b+10000),])),error=function(e)setNames(rep(NA,4),names(delta))),mc.cores=8,mc.set.seed=FALSE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0070 mat<-do.call(rbind,bootg);save_model(mat,"mga_cluster_bootstrap")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0071 save_table(data.frame(path=names(delta),difference=delta,low=apply(mat,2,quantile,.025,na.rm=TRUE),high=apply(mat,2,quantile,.975,na.rm=TRUE),successful=colSums(is.finite(mat)),interpretation="Group-standardized path differences; conditional on adequate invariance; no equivalence claim"),"mga_cluster_differences")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0072 }Executes a supporting calculation, option, or output step for this module.
0073 file.path(OUT,"tables/pls_bootstrap_summary.csv")Executes a supporting calculation, option, or output step for this module.
0074}Executes a supporting calculation, option, or output step for this module.
src/fresh/bayesian.R (29 lines)

How this script helps: Fits complementary Bayesian cumulative-logit models with township random intercepts and posterior predictive checks.

LineSource codeWhat the line does for the analysis
0001run_bayesian<-function(prepared) {Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002 d<-readRDS(prepared)$data;dd<-d[complete.cases(d[c(TOLS,BG,"application","township")]),]Creates or updates an analysis object; this stores an intermediate result used by later lines.
0003 dd$age<-z(dd$age);dd$household_size<-z(dd$household_size)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0004 rows<-list();diagnostics<-list();fit<-NULLCreates or updates an analysis object; this stores an intermediate result used by later lines.
0005 for(y in TOLS){dd$response<-ordered(dd[[y]],levels=1:5)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0006 path<-file.path(OUT,"models",paste0("bayes_",y))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0007 if(file.exists(paste0(path,".rds"))) f<-readRDS(paste0(path,".rds")) else {Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0008 f<-attempt(paste0("Bayes_",y),brms::brm(response~application+county+np+age+gender+education+household_size+(1|township),data=dd,Creates or updates an analysis object; this stores an intermediate result used by later lines.
0009 family=brms::cumulative("logit"),prior=c(brms::prior(normal(0,1),class="b"),brms::prior(exponential(1),class="sd")),Creates or updates an analysis object; this stores an intermediate result used by later lines.
0010 chains=4,cores=4,iter=2000,warmup=1000,seed=SEED,control=list(adapt_delta=.99,max_treedepth=12),Creates or updates an analysis object; this stores an intermediate result used by later lines.
0011 refresh=0,file=path,save_pars=brms::save_pars(all=TRUE)))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0012 }Executes a supporting calculation, option, or output step for this module.
0013 if(is.null(f))nextControls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0014 sm<-posterior::summarise_draws(posterior::as_draws_array(f));np<-brms::nuts_params(f);div<-sum(np$Value[np$Parameter=="divergent__"])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0015 good<-max(sm$rhat,na.rm=TRUE)<=1.01&&min(sm$ess_bulk,na.rm=TRUE)>=400&&min(sm$ess_tail,na.rm=TRUE)>=400&&div==0Creates or updates an analysis object; this stores an intermediate result used by later lines.
0016 diagnostics[[length(diagnostics)+1]]<-data.frame(outcome=y,max_rhat=max(sm$rhat,na.rm=TRUE),min_bulk_ess=min(sm$ess_bulk,na.rm=TRUE),min_tail_ess=min(sm$ess_tail,na.rm=TRUE),divergences=div,diagnostics_pass=good)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0017 b<-posterior::as_draws_df(f)$b_application;q<-quantile(b,c(.025,.5,.975))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0018 rows[[length(rows)+1]]<-data.frame(outcome=y,n=nrow(dd),median=q[2],low=q[1],high=q[3],prob_positive=mean(b>0),diagnostics_pass=good)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0019 p<-brms::pp_check(f,type="bars",ndraws=100);plot_save(paste0("bayes_ppc_",y),p)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0020 # Cluster-marginal contrast: include estimated township effects at each observed township.Comment documenting the intent or an analytical decision; it does not execute.
0021 a<-dd;bdata<-dd;a$application<-0;bdata$application<-1Creates or updates an analysis object; this stores an intermediate result used by later lines.
0022 p0<-brms::posterior_epred(f,newdata=a,draw_ids=seq_len(500));p1<-brms::posterior_epred(f,newdata=bdata,draw_ids=seq_len(500))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0023 contrasts<-apply(p1-p0,c(1,3),mean)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0024 save_table(data.frame(category=1:5,mean=colMeans(contrasts),low=apply(contrasts,2,quantile,.025),high=apply(contrasts,2,quantile,.975)),paste0("bayes_probabilities_",y))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0025 }Executes a supporting calculation, option, or output step for this module.
0026 if(length(rows))save_table(do.call(rbind,rows),"bayesian_associations")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0027 if(length(diagnostics))save_table(do.call(rbind,diagnostics),"bayesian_diagnostics")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0028 file.path(OUT,"tables/bayesian_diagnostics.csv")Executes a supporting calculation, option, or output step for this module.
0029}Executes a supporting calculation, option, or output step for this module.
src/fresh/prediction.R (73 lines)

How this script helps: Runs leakage-safe grouped cross-validation and out-of-fold prediction/importance analyses for descriptive transportability.

LineSource codeWhat the line does for the analysis
0001group_folds<-function(g,k=5,seed=SEED){set.seed(seed);u<-sample(unique(g));map<-setNames(rep(seq_len(k),length.out=length(u)),u);unname(map[g])}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002design_matrix<-function(d,features){model.matrix(reformulate(features),data=d,na.action=na.pass)[,-1,drop=FALSE]}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0003preprocess<-function(a,b){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0004 for(j in seq_len(ncol(a))){med<-median(a[,j],na.rm=TRUE);if(!is.finite(med))med<-0;a[is.na(a[,j]),j]<-med;b[is.na(b[,j]),j]<-med}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0005 mu<-colMeans(a);ss<-apply(a,2,sd);ss[!is.finite(ss)|ss==0]<-1Creates or updates an analysis object; this stores an intermediate result used by later lines.
0006 list(train=sweep(sweep(a,2,mu,"-"),2,ss,"/"),test=sweep(sweep(b,2,mu,"-"),2,ss,"/"))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0007}Executes a supporting calculation, option, or output step for this module.
0008learn_predict<-function(method,par,a,y,b){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0009 pp<-preprocess(a,b);a<-pp$train;b<-pp$testCreates or updates an analysis object; this stores an intermediate result used by later lines.
0010 if(method=="mean")return(rep(mean(y),nrow(b)))Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0011 if(method=="elastic_net"){f<-glmnet::glmnet(a,y,alpha=par$alpha,lambda=par$lambda,standardize=FALSE);return(as.numeric(predict(f,b,s=par$lambda)))}Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0012 if(method=="random_forest"){f<-ranger::ranger(x=as.data.frame(a),y=y,num.trees=400,min.node.size=par$node,mtry=min(ncol(a),par$mtry),seed=SEED,num.threads=1);return(predict(f,as.data.frame(b))$predictions)}Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0013 if(method=="boosting"){f<-gbm::gbm.fit(x=a,y=y,distribution="gaussian",n.trees=par$trees,interaction.depth=par$depth,shrinkage=.03,n.minobsinnode=15,bag.fraction=.8,verbose=FALSE);return(as.numeric(predict(f,b,n.trees=par$trees)))}Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0014 if(method=="GAM"){Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0015 aa<-as.data.frame(a);bb<-as.data.frame(b);names(aa)<-names(bb)<-make.names(colnames(a));aa$y<-yCreates or updates an analysis object; this stores an intermediate result used by later lines.
0016 terms<-names(bb);terms[terms%in%c("age","log_income","log_area")]<-paste0("s(",terms[terms%in%c("age","log_income","log_area")],",k=4)")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0017 f<-mgcv::gam(as.formula(paste("y ~",paste(terms,collapse=" + "))),data=aa,method="REML",select=TRUE);return(as.numeric(predict(f,bb)))}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0018}Executes a supporting calculation, option, or output step for this module.
0019run_prediction<-function(prepared){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0020 d<-readRDS(prepared)$data;d<-d[!is.na(d$tolerance3),];features<-c("application",BG,RES,"conflict_wb","conflict_all","log_damage","log_loss","ic1","word_mean","benefit","report_count","info_count","prevention_used","prevention_eff0")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0021 # model.frame with na.pass preserves rows; all categorical levels are questionnaire-defined.Comment documenting the intent or an analytical decision; it does not execute.
0022 mf<-model.frame(reformulate(features),data=d,na.action=na.pass);X<-model.matrix(reformulate(features),mf)[,-1,drop=FALSE];y<-d$tolerance3Creates or updates an analysis object; this stores an intermediate result used by later lines.
0023 folds<-group_folds(d$township);save_table(data.frame(ID=d$ID,township=d$township,outer_fold=folds),"prediction_folds")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0024 grids<-list(mean=list(list()),elastic_net=lapply(1:6,function(i){g<-expand.grid(alpha=c(0,.5,1),lambda=c(.01,.1));as.list(g[i,])}),GAM=list(list()),Creates or updates an analysis object; this stores an intermediate result used by later lines.
0025 random_forest=lapply(1:4,function(i){g<-expand.grid(node=c(5,15),mtry=c(5,10));as.list(g[i,])}),boosting=lapply(1:4,function(i){g<-expand.grid(trees=c(100,300),depth=c(1,2));as.list(g[i,])}))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0026 preds<-list();selected<-list();importance<-list()Creates or updates an analysis object; this stores an intermediate result used by later lines.
0027 for(k in 1:5){tr<-which(folds!=k);te<-which(folds==k);inner<-group_folds(d$township[tr],3,SEED+k)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0028 stopifnot(!length(intersect(d$township[tr],d$township[te])))Executes a supporting calculation, option, or output step for this module.
0029 for(method in names(grids)){Executes a supporting calculation, option, or output step for this module.
0030 grid<-grids[[method]];loss<-sapply(grid,function(par)mean(sapply(1:3,function(j){ia<-tr[inner!=j];ib<-tr[inner==j];p<-attempt("inner_predict",learn_predict(method,par,X[ia,,drop=FALSE],y[ia],X[ib,,drop=FALSE]));if(is.null(p))return(Inf);mean((y[ib]-p)^2)})))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0031 best<-which.min(loss);par<-grid[[best]];p<-attempt("outer_predict",learn_predict(method,par,X[tr,,drop=FALSE],y[tr],X[te,,drop=FALSE]));if(is.null(p))nextCreates or updates an analysis object; this stores an intermediate result used by later lines.
0032 preds[[length(preds)+1]]<-data.frame(ID=d$ID[te],fold=k,method=method,observed=y[te],predicted=p)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0033 selected[[length(selected)+1]]<-data.frame(fold=k,method=method,parameters=jsonlite::toJSON(par,auto_unbox=TRUE),inner_MSE=loss[best])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0034 if(method=="random_forest"){Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0035 base<-mean((y[te]-p)^2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0036 for(j in seq_len(ncol(X))){drops<-sapply(1:5,function(b){set.seed(SEED+k*1000+j*10+b);xx<-X[te,,drop=FALSE];xx[,j]<-sample(xx[,j]);pp<-learn_predict(method,par,X[tr,,drop=FALSE],y[tr],xx);mean((y[te]-pp)^2)-base});importance[[length(importance)+1]]<-data.frame(fold=k,feature=colnames(X)[j],delta_MSE=mean(drops))}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0037 }Executes a supporting calculation, option, or output step for this module.
0038 }Executes a supporting calculation, option, or output step for this module.
0039 }Executes a supporting calculation, option, or output step for this module.
0040 pr<-do.call(rbind,preds);save_table(pr,"prediction_oof");save_table(do.call(rbind,selected),"prediction_tuning")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0041 met<-do.call(rbind,lapply(split(pr,pr$method),function(v)data.frame(method=v$method[1],n=nrow(v),RMSE=sqrt(mean((v$observed-v$predicted)^2)),MAE=mean(abs(v$observed-v$predicted)),R2=1-sum((v$observed-v$predicted)^2)/sum((v$observed-mean(v$observed))^2))))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0042 save_table(met,"prediction_metrics");if(length(importance))save_table(do.call(rbind,importance),"heldout_importance")Executes a supporting calculation, option, or output step for this module.
0043 transfer<-list()Creates or updates an analysis object; this stores an intermediate result used by later lines.
0044 for(cty in levels(d$county)){tr<-which(d$county!=cty);te<-which(d$county==cty)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0045 for(method in c("mean","elastic_net","random_forest")){par<-switch(method,mean=list(),elastic_net=list(alpha=.5,lambda=.1),random_forest=list(node=15,mtry=5));pp<-attempt("county_transfer",learn_predict(method,par,X[tr,,drop=FALSE],y[tr],X[te,,drop=FALSE]));if(!is.null(pp))transfer[[length(transfer)+1]]<-data.frame(test_county=cty,method=method,n=length(te),RMSE=sqrt(mean((y[te]-pp)^2)),R2=1-sum((y[te]-pp)^2)/sum((y[te]-mean(y[te]))^2))}}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0046 save_table(do.call(rbind,transfer),"county_transport")Executes a supporting calculation, option, or output step for this module.
0047 plot_save("prediction",ggplot2::ggplot(met,ggplot2::aes(RMSE,reorder(method,-RMSE)))+ggplot2::geom_col(fill="#327f91")+ggplot2::labs(x="Out-of-fold RMSE (raw 1–5 three-item score)",y=NULL,title="Nested township-grouped prediction")+ggplot2::theme_minimal(base_size=12))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0048 file.path(OUT,"tables/prediction_metrics.csv")Executes a supporting calculation, option, or output step for this module.
0049}Executes a supporting calculation, option, or output step for this module.
0050run_adjustment<-function(prepared){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0051 d<-readRDS(prepared)$data;d<-d[!is.na(d$tolerance3),];X<-model.matrix(reformulate(c(BG,RES)),d)[,-1,drop=FALSE];y<-d$tolerance3;D<-d$applicationCreates or updates an analysis object; this stores an intermediate result used by later lines.
0052 all<-list();scores<-list()Creates or updates an analysis object; this stores an intermediate result used by later lines.
0053 for(rep in 1:5){fold<-group_folds(d$township,5,SEED+rep);p<-mu0<-mu1<-rep(NA_real_,nrow(d))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0054 for(k in 1:5){tr<-which(fold!=k);te<-which(fold==k);pp<-preprocess(X[tr,,drop=FALSE],X[te,,drop=FALSE]);a<-pp$train;b<-pp$testCreates or updates an analysis object; this stores an intermediate result used by later lines.
0055 # Hyperparameters fixed a priori for nuisance forests; cross-fitting is genuinely out of sample.Comment documenting the intent or an analytical decision; it does not execute.
0056 fm<-ranger::ranger(x=as.data.frame(a),y=factor(D[tr],levels=0:1),probability=TRUE,num.trees=500,min.node.size=15,seed=SEED,num.threads=1)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0057 p[te]<-predict(fm,as.data.frame(b))$predictions[,"1"]Creates or updates an analysis object; this stores an intermediate result used by later lines.
0058 for(g in 0:1){idx<-which(D[tr]==g);f<-ranger::ranger(x=as.data.frame(a[idx,,drop=FALSE]),y=y[tr[idx]],num.trees=500,min.node.size=10,seed=SEED,num.threads=1);pred<-predict(f,as.data.frame(b))$predictions;if(g==0)mu0[te]<-pred else mu1[te]<-pred}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0059 }Executes a supporting calculation, option, or output step for this module.
0060 clipped<-pmin(pmax(p,.01),.99);phi<-mu1-mu0+D*(y-mu1)/clipped-(1-D)*(y-mu0)/(1-clipped);est<-mean(phi);G<-length(unique(d$township));cs<-tapply(phi-est,d$township,sum);se<-sqrt(G/(G-1)*sum(cs^2))/nrow(d)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0061 w<-D/clipped+(1-D)/(1-clipped)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0062 all[[rep]]<-data.frame(repetition=rep,estimate_raw=est,se=se,low=est-qt(.975,G-1)*se,high=est+qt(.975,G-1)*se,min_propensity=min(p),max_propensity=max(p),clipped=sum(p<.01|p>.99),effective_sample_size=sum(w)^2/sum(w^2),estimand="Cross-fitted adjusted contrast; causal interpretation requires unverified assumptions")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0063 scores[[rep]]<-data.frame(ID=d$ID,repetition=rep,fold=fold,application=D,propensity=p,mu0=mu0,mu1=mu1,score=phi,weight=w)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0064 }Executes a supporting calculation, option, or output step for this module.
0065 save_table(do.call(rbind,all),"aipw_summary");ss<-do.call(rbind,scores);save_table(ss,"aipw_oof")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0066 first<-ss[ss$repetition==1,];balance<-lapply(seq_len(ncol(X)),function(j){v<-X[,j];den<-sqrt((var(v[D==0])+var(v[D==1]))/2);data.frame(variable=colnames(X)[j],unweighted=(mean(v[D==1])-mean(v[D==0]))/den,weighted=(weighted.mean(v[D==1],first$weight[D==1])-weighted.mean(v[D==0],first$weight[D==0]))/den)})Creates or updates an analysis object; this stores an intermediate result used by later lines.
0067 save_table(do.call(rbind,balance),"aipw_balance")Executes a supporting calculation, option, or output step for this module.
0068 plot_save("overlap",ggplot2::ggplot(first,ggplot2::aes(propensity,fill=factor(application)))+ggplot2::geom_histogram(position="identity",alpha=.5,bins=25)+ggplot2::labs(x="Out-of-fold propensity",fill="Applied",title="Overlap must be assessed before interpreting adjustment")+ggplot2::theme_minimal(base_size=12))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0069 # Omitted-variable bias contours for linear benchmark; point-estimate sensitivity, not cluster-adjusted causal bounds.Comment documenting the intent or an analytical decision; it does not execute.
0070 f<-lm(reformulate(c("application",BG,RES),"tolerance3"),d);fd<-lm(reformulate(c(BG,RES),"application"),d)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0071 grid<-expand.grid(partial_R2_y=c(0,.01,.03,.05,.1,.2),partial_R2_d=c(0,.01,.03,.05,.1,.2));grid$bias<-sd(residuals(f))/sd(residuals(fd))*sqrt(grid$partial_R2_y*grid$partial_R2_d/(1-grid$partial_R2_d));grid$estimate<-coef(f)["application"];grid$toward_zero<-grid$estimate-sign(grid$estimate)*grid$biasCreates or updates an analysis object; this stores an intermediate result used by later lines.
0072 save_table(grid,"unmeasured_confounding_grid");file.path(OUT,"tables/aipw_summary.csv")Executes a supporting calculation, option, or output step for this module.
0073}Executes a supporting calculation, option, or output step for this module.
src/fresh/secondary.R (35 lines)

How this script helps: Analyses applicant experience, prevention, preferences, reporting, information, crop damage, and descriptive-word fields.

LineSource codeWhat the line does for the analysis
0001run_secondary<-function(prepared){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002 a<-readRDS(prepared);d<-a$data;raw<-a$raw;x<-a$input;rows<-list();status<-list()Creates or updates an analysis object; this stores an intermediate result used by later lines.
0003 lm_result<-function(label,formula,dd,term="application",family=NULL){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0004 needed<-unique(c(all.vars(formula),"township"));dd<-dd[complete.cases(dd[needed]),];if(nrow(dd)<30){status[[length(status)+1]]<<-data.frame(analysis=label,status="insufficient complete observations",n=nrow(dd));return(NULL)}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0005 fit<-attempt(label,if(is.null(family))lm(formula,dd)else glm(formula,dd,family=family))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0006 if(is.null(fit))return(NULL)Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0007 r<-attempt(paste(label,"cluster"),cluster_coef(fit,dd,term=term));if(!is.null(r)){r$analysis<-label;r$scale<-if(is.null(family))"outcome units"else"log odds";rows[[length(rows)+1]]<<-r}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0008 save_model(fit,paste0("secondary_",label));invisible(fit)Executes a supporting calculation, option, or output step for this module.
0009 }Executes a supporting calculation, option, or output step for this module.
0010 lm_result("application_selection",reformulate(c(BG,RES,"conflict_wb","log_loss"),"application"),d,term="log_loss",family=binomial())Creates or updates an analysis object; this stores an intermediate result used by later lines.
0011 app<-d[d$application==1,];lm_result("applicant_timeliness",reformulate(c("timeliness",BG,"log_loss"),"tolerance3"),app,"timeliness")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0012 lm_result("applicant_satisfaction",reformulate(c("satisfaction",BG,"log_loss"),"tolerance3"),app,"satisfaction")Executes a supporting calculation, option, or output step for this module.
0013 lm_result("applicant_both_experiences",reformulate(c("timeliness","satisfaction",BG,"log_loss"),"tolerance3"),app,"satisfaction")Executes a supporting calculation, option, or output step for this module.
0014 lm_result("livelihood_dependence",reformulate(c("application",BG,RES,"log_loss"),"tolerance3"),d,"agri_share")Executes a supporting calculation, option, or output step for this module.
0015 lm_result("damage_burden",reformulate(c("application",BG,RES,"damage_share"),"tolerance3"),d,"damage_share")Executes a supporting calculation, option, or output step for this module.
0016 lm_result("income_loss_burden",reformulate(c("application",BG,"log_income","loss_income_share"),"tolerance3"),d,"loss_income_share")Executes a supporting calculation, option, or output step for this module.
0017 lm_result("prevention_adoption",reformulate(c("application",BG,"conflict_wb","log_loss"),"prevention_used"),d,family=binomial())Creates or updates an analysis object; this stores an intermediate result used by later lines.
0018 users<-d[d$prevention_used==1,];lm_result("prevention_effectiveness_users",reformulate(c("application",BG,"prevention_eff","log_loss"),"tolerance3"),users,"prevention_eff")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0019 d$positive_wtp<-as.integer(d$insurance_wtp>0);lm_result("insurance_positive_wtp",reformulate(c("application",BG,"log_income","agri_share"),"positive_wtp"),d,family=binomial())Creates or updates an analysis object; this stores an intermediate result used by later lines.
0020 d$log_wtp<-log(d$insurance_wtp);lm_result("insurance_positive_amount",reformulate(c("application",BG,"log_income","agri_share"),"log_wtp"),d[d$positive_wtp==1,])Creates or updates an analysis object; this stores an intermediate result used by later lines.
0021 for(y in c("minimum_ratio","desired_ratio")){lm_result(paste0(y,"_validated"),reformulate(c("application",BG),y),d);dd<-d;dd[[y]]<-dd[[paste0(y,"_original")]];lm_result(paste0(y,"_retain_flagged"),reformulate(c("application",BG),y),dd)}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0022 lm_result("reporting_contacts",reformulate(c("application",BG,"report_count","info_count","log_loss"),"tolerance3"),d,"report_count")Executes a supporting calculation, option, or output step for this module.
0023 lm_result("information_channels",reformulate(c("application",BG,"report_count","info_count","log_loss"),"tolerance3"),d,"info_count")Executes a supporting calculation, option, or output step for this module.
0024 rr<-do.call(rbind,rows);rr$p_BH_exploratory<-p.adjust(rr$p,"BH");save_table(rr,"secondary_associations")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0025 pe<-do.call(rbind,lapply(1:7,function(j){v<-d[[paste0("prevention_",LETTERS[j])]];cost<-d[[paste0("prevention_cost_",j)]];data.frame(method=LETTERS[j],raw_question=as.character(a$labels[match(paste0("Q36_",j),names(raw))]),users=sum(v>0,na.rm=TRUE),nonusers=sum(v==0,na.rm=TRUE),mean_effectiveness_users=mean(v[v>0],na.rm=TRUE),recorded_cost_n=sum(!is.na(cost)),median_recorded_cost=median(cost,na.rm=TRUE))}))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0026 save_table(pe,"prevention_methods")Executes a supporting calculation, option, or output step for this module.
0027 payout_cols<-c("Q15_1_TEXT","Q15_2_TEXT","Q15_3_TEXT");payout<-sapply(raw[payout_cols],function(v){s<-trimws(as.character(v));valid<-grepl("^[0-9]+(\\.[0-9]+)?$",s);out<-rep(NA_real_,length(s));out[valid]<-as.numeric(s[valid]);out})Creates or updates an analysis object; this stores an intermediate result used by later lines.
0028 d$payout<-apply(payout,1,function(v)if(sum(!is.na(v))==1)sum(v,na.rm=TRUE)else NA_real_)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0029 save_table(data.frame(metric=c("applicants","numeric_unambiguous_payouts_applicants","median_available_payout","timeliness_observed","satisfaction_observed","zero_income","loss_income_undefined"),value=c(sum(d$application),sum(!is.na(d$payout)&d$application==1),median(d$payout[d$application==1],na.rm=TRUE),sum(!is.na(d$timeliness)),sum(!is.na(d$satisfaction)),sum(d$income==0),sum(is.na(d$loss_income_share)))),"secondary_coverage")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0030 # Crop-specific losses retain the original seven question components and monetary units.Comment documenting the intent or an analytical decision; it does not execute.
0031 crop_loss<-do.call(rbind,lapply(1:7,function(j){v<-numeric_safely(raw[[paste0("Q25_",j)]]);data.frame(field=paste0("Q25_",j),label=a$labels[match(paste0("Q25_",j),names(raw))],n=sum(!is.na(v)),positive=sum(v>0,na.rm=TRUE),median=median(v,na.rm=TRUE),total=sum(v,na.rm=TRUE))}))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0032 save_table(crop_loss,"crop_specific_losses")Executes a supporting calculation, option, or output step for this module.
0033 save_table(data.frame(question=c("payout_loss_ratio","word_themes","causal_effectiveness"),status=c("Not estimated: reference periods and payout coverage not verified","Original frequencies supplied; thematic interpretation requires Chinese-language human review","Prevention is self-selected; conditional associations only")),"secondary_limitations")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0034 file.path(OUT,"tables/secondary_associations.csv")Executes a supporting calculation, option, or output step for this module.
0035}Executes a supporting calculation, option, or output step for this module.
src/fresh/robustness.R (32 lines)

How this script helps: Runs leave-one-township-out, county, clustering, anomaly, missingness, overlap, AIPW-style, and specification-curve stress tests.

LineSource codeWhat the line does for the analysis
0001run_robustness<-function(prepared){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002 d<-readRDS(prepared)$data;rows<-list();seen<-new.env(parent=emptyenv());fail<-list()Creates or updates an analysis object; this stores an intermediate result used by later lines.
0003 # Each outcome/adjustment family is displayed separately; no arbitrary all-subset search.Comment documenting the intent or an analytical decision; it does not execute.
0004 sets<-list(none=character(),background=BG,resources=c(BG,RES),conflict=c(BG,RES,"conflict_wb","conflict_all"),explanatory=c(BG,RES,EXPL))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0005 for(y in c(TOLS,"tolerance3","tolerance4"))for(s in names(sets))for(transform in c("log","raw"))for(rule in c("retain","exclude_extreme_loss","exclude_reporting_conflict"))for(miss in c("complete","median_mode_sensitivity")){Executes a supporting calculation, option, or output step for this module.
0006 dd<-d;ctrl<-sets[[s]]Creates or updates an analysis object; this stores an intermediate result used by later lines.
0007 if(transform=="raw")ctrl<-sub("^log_","",ctrl)Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0008 if(rule=="exclude_extreme_loss")dd<-dd[dd$loss<=quantile(d$loss,.99),]Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0009 if(rule=="exclude_reporting_conflict")dd<-dd[!dd$report_contradiction,]Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0010 vars<-unique(c(y,"application",ctrl,"township","village"));dd<-dd[,vars]Creates or updates an analysis object; this stores an intermediate result used by later lines.
0011 if(miss=="median_mode_sensitivity")for(v in ctrl){if(is.numeric(dd[[v]]))dd[[v]][is.na(dd[[v]])]<-median(dd[[v]],na.rm=TRUE)else if(anyNA(dd[[v]]))dd[[v]][is.na(dd[[v]])]<-names(which.max(table(dd[[v]])))}Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0012 dd<-dd[complete.cases(dd),];f<-reformulate(c("application",ctrl),y)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0013 # Deduplicate exact model inputs before fitting; uncertainty variants remain explicit.Comment documenting the intent or an analytical decision; it does not execute.
0014 key<-digest::digest(list(outcome=y,formula=deparse(f),data=dd));if(exists(key,seen,inherits=FALSE))next;assign(key,TRUE,seen)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0015 dd[[y]]<-z(dd[[y]]);fit<-attempt("specification",lm(f,dd));if(is.null(fit)){fail[[length(fail)+1]]<-data.frame(outcome=y,adjustment=s,transform=transform,rule=rule,missing=miss);next}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0016 for(g in c("township","village")){r<-attempt("spec_cluster",cluster_coef(fit,dd,group=g));if(is.null(r))next;r$outcome<-y;r$adjustment<-s;r$transform<-transform;r$rule<-rule;r$missing<-miss;r$clustering<-g;rows[[length(rows)+1]]<-r}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0017 }Executes a supporting calculation, option, or output step for this module.
0018 rr<-do.call(rbind,rows);save_table(rr,"specification_curve");if(length(fail))save_table(do.call(rbind,fail),"specification_failures")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0019 rr$rank<-ave(rr$estimate,rr$outcome,FUN=rank)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0020 plot_save("specification_curve",ggplot2::ggplot(rr,ggplot2::aes(rank,estimate,color=adjustment))+ggplot2::geom_point(alpha=.6,size=1)+ggplot2::facet_wrap(~outcome,scales="free_x")+ggplot2::geom_hline(yintercept=0,lty=2)+ggplot2::labs(x="Specification rank within outcome",y="Standardized association",title="Reasonable choices can answer different questions")+ggplot2::theme_minimal(base_size=11),11,7)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0021 sumr<-do.call(rbind,lapply(split(rr,interaction(rr$outcome,rr$adjustment,drop=TRUE)),function(v)data.frame(outcome=v$outcome[1],adjustment=v$adjustment[1],specifications=nrow(v),min=min(v$estimate),median=median(v$estimate),max=max(v$estimate),negative_fraction=mean(v$estimate<0))))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0022 save_table(sumr,"specification_summary")Executes a supporting calculation, option, or output step for this module.
0023 vars<-c("tolerance3","application",BG,RES,"township","village");dd<-d[complete.cases(d[vars]),];dd$tolerance3<-z(dd$tolerance3)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0024 jk<-do.call(rbind,lapply(unique(dd$township),function(g){a<-dd[dd$township!=g,];r<-cluster_coef(lm(reformulate(c("application",BG,RES),"tolerance3"),a),a);r$left_out<-g;r}))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0025 save_table(jk,"leave_one_township_out")Executes a supporting calculation, option, or output step for this module.
0026 ct<-do.call(rbind,lapply(levels(dd$county),function(ct){a<-droplevels(dd[dd$county==ct,]);r<-cluster_coef(lm(reformulate(c("application",setdiff(BG,"county"),RES),"tolerance3"),a),a);r$county<-ct;r}))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0027 save_table(ct,"county_specific_associations")Executes a supporting calculation, option, or output step for this module.
0028 # Equivalent observed-scale interaction is interpretable without PLS invariance.Comment documenting the intent or an analytical decision; it does not execute.
0029 ii<-d[complete.cases(d[c("tolerance3","application",BG,RES,"ic","township")]),];ii$ic<-z(ii$ic)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0030 f<-lm(reformulate(c("application*ic",BG,RES),"tolerance3"),ii);r<-cluster_coef(f,ii,term="application:ic");r$f2<-(summary(f)$r.squared-summary(update(f,.~.-application:ic))$r.squared)/(1-summary(f)$r.squared);save_table(r,"observed_interaction")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0031 file.path(OUT,"tables/specification_summary.csv")Executes a supporting calculation, option, or output step for this module.
0032}Executes a supporting calculation, option, or output step for this module.
src/fresh/reporting.R (96 lines)

How this script helps: Collects outputs into publication-ready CSV tables, figures, HTML/PDF reporting inputs, and presentation materials.

LineSource codeWhat the line does for the analysis
0001read_result<-function(n)read.csv(file.path(OUT,"tables",paste0(n,".csv")),check.names=FALSE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002make_slides<-function(){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0003 ci<-subset(read_result("pls_bootstrap_summary"),requested==5000);getci<-function(n){r<-ci[ci$parameter==n,];paste0(fmt(r$estimate)," [",fmt(r$low),", ",fmt(r$high),"]")}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0004 ord<-subset(read_result("ordinal_associations"),adjustment=="background")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0005 pred<-read_result("prediction_metrics");best<-pred[which.min(pred$RMSE),]Creates or updates an analysis object; this stores an intermediate result used by later lines.
0006 bay<-read_result("bayesian_diagnostics");cfa<-subset(read_result("cfa_fit"),partition=="validation"&model=="two_factor_three")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0007 aipw<-read_result("aipw_summary");spec<-read_result("specification_curve");jk<-read_result("leave_one_township_out")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0008 slides<-list();add<-function(title,bullets,notes,figure=NULL,minutes=1.5,backup=FALSE){slides[[length(slides)+1]]<<-list(title=title,bullets=bullets,notes=notes,figure=figure,minutes=minutes,backup=backup)}Creates or updates an analysis object; this stores an intermediate result used by later lines.
0009 add("Compensation application and tolerance",c("Wild-boar conflict in Giant Panda National Park, China","Fresh analysis for Mengxi Kou","Measurement, associations, mechanisms, and robustness"),"Opening: our task is to learn what this fieldwork supports, including results that challenge the original narrative. We distinguish compensation application from payment receipt throughout. Outline the 45-minute talk and reserve 15 minutes for methodological discussion.",minutes=1)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0010 add("The substantive question",c("Can financial compensation support coexistence?","Do applicants report different tolerance?","Which lived experiences and institutional contacts accompany that difference?"),"The policy motivation is important, but this household survey measures simultaneous reports. We can describe and adjust associations; the causal effect of a compensation programme requires additional identification. Introduce the Wildlife Tolerance Model as a conceptual starting point, not a predetermined statistical solution.")Executes a supporting calculation, option, or output step for this module.
0011 add("Study design and retained sample",c("625 households: Baoxing 160; Qingchuan 465","Different interview periods: August 2024 vs March–April 2025","25 townships; 177 complete village keys; 49 earlier exclusions unexplained"),"County and survey timing are inseparable here. There are no repeated measurements on the same households. Unknown sampling and exclusion mechanisms limit population generalization. A missing village receives its own grouping key, not an invented location.")Executes a supporting calculation, option, or output step for this module.
0012 add("Application is not verified payment",c("CE0 asks whether the respondent applied","277 applicants; 348 non-applicants","Receipt, timing, and eligibility are not independently established"),"The original wording matters: never label CE0 as random policy exposure or guaranteed compensation receipt. Selection into applying can reflect losses, reporting access, and attitudes. Applicants are not automatically comparable to non-applicants.")Executes a supporting calculation, option, or output step for this module.
0013 add("Application differs by county",c("County adjustment is essential context, not causal identification."),"Explain the 74% versus 34% application rates. Geographic composition can change pooled comparisons. This motivates county fixed effects and township clustering, not standard errors clustered on only two counties.","application_by_county")Executes a supporting calculation, option, or output step for this module.
0014 add("Four questions, four dimensions",c("Non-lethal management; population control; safety; accepting damage"),"Read the substantive meaning of each item. Tol2 and Tol3 are already reversed, confirmed by Mengxi and raw responses. Higher Tol3 means less safety concern. A common positive orientation does not establish one underlying factor.","tolerance_distributions",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0015 add("A traceable data rebuild",c("Preserve the workbook; record every derived change","Restore raw nonresponse and missing-word zeros","Rebuild institutional counts; flag unresolved percentages and units"),"Clarify that data cleaning is evidence-based rather than selected for favorable results. Percentages over 100% remain unresolved and receive sensitivity analysis. Non-applicants have structurally undefined payment satisfaction. Prevention non-use is not poor effectiveness.",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0016 add("EDA establishes the comparison",c("Profiles, missingness, skewness, ceiling effects, and imbalance","Raw questionnaire fields retain additional substantive information"),"The full EDA tables are available, including every derived variable and the raw-field inventory. Do not read every imbalance as a hypothesis test. Emphasize sparse ordinal categories, skewed losses, and different household compositions.","balance",minutes=1)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0017 add("An analysis map, not a model contest",c("Measurement: EFA → theory CFA; PCA as description","Associations: ordinal, score, Bayesian, and nonlinear models","Mechanisms: PLS paths, interaction, MGA","Stress tests and prediction answer separate questions"),"Explain why methods are complementary. The best predictive model does not identify a policy effect. CFA fit does not prove a mechanism. A PLS composite does not automatically represent an error-free latent variable.",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0018 add("What is reflective, formative, or observed?",c("Tolerance: reflective hypothesis under examination","Institutions and tangible costs: formative components","CE0 and ecological value: observed single items","Item meanings constrain admissible models"),"Avoid using low alpha as a reason to relabel a construct formative. Institutional contact counts and information channels are behaviors, not interchangeable symptoms of fatigue. Reflective diagnostics such as HTMT must be interpreted within this distinction.",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0019 add("EFA: the expected structure is not assured",c("Ordinal polychorics, minres extraction, oblimin rotation","Parallel analysis and identification must be read together"),"The development split has 316 respondents and only 238 complete eight-item records. Pairwise polychorics use available pairs. The parallel suggestion of four factors among eight items is not an identified four-factor questionnaire model. The two-factor EFA has a Heywood problem; report it openly.","parallel_analysis",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0020 add("CFA: internal validation, not independent replication",c(paste0("Three-item tolerance two-factor validation: CFI ",fmt(cfa$cfi.scaled),", RMSEA ",fmt(cfa$rmsea.scaled)),"Village-disjoint development and validation partitions","Weak word-item loadings and factor overlap remain"),"Use the holdout to assess fixed theory models rather than optimize modification indices. The dataset was previously seen, so do not call this independent confirmation. Explain that a standalone three-item factor is just-identified and its perfect fit would not validate it. Factor orientation is arbitrary; compare absolute latent correlations.",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0021 add("PCA describes variance; it does not validate constructs",c("Standardized complete-case item PCA","Loadings and explained variance supplied","PCA components are not latent causes, IRT, or PLS-SEM"),"PCA answers a variance-reduction question. It is useful for checking whether scoring changes the picture, but choosing a component to maximize the application coefficient would be selective analysis. Keep it separate from the substantive construct argument.",minutes=1)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0022 add("The HTMT question",c("Historical 1.112 must be reassessed after coding corrections","Corrected reflective cost/tolerance diagnostics still show overlap","HTMT is not a pass/fail rule for formative institutional contact"),"This directly answers Mengxi's question. Revisit the indicators before merging constructs. The rebuilt reflective cost/tolerance HTMT is high, consistent with overlapping attitudinal content and weak word-item coherence. Institutional contact should not be renamed governance fatigue based on a correlation.",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0023 add("Primary estimands and uncertainty",c("Four ordinal outcomes; Holm adjustment within each model family","Unadjusted → background → resources → explanatory","County effects; township-clustered uncertainty","Report probabilities and intervals, not just p-values"),"The adjustment sequence changes the interpretation. The explanatory model conditions on simultaneous attitudes and potential mediators. It does not estimate the total policy effect. Explain finite-cluster t inference with 25 townships and why village clustering is a sensitivity.",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0024 add("Item-level results differ",c("The strongest background-adjusted signal concerns non-lethal management."),"Point out the negative application association for Tol1, uncertainty for other items after Holm adjustment, and little adjusted association for safety. The stronger resource-adjusted Tol2/Tol4 estimates appear in backup tables. Do not summarize all outcomes as the same psychological response.","primary_ordinal",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0025 add("Composite results depend on the definition",c("Three- and four-item scores are secondary summaries."),"Read the outcome-SD scale carefully. Equal raw-item means differ from the earlier mean-z-score construction. A change in coefficient size can reflect the outcome definition and adjustment, not an algorithm discovering a new causal effect.","score_associations",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0026 add("Ordinal assumptions and Bayesian checks",c(paste0(sum(bay$diagnostics_pass),"/4 Bayesian models passed the prespecified MCMC checks"),"Township random intercepts; weakly informative priors","Nonparallel slopes and sparse-category fits remain concerns"),"Four chains, R-hat at most 1.01, ESS at least 400, and no divergences are computational checks. Posterior predictive plots are provided. Some proportional-odds diagnostics indicate deviations; a Tol2 partial model has a singular Hessian. Do not claim that Bayesian estimation solves these substantive assumptions.",minutes=1.5)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0027 add("PLS-SEM: compare specified models",c("Baseline; mediation; conflict/prevention extension","Three vs four tolerance items; IC1-only sensitivity","Standard PLS-PM; full measurement refit in the bootstrap"),"The main model uses formative cost and institution blocks, observed application/benefit, and a reflective tolerance specification. We report weights, loadings, VIF, reliability where applicable, R², f² and SRMR. Fit and explained variance do not establish causality or construct validity.",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0028 add("Direct and indirect associations",c("Intervals come from 5,000 county-stratified township resamples."),"The direct negative path persists, but both proposed indirect intervals cross zero. The institutional and cost indirect paths have opposite signs and almost cancel. Distinguish standardized PLS paths from the two-stage raw 0/1 application interaction. One bootstrap fit was inadmissible and was recorded, not replaced.","pls_paths",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0029 add("The proposed mechanisms remain uncertain",c(paste0("Direct path: ",getci("direct")),paste0("Indirect via costs: ",getci("indirect_IC")),paste0("Indirect via institutions: ",getci("indirect_PS")),"These data do not demonstrate governance fatigue."),"This is an important departure from earlier reports. Even a nonzero indirect product would need temporal and confounding assumptions to support causal mediation. Here uncertainty already prevents a strong statistical mediation claim.",minutes=1.5)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0030 add("Small interaction; uncertain group differences",c(paste0("Interaction: ",getci("interaction")),paste0("Interaction f² = ",fmt(ci$estimate[ci$parameter=="interaction_f2"])),"All four cluster-bootstrap MGA intervals include zero","No strong difference is not proof of equivalence"),"Keep the prespecified interaction in the exploratory results. Do not delete it to make the model appear stronger. MICOM is a conventional supporting diagnostic; means/variances are not fully invariant. Group-standardized paths are not identical to common-scale observed interactions.",minutes=1.5)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0031 add("Secondary findings use more of the fieldwork",c("Agricultural dependence and prevention deserve attention","Applicant timeliness/satisfaction estimates are uncertain","Insurance preferences, channels, crops, and seasons are profiled","Secondary family uses BH multiplicity adjustment"),"The aim is useful substantive coverage, not accumulating significant results. Adoption and conditional effectiveness answer different questions. Payment text and prevention expenditure are incomplete; payout/loss ratios and causal cost-effectiveness rankings are withheld. Original word counts await human thematic review.",minutes=1.5)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0032 add("How much can we predict?",c(paste0("Best observed grouped-CV RMSE: ",fmt(best$RMSE)," (",best$method,")")),"Five outer and three inner township folds prevent community leakage. Scaling and imputation are trained within folds. Differences among the leading models are small and do not prove linearity. Held-out importance is predictive reliance, not causal importance.","prediction",minutes=1.5)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0033 add("Cross-fitting checks adjusted associations",c(paste0("Five AIPW contrasts: ",fmt(min(aipw$estimate_raw))," to ",fmt(max(aipw$estimate_raw))," raw score points"),"Nuisance models predict unseen townships","Overlap and balance are checked; causal assumptions remain"),"Explain the orthogonal-style score without presenting DML as an automatic confounding cure. Only background/resources enter nuisance models. Repeated splits check algorithmic sensitivity, not five independent replications. Report propensity ranges and effective sample size.",minutes=1.5)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0034 add("A transparent specification curve",c(paste0(nrow(spec)," distinct model/uncertainty combinations; outcomes shown separately")),"We vary reasonable decisions and deduplicate identical inputs. This is not a search for significance. A percentage of negative estimates is not a probability of robustness. Invalid reverse coding is not a reasonable alternative. The safety item should not be hidden among composite results.","specification_curve",minutes=2)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0035 add("Stress-test the observations and assumptions",c(paste0("Leave-one-township contrast range: ",fmt(min(jk$estimate))," to ",fmt(max(jk$estimate))),"Village clustering; county checks; extreme-loss sensitivity","Unresolved-value handling and confounding-strength grid","All failures and model choices remain visible"),"Influence tests assess whether a small number of observations or communities dominate the result. They do not address all unmeasured confounding. The bias grid is a linear point-estimate sensitivity, not a cluster-adjusted causal confidence interval.",minutes=1)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0036 add("What can we defend?",c("Applicants report lower tolerance on several management dimensions","Measurement and outcome choice materially affect the story","The proposed mediation and moderation are not established","Policy failure is not identified by this survey"),"Offer the most defensible interpretation in plain language. Compensation application may mark respondents with different experiences, expectations, and institutional contact. Multiple explanations remain compatible with the data. A causal policy evaluation needs timing and a credible design.",minutes=1.5)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0037 add("What remains for the final report?",c("Clarify sampling, exclusions, payment timing, percentages, and units","Resolve methodological questions from today's discussion","Amend the decision register and rerun affected analyses","Preserve the presentation release for comparison"),"All available-data analyses are reproducible today. Future work is substantive clarification and response to feedback, not inventing causal identification. Clearly separate information unavailable in the workbook from computational tasks already completed.",minutes=1)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0038 add("Discussion",c("Which tolerance dimensions matter for the policy question?","What evidence would distinguish selection from policy effects?","Which measurement interpretation is defensible?"),"Invite methodological criticism. Have the following backup slides and the full report ready. Allocate 15 minutes to discussion and record questions for the three-week final-report revision.",minutes=.5)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0039 add("Backup: direct answers to Mengxi",c("Measurement: no clean, automatic latent structure","HTMT: diagnose reflective blocks; do not merge formative behaviors blindly","Moderation: small and uncertain; MGA: no strong difference","Interpretation: association, not demonstrated causal mediation"),"Use this as the checklist that every item of the Exploratory Contribution was addressed. The full report contains the explicit question-to-answer mapping.",backup=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0040 add("Backup: selection and causal direction",c("Application is voluntary and measured cross-sectionally","County, losses, attitudes, and institutions can shape selection","Cross-fitting removes training reuse, not unmeasured confounding","No valid instrument or longitudinal policy comparison is established"),"If asked for an ATE, explain the identification assumptions and why our adjusted contrasts do not establish them. Conditioning on current attitudes can block or distort paths; a statistical arrow is not temporal evidence.",backup=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0041 add("Backup: why not interpret nonsignificance as equality?",c("Group differences can be imprecise","Equivalence needs a justified margin and adequate precision","Group-standardized coefficients depend on variance","MICOM non-rejection is not proof of full invariance"),"A nonsignificant MGA is supplementary evidence of no clear difference, exactly as Mengxi suggested. The study did not specify a substantive equivalence margin, so it cannot claim equivalent mechanisms.",backup=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0042 add("Backup: posterior predictive check",c("MCMC diagnostics and model fit answer different questions."),"Compare observed response frequencies with replicated frequencies. The remaining three item plots and all diagnostics are available in the report outputs.","bayes_ppc_tol1",backup=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0043 add("Backup: propensity overlap",c("Inspect support, balance, clipping, and effective sample size."),"Overlap in the fitted propensity distribution does not prove overlap on unobserved confounders. The exported balance table shows how observed differences change after weighting.","overlap",backup=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0044 add("Backup: p-hacking safeguards",c("Dated plan; prior inspection disclosed","Full results and failures; no significance-driven deletion","Deduplicated specifications; multiplicity; internal validation","No p-curve or certificate of 'no p-hacking'"),"Explain that the appropriate safeguard is transparent analytical practice. P-curve on correlated tests from this single sample would not establish the absence of selective reporting.",backup=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0045 add("Backup: missingness and anomalies",c("Structural payment missingness is never imputed","Word zeros are absent answers, not positive sentiment","Percentages above 100% are flagged, not guessed","Median/mode sensitivity is limited, not full multiple imputation"),"The transformation log identifies exactly which values changed and why. One missing raw Tol1 changes the score sample from 625 to 624. Main PLS complete cases number 622 because reporting responses are also missing.",backup=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0046 add("Backup: reproducibility",c("R targets pipeline and renv lockfile","Source/data hashes, seeds, grouped folds, model objects","Reports and slides read the same saved tables","One build command; separate render and validation commands"),"Commands: Rscript run_project.R --restore; Rscript run_project.R; Rscript run_project.R --render; Rscript run_project.R --verify. A rebuild should not rely on an RStudio workspace or .RData.",backup=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0047 add("Backup: methodological references",c("lavaan: categorical WLSMV; psych: EFA and parallel analysis","cSEM: PLS-PM and MICOM; brms: ordinal multilevel models","Simonsohn et al. (2020): specification curve analysis","DoubleML: cross-fitting and sensitivity assumptions"),"Clickable references and full URLs are in the report and PLAN.md. These guide method choices; they do not validate the present dataset automatically.",backup=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0048 slidesExecutes a supporting calculation, option, or output step for this module.
0049}Executes a supporting calculation, option, or output step for this module.
0050render_deliverables<-function(){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0051 Sys.setenv(WILDBOAR_ROOT=ROOT)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0052 # Additional presentation-ready variance figure.Comment documenting the intent or an analytical decision; it does not execute.
0053 pv<-read_result("pca_variance")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0054 plot_save("pca_variance",ggplot2::ggplot(pv,ggplot2::aes(component,variance))+ggplot2::geom_col(fill="#327f91")+ggplot2::labs(x="Component",y="Proportion of variance",title="PCA: variance description, not construct validation")+ggplot2::theme_minimal(base_size=12))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0055 slides<-make_slides();slides[[13]]$figure<-"pca_variance"Creates or updates an analysis object; this stores an intermediate result used by later lines.
0056 # Scale declared main-talk timings to exactly 45 minutes.Comment documenting the intent or an analytical decision; it does not execute.
0057 main<-!vapply(slides,`[[`,logical(1),"backup");total<-sum(vapply(slides[main],`[[`,numeric(1),"minutes"))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0058 for(i in which(main))slides[[i]]$minutes<-slides[[i]]$minutes*45/totalCreates or updates an analysis object; this stores an intermediate result used by later lines.
0059 p<-officer::read_pptx();notes<-c("# Speaker notes: 45-minute talk + 15-minute discussion","");md<-c("% Compensation application and wild-boar tolerance","% Statistical consulting for Mengxi Kou","% 17 September 2026","")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0060 for(i in seq_along(slides)){Executes a supporting calculation, option, or output step for this module.
0061 s<-slides[[i]];p<-officer::add_slide(p,layout="Blank",master="Office Theme")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0062 title<-officer::fpar(officer::ftext(s$title,officer::fp_text(font.size=25,bold=TRUE,color="#16324F",font.family="Arial")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0063 p<-officer::ph_with(p,title,location=officer::ph_location(left=.45,top=.3,width=9.1,height=.8))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0064 if(!is.null(s$figure)){Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0065 p<-officer::ph_with(p,officer::external_img(file.path(OUT,"figures",paste0(s$figure,".png")),width=8.9,height=4.9),location=officer::ph_location(left=.55,top=1.3,width=8.9,height=4.9))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0066 body<-officer::fpar(officer::ftext(paste(s$bullets,collapse="\n"),officer::fp_text(font.size=15,color="#16324F",font.family="Arial")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0067 p<-officer::ph_with(p,body,location=officer::ph_location(left=.55,top=6.2,width=8.9,height=.7))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0068 }else{Executes a supporting calculation, option, or output step for this module.
0069 for(j in seq_along(s$bullets)){Executes a supporting calculation, option, or output step for this module.
0070 body<-officer::fpar(officer::ftext(paste0("• ",s$bullets[j]),officer::fp_text(font.size=21,color="#223344",font.family="Arial")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0071 p<-officer::ph_with(p,body,location=officer::ph_location(left=.7,top=1.5+(j-1)*1.12,width=8.6,height=1.02))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0072 }Executes a supporting calculation, option, or output step for this module.
0073 }Executes a supporting calculation, option, or output step for this module.
0074 foot<-officer::fpar(officer::ftext(paste0(if(s$backup)"DISCUSSION BACKUP"else"PRESENTATION RELEASE • 17 SEPT 2026"," | ",i),officer::fp_text(font.size=9,color="#64748B")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0075 p<-officer::ph_with(p,foot,location=officer::ph_location(left=.5,top=7.12,width=9,height=.2))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0076 note<-paste0(if(s$backup)"Backup slide"else paste0("Target time: ",round(s$minutes,1)," minutes"),"\n",s$notes)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0077 p<-officer::set_notes(p,value=note,location=officer::notes_location_type("body"))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0078 notes<-c(notes,paste0("## ",i,". ",s$title),"",note,"",paste0("- ",s$bullets),"")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0079 md<-c(md,paste0("## ",if(s$backup)"Backup: "else"",s$title),"",paste0("- ",s$bullets),"")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0080 if(!is.null(s$figure))md<-c(md,paste0("![](",file.path(OUT,"figures",paste0(s$figure,".png")),"){height=60%}"),"")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0081 }Executes a supporting calculation, option, or output step for this module.
0082 ppt<-file.path(OUT,"presentation/Wildboar_Consulting_Presentation.pptx");print(p,target=ppt)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0083 writeLines(notes,file.path(OUT,"presentation/Speaker_Notes.md"))Persists a table, model, figure, or report artifact so results are inspectable outside R.
0084 writeLines(md,file.path(OUT,"presentation/Slides.md"))Persists a table, model, figure, or report artifact so results are inspectable outside R.
0085 jsonlite::write_json(slides,file.path(OUT,"presentation/slide_content.json"),pretty=TRUE,auto_unbox=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0086 # Render an accessible narrative report and a printable version from identical sources.Comment documenting the intent or an analytical decision; it does not execute.
0087 html<-rmarkdown::render(file.path(ROOT,"docs/Analysis_Report.Rmd"),output_format="html_document",output_file="Analysis_Report.html",output_dir=file.path(OUT,"report"),quiet=TRUE,envir=new.env())Creates or updates an analysis object; this stores an intermediate result used by later lines.
0088 pdf<-rmarkdown::render(file.path(ROOT,"docs/Analysis_Report.Rmd"),output_format="pdf_document",output_file="Analysis_Report.pdf",output_dir=file.path(OUT,"report"),quiet=TRUE,envir=new.env())Creates or updates an analysis object; this stores an intermediate result used by later lines.
0089 slidepdf<-file.path(OUT,"presentation/Wildboar_Consulting_Presentation.pdf")Creates or updates an analysis object; this stores an intermediate result used by later lines.
0090 status<-system2("pandoc",c(shQuote(file.path(OUT,"presentation/Slides.md")),"-t","beamer","--pdf-engine=xelatex","-V","theme:default","-V","colortheme:dolphin","-V",shQuote("mainfont:DejaVu Sans"),"-o",shQuote(slidepdf)),stdout=file.path(OUT,"logs/slides_pdf.log"),stderr=file.path(OUT,"logs/slides_pdf.log"))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0091 if(status!=0)stop("Presentation PDF rendering failed; see slides_pdf.log")Controls execution so checks, loops, or conditional sensitivity branches run reproducibly.
0092 files<-c(list.files(file.path(ROOT,"src/fresh"),full.names=TRUE),file.path(ROOT,c("_targets.R","run_project.R","docs/PLAN.md","docs/ANALYSIS_DECISIONS.md","docs/Analysis_Report.Rmd","data/3_Data.xlsx")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0093 manifest<-list(created_utc=format(Sys.time(),tz="UTC",usetz=TRUE),seed=SEED,data_sha256=digest::digest(file=file.path(ROOT,"data/3_Data.xlsx"),algo="sha256"),source_hashes=setNames(lapply(files,function(p)digest::digest(file=p,algo="sha256")),sub(paste0(ROOT,"/"),"",files,fixed=TRUE)),session=capture.output(sessionInfo()),main_slides=sum(main),backup_slides=sum(!main),talk_minutes=sum(vapply(slides[main],`[[`,numeric(1),"minutes")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0094 jsonlite::write_json(manifest,file.path(OUT,"run_manifest.json"),pretty=TRUE,auto_unbox=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0095 c(ppt,html,pdf,slidepdf,file.path(OUT,"presentation/Speaker_Notes.md"),file.path(OUT,"run_manifest.json"))Executes a supporting calculation, option, or output step for this module.
0096}Executes a supporting calculation, option, or output step for this module.
src/fresh/validate.R (14 lines)

How this script helps: Checks that key counts, hashes, diagnostics, bootstrap success, and required output files meet the reproducibility guardrails.

LineSource codeWhat the line does for the analysis
0001validate_project<-function(){Creates or updates an analysis object; this stores an intermediate result used by later lines.
0002 checks<-list.files(file.path(OUT,"tables"),pattern="\\.csv$",full.names=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0003 stopifnot(file.exists(file.path(ROOT,"docs/PLAN.md")),file.exists(file.path(ROOT,"docs/ANALYSIS_DECISIONS.md")),length(checks)>=50)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0004 d<-readRDS(file.path(OUT,"models/prepared.rds"))$dataCreates or updates an analysis object; this stores an intermediate result used by later lines.
0005 stopifnot(nrow(d)==625,sum(d$application)==277,all(is.na(d$timeliness[d$application==0])),all(!is.na(d$tol2)|!is.na(d$tol1)))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0006 source_map<-read.csv(file.path(ROOT,"results/repository_audit/tolerance_coding.csv"));stopifnot(all(source_map$mismatches==0))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0007 b<-read.csv(file.path(OUT,"tables/pls_bootstrap_summary.csv"));stopifnot(all(b$successful>0),all(b$failure_rate<.01))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0008 bay<-read.csv(file.path(OUT,"tables/bayesian_diagnostics.csv"));stopifnot(all(bay$diagnostics_pass))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0009 pred<-read.csv(file.path(OUT,"tables/prediction_metrics.csv"));stopifnot(all(is.finite(pred$RMSE)),all(pred$method%in%c("mean","elastic_net","GAM","random_forest","boosting")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0010 files<-c(list.files(file.path(ROOT,"src/fresh"),full.names=TRUE),file.path(ROOT,c("_targets.R","run_project.R","docs/PLAN.md","docs/ANALYSIS_DECISIONS.md","docs/Analysis_Report.Rmd")))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0011 manifest<-list(checked_utc=format(Sys.time(),tz="UTC",usetz=TRUE),n_respondents=nrow(d),n_tables=length(checks),file_hashes=setNames(lapply(files,function(p)digest::digest(file=p,algo="sha256")),sub(paste0(ROOT,"/"),"",files,fixed=TRUE)))Creates or updates an analysis object; this stores an intermediate result used by later lines.
0012 jsonlite::write_json(manifest,file.path(OUT,"validation.json"),pretty=TRUE,auto_unbox=TRUE)Creates or updates an analysis object; this stores an intermediate result used by later lines.
0013 writeLines(c("VALIDATION PASSED",capture.output(str(manifest))),file.path(OUT,"logs/validation.txt"));TRUEPersists a table, model, figure, or report artifact so results are inspectable outside R.
0014}Executes a supporting calculation, option, or output step for this module.

7. Reproduction

Rscript run_project.R --restore
Rscript run_project.R
Rscript run_project.R --render
Rscript run_project.R --verify

The generated manifest records source hashes, data hash, seed, session information, and slide counts. Validation passed for coding audit, respondent/application counts, bootstrap success, Bayesian diagnostics, and prediction outputs.

Data hash: 9fca74ec64e7cf5858b3c63b39ace1f9b891b7572114e531be9c7dcb30a92634. The source audit reports 625 input rows, 319 disagreements between CE0 and the obsolete sightings proxy, and 13 unresolved percentage anomalies.

All machine-readable outputs are under tables; model objects and logs are under models/logs. The complete narrative report contains the explicit answers to every Exploratory Contribution question.

8. Limitations and next clarification

This is a cross-sectional, nonrandom application comparison from two county-period combinations. Unknown sampling/exclusion mechanisms, incomplete payment timing, unresolved percentage and area-unit meanings, weak/overlapping reflective measurement, structural missingness, and potential unmeasured confounding limit causal claims. The most useful next step is to resolve these fieldwork questions with Mengxi and amend affected analyses transparently.