Manuscript v1.0 draft compiled (48 p.), table/figure fixes
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
59 changed files +120 −25
modified
paper/figures/attrition.pdf
+0 −0
Binary file not shown.
modified
paper/figures/category_network.pdf
+0 −0
Binary file not shown.
modified
paper/figures/coverage_map.pdf
+0 −0
Binary file not shown.
modified
paper/figures/diversity_region.pdf
+0 −0
Binary file not shown.
modified
paper/figures/h4_density.pdf
+0 −0
Binary file not shown.
modified
paper/figures/h5_region_effects.pdf
+0 −0
Binary file not shown.
modified
paper/figures/h7_validation.pdf
+0 −0
Binary file not shown.
modified
paper/figures/price_gaps.pdf
+0 −0
Binary file not shown.
modified
paper/figures/raa_heatmap.pdf
+0 −0
Binary file not shown.
modified
paper/figures/rank_size.pdf
+0 −0
Binary file not shown.
modified
paper/figures/robustness_h1.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/attrition.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/category_network.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/coverage_map.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/diversity_region.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/h4_density.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/h5_region_effects.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/h7_validation.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/price_gaps.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/raa_heatmap.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/rank_size.pdf
+0 −0
Binary file not shown.
modified
paper/figures_model/robustness_h1.pdf
+0 −0
Binary file not shown.
modified
paper/main.pdf
+0 −0
Binary file not shown.
modified
paper/sections/data.tex
+5 −0
@@ -5,6 +5,11 @@ The research copy is a read-only backup of the Fabri-Ka production database take | ||
| 5 | 5 | |
| 6 | 6 | \input{tables/sample_flow} |
| 7 | 7 | |
| 8 | +\begin{figure}[htbp]\centering | |
| 9 | +\includegraphics[width=0.95\textwidth]{\FR{attrition.pdf}} | |
| 10 | +\caption{Sample flow from database rows to the assortment and price samples. Source: Fabri-Ka research snapshot (2026-11-01).}\label{fig:attrition} | |
| 11 | +\end{figure} | |
| 12 | + | |
| 8 | 13 | \subsection{Merchant geography}\label{sec:data_geo} |
| 9 | 14 | The platform assigns a region from the discovery source (regional directories), from region mentions on the site, or from a map of forward sortation areas (FSA, the first three characters of the postal code); coordinates are FSA centroids obtained from a public geocoder, never civic addresses. At the snapshot 346 of the 1{,}569 live stores had no region, including the four largest catalogues (a book retailer, a souvenir printer, a trailer-parts seller and a pet-supply retailer). We recovered regions from official geography: for urban FSAs the sector label is matched to the MRNF municipality table (393 stores, 95.9\% agreement with the point-in-polygon of the centroid where both exist), then the platform's own label is kept (865 stores), then the FSA centroid is located in the MRNF administrative-region polygons (82 stores). The order was amended after preregistration (A-001): a first attempt with the Statistics Canada 2021 economic-region layer produced 229 apparent conflicts between platform labels and polygons, of which 99 were a spelling artefact and most of the rest the Brome-Missisquoi/Haute-Yamaska transfer from Montérégie to Estrie that the 2021 layer predates; with the current MRNF layer the platform label and the centroid agree for 89.1\% of stores, and the remaining disagreements (30 after the final rule) are rural FSAs whose centroids fall near a border, which is why the platform label is preferred to the centroid. After recovery, 229 stores (71{,}692 listings, 19\% of the assortment sample) remain without a location; they come mainly from gift directories and search sweeps, are reported as a separate ``Inconnue'' row in descriptive tables, and are excluded from all regional inference. One further caveat: the telephone field of 250 stores is the switchboard of the certification directory that listed them (212 carry the number of Les Produits du Québec); telephones are therefore never used for geography. Table~\ref{tab:region_summary} summarises the regional sample. |
| 10 | 15 | |
modified
paper/sections/results.tex
+2 −0
@@ -58,6 +58,8 @@ The primary matched sample contains 2{,}203 listings in 1{,}064 groups sold by 1 | ||
| 58 | 58 | |
| 59 | 59 | \paragraph{A descriptive contrast that is not H6.} Across the whole price sample, within category, stores certified by Aliments du Québec or Les Produits du Québec post prices 0.20 log points below other stores (store-clustered SE 0.14; Table~\ref{tab:cert}). This is a store-level contrast between certified enterprises and others, confounded by category composition within the twenty bins and by store size; it says nothing about a premium for products made in Quebec, which cannot be identified in this source. |
| 60 | 60 | |
| 61 | +\TR{cert_contrast} | |
| 62 | + | |
| 61 | 63 | \subsection{H7 --- The complexity indicator does not survive validation}\label{sec:results_h7} |
| 62 | 64 | The binary region--category matrix ($M_{rc}=1$ if RAA $\ge1$, 40\% of cells) yields a diversity count, an ECI and a fitness index per region (Appendix~\ref{app:indicators}). Table~\ref{tab:h7} reports the validation. V1 fails: across 500 bootstrap resamples of stores the median Spearman correlation between the resampled and the full-sample ECI ranking is 0.67 (tenth percentile $-0.34$) against a criterion of 0.8; fitness (0.55) and even plain diversity (0.61) are also unstable, because with 17 regions and 20 categories the matrix is small and the marginal cells depend on a handful of merchants. V2 is mixed: the second eigenvalue of $\tilde M$ is larger than in all 2{,}000 merchant reshuffles ($p<0.001$) --- there is more block structure than chance --- but the spectral radius of the bipartite graph is not ($p=0.97$), and the ECI--diversity correlation (0.43) lies within the null band ($-0.09$; $0.57$). V3 fails: regressed on log population, log business locations and income the ECI has an $R^2$ of 0.25 and a leave-one-region-out predictive correlation of 0.00. Under the rule labelling V1 is worse (0.20) and V2 fails on both statistics. V4 is the only clean result: Louvain finds the same two communities in all 200 seeds (NMI 1.0), a food block (maple, fine grocery, chocolate, bakery, meat and fish, cheese, beverages, coffee and alcohol) and a non-food block (Figure~\ref{fig:network}); it is also the least informative, since it reproduces the obvious food/non-food divide. By the preregistered rule the indicator is reported as unstable, not called a complexity index, and excluded from the index family. |
| 63 | 65 | |
modified
paper/tables/category_audit.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Audit of the rule-based category labels (500-listing stratified sample)}\label{tab:cat_audit} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrr}\toprule |
| 4 | 5 | Rule label & Listings with annotator consensus & Precision of the rule label \\\midrule |
| 5 | 6 | Maple \& honey & 24 & 0.50 \\ |
@@ -24,5 +25,6 @@ Industrial & 24 & 0.42 \\ | ||
| 24 | 25 | Other & 25 & 0.00 \\ |
| 25 | 26 | \textbf{All} & 474 & \textbf{0.46} \\ |
| 26 | 27 | \bottomrule\end{tabular} |
| 28 | +\end{adjustbox} | |
| 27 | 29 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} 25 random listings per category annotated independently by two LLMs (claude-opus-5-5, gpt-5.5) with the platform's taxonomy; agreement rule vs A 0.45, rule vs B 0.45, A vs B 0.95; consensus exists for 95\% of listings. Precision = share of consensus labels equal to the rule label. Disagreements listed in the replication package.\end{minipage} |
| 28 | 30 | \end{table} |
modified
paper/tables/cert_contrast.tex
+2 −0
@@ -1,9 +1,11 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\small |
| 2 | 2 | \caption{Descriptive store-certification price contrast (not a test of H6)}\label{tab:cert} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lr}\toprule |
| 4 | 5 | Statistic & Value \\\midrule |
| 5 | 6 | Observations / stores / certified stores & 288\,663 / 1\,264 / 491 \\ |
| 6 | 7 | Certified store, log price difference within category (SE, store-clustered) & -0.204 (0.138) \\ |
| 7 | 8 | \bottomrule\end{tabular} |
| 9 | +\end{adjustbox} | |
| 8 | 10 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} descriptive store-certification contrast (Aliments du Québec / Les Produits du Québec), category FE, store-clustered SE — NOT a test of H6\end{minipage} |
| 9 | 11 | \end{table} |
modified
paper/tables/external_coverage.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Coverage of the regional sample against external business and population counts}\label{tab:external} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrrr}\toprule |
| 4 | 5 | Region & Fabri-Ka stores & Business locations & Stores per 1\,000 businesses & Population & Stores per 100\,000 pop. \\\midrule |
| 5 | 6 | Bas-Saint-Laurent & 39 & 7\,441 & 5.24 & 204\,755 & 19.0 \\ |
@@ -20,5 +21,6 @@ Laurentides & 99 & 22\,002 & 4.50 & 679\,190 & 14.6 \\ | ||
| 20 | 21 | Montérégie & 190 & 44\,787 & 4.24 & 1\,522\,372 & 12.5 \\ |
| 21 | 22 | Centre-du-Québec & 61 & 9\,270 & 6.58 & 264\,820 & 23.0 \\ |
| 22 | 23 | \bottomrule\end{tabular} |
| 24 | +\end{adjustbox} | |
| 23 | 25 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Business locations = ISQ, locations with employees, December 2025 (all industries; retail NAICS 44-45; manufacturing 31-33); population = ISQ 1 July 2025 provisional. Fabri-Ka stores are online storefronts of Quebec-based merchants discovered through certification registries, associations and search; coverage ratios are not sampling rates.\end{minipage} |
| 24 | 26 | \end{table} |
modified
paper/tables/h1_raa.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{H1 --- Region $\times$ category dependence against the store-reshuffle null}\label{tab:h1} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrrrrrr}\toprule |
| 4 | 5 | Sample / variant & Weights & Stores & Regions & Cramér's $V$ & Null mean & Null p95 & $p$ (perm.) & Cells RAA$>1$/$<1$ \\\midrule |
| 5 | 6 | S\_R & M & 1\,331 & 17 & 0.105 & 0.075 & 0.081 & 0.0005 & 13/62 \\ |
@@ -18,5 +19,6 @@ drop\_autre & M & 1\,296 & 17 & 0.108 & 0.076 & & 0.001 & \\ | ||
| 18 | 19 | excl\_resellers\_collectives & M & 1\,306 & 17 & 0.106 & 0.076 & & 0.001 & \\ |
| 19 | 20 | excl\_region\_conflicts & M & 1\,301 & 17 & 0.107 & 0.076 & & 0.001 & \\ |
| 20 | 21 | \bottomrule\end{tabular} |
| 22 | +\end{adjustbox} | |
| 21 | 23 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} $V$ = Cramér's $V$ of the region $\times$ category table of listing weights (L = one per listing; M = merchant-equal, each store sums to one; T = listings after dropping the 1\% largest stores; `stores' = count of stores present in the category). Null = 2\,000 permutations of region labels across stores (each region keeps its number of stores, each store keeps its catalogue); $p$ is one-sided. Last column: number of the $R\times C$ cells whose store-bootstrap 95\% interval for RAA lies entirely above / below 1. Variants from the preregistered robustness list (1\,000 permutations).\end{minipage} |
| 22 | 24 | \end{table} |
modified
paper/tables/h2_scale.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{H2 --- Regional assortment diversity and regional scale}\label{tab:h2} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrr}\toprule |
| 4 | 5 | Outcome $\sim$ covariate & $n$ & Spearman $\rho$ & 95\% CI & OLS slope (HC3 SE) \\\midrule |
| 5 | 6 | H\_rarefied15 ~ log\_population & 16 & -0.20 & [-0.62; 0.34] & -0.005 (0.006) \\ |
@@ -18,5 +19,6 @@ log\_stores\_per\_100k ~ log\_population & 17 & -0.19 & [-0.60; 0.30] & -- \\ | ||
| 18 | 19 | log\_stores\_per\_100k ~ log\_density & 17 & -0.22 & [-0.71; 0.36] & -- \\ |
| 19 | 20 | log\_stores\_per\_100k ~ disposable\_income & 17 & -0.02 & [-0.49; 0.46] & -- \\ |
| 20 | 21 | \bottomrule\end{tabular} |
| 22 | +\end{adjustbox} | |
| 21 | 23 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} 17 regions at most (Nord-du-Québec has no located store); rarefied diversity needs >= 15 stores. Associations only; CIs from 5 000 region-level bootstrap draws; OLS slope with HC3 SE.\end{minipage} |
| 22 | 24 | \end{table} |
modified
paper/tables/h3_concentration.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\small |
| 2 | 2 | \caption{H3 --- Concentration of listings across merchants (assortment sample)}\label{tab:h3} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lr}\toprule |
| 4 | 5 | Statistic & Value \\\midrule |
| 5 | 6 | Stores / listings & 1\,557 / 370\,054 \\ |
@@ -12,5 +13,6 @@ Discrete power law: $x_{\min}$, $\alpha$, KS, tail $n$ & 165, 1.929, 0.028, 288 | ||
| 12 | 13 | Vuong LR (power law vs log-normal on the tail): $z$, $p$ & 4.99, 6e-07 (power-law) \\ |
| 13 | 14 | Preregistered criterion (Gini $\ge$ 0.70 and top-10\% $\ge$ 0.50) & met \\ |
| 14 | 15 | \bottomrule\end{tabular} |
| 16 | +\end{adjustbox} | |
| 15 | 17 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Bootstrap CIs from 2\,000 resamples of stores. Power-law fit by maximum likelihood with $x_{\min}$ chosen by KS minimisation (Clauset et al.\ 2009); the log-normal is fitted on the same tail. Inconnue-region stores included (all stores).\end{minipage} |
| 16 | 18 | \end{table} |
modified
paper/tables/h3_within_region.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Within-region concentration of catalogue sizes}\label{tab:h3_region} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrr}\toprule |
| 4 | 5 | Region & Stores & Gini [95\% CI] & Top-10\% share \\\midrule |
| 5 | 6 | Outaouais & 36 & 0.922 [0.632; 0.937] & 0.946 \\ |
@@ -20,5 +21,6 @@ Mauricie & 31 & 0.730 [0.495; 0.792] & 0.701 \\ | ||
| 20 | 21 | Côte-Nord & 16 & 0.517 [0.318; 0.565] & 0.455 \\ |
| 21 | 22 | Nord-du-Québec & 3 & -- & -- \\ |
| 22 | 23 | \bottomrule\end{tabular} |
| 24 | +\end{adjustbox} | |
| 23 | 25 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} 500 store-bootstrap resamples per region; regions with fewer than five stores omitted.\end{minipage} |
| 24 | 26 | \end{table} |
modified
paper/tables/h4_dynamics.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\small |
| 2 | 2 | \caption{H4 (exploratory) --- Entry into related categories within stores}\label{tab:h4} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lr}\toprule |
| 4 | 5 | Statistic & Value \\\midrule |
| 5 | 6 | Baseline / outcome windows & 2026-08-31 to 2026-09-27 / 2026-09-28 to 2026-11-01 \\ |
@@ -11,5 +12,6 @@ Placebo (category-relabelled proximity, 200 draws): mean, p95, $p$ & -0.004, 0.0 | ||
| 11 | 12 | Region-level category entries / exits & 11 / 0 \\ |
| 12 | 13 | Share of entering stores with an `added' burst $>$50\% of baseline catalogue & 0.16 \\ |
| 13 | 14 | \bottomrule\end{tabular} |
| 15 | +\end{adjustbox} | |
| 14 | 16 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Linear probability model with store and category fixed effects; density = share of a category's proximity mass covered by the store's baseline portfolio (Hidalgo-type proximity from co-occurrence across stores). Exploratory by preregistration: no causal claim.\end{minipage} |
| 15 | 17 | \end{table} |
modified
paper/tables/h5_hedonic.tex
+19 −5
@@ -1,9 +1,23 @@ | ||
| 1 | −\begin{table}[htbp]\centering\scriptsize | |
| 1 | +\begin{table}[htbp]\centering\small | |
| 2 | 2 | \caption{H5 --- Matched-product price dispersion across merchants}\label{tab:h5} |
| 3 | −\begin{tabular}{lrrrrrrrrrrrrr}\toprule | |
| 4 | −Spec. & Obs. & Groups & Stores & Regions & Wald region (df) & $p$ wild-boot & Reseller (SE) & $p$ wild-boot & Certified (SE) & log catalogue (SE) & Within $R^2$ & Gap median / p90 & Share gap $>$5\% \\\midrule | |
| 5 | −primary\_AB & 2\,203 & 1\,064 & 143 & 15 & 164.4 (14) & 0.0045 & -0.116 (0.026) & 0.0012 & -0.073 (0.023) & 0.002 (0.008) & 0.166 & 0.047 / 0.288 & 0.49 \\ | |
| 6 | −sens\_ABC & 2\,512 & 1\,189 & 156 & 15 & 83.3 (14) & 0.0162 & -0.101 (0.025) & 0.0029 & -0.028 (0.018) & 0.009 (0.007) & 0.139 & 0.051 / 0.333 & 0.50 \\ | |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 4 | +\begin{tabular}{lrr}\toprule | |
| 5 | +Statistic & primary\_AB & sens\_ABC \\\midrule | |
| 6 | +Observations & 2\,203 & 2\,512 \\ | |
| 7 | +Match groups & 1\,064 & 1\,189 \\ | |
| 8 | +Stores & 143 & 156 \\ | |
| 9 | +Regions (with $\ge$ 5 matched stores) & 15 (9) & 15 (9) \\ | |
| 10 | +Wald statistic, region effects (df) & 164.4 (14) & 83.3 (14) \\ | |
| 11 | +\quad $p$, wild cluster bootstrap & 0.0045 & 0.0162 \\ | |
| 12 | +Reseller / collective store (SE) & -0.116 (0.026) & -0.101 (0.025) \\ | |
| 13 | +\quad $p$, wild cluster bootstrap & 0.0012 & 0.0029 \\ | |
| 14 | +Certified store (SE) & -0.073 (0.023) & -0.028 (0.018) \\ | |
| 15 | +log catalogue size (SE) & 0.002 (0.008) & 0.009 (0.007) \\ | |
| 16 | +Within-group $R^2$ & 0.166 & 0.139 \\ | |
| 17 | +Within-group gap: median / p90 & 0.047 / 0.288 & 0.051 / 0.333 \\ | |
| 18 | +Share of groups with gap $>$ 5\% & 0.49 & 0.50 \\ | |
| 19 | +Share of groups with identical prices & 0.29 & 0.29 \\ | |
| 7 | 20 | \bottomrule\end{tabular} |
| 21 | +\end{adjustbox} | |
| 8 | 22 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Dependent variable: log posted price at the snapshot. Match-group fixed effects absorbed; region and platform dummies, log catalogue size, reseller/collective and certification indicators. SE clustered by store; $p$-values from a wild cluster bootstrap (Rademacher, 9\,999 draws, restricted residuals). primary\_AB = tiers A (shared SKU) and B (same brand, identical title); sens\_ABC adds fuzzy tier C. Gap = within-group max--min log price.\end{minipage} |
| 9 | 23 | \end{table} |
modified
paper/tables/h7_indicators.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Region-level indicators (reported for transparency; unstable under bootstrap)}\label{tab:h7ind} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrr}\toprule |
| 4 | 5 | Region & Stores & Diversity & ECI & Fitness \\\midrule |
| 5 | 6 | Montréal & 237 & 9 & 1.70 & 1.15 \\ |
@@ -20,5 +21,6 @@ Centre-du-Québec & 61 & 11 & -1.19 & 1.54 \\ | ||
| 20 | 21 | Bas-Saint-Laurent & 39 & 6 & -1.49 & 0.63 \\ |
| 21 | 22 | Mauricie & 31 & 6 & -1.56 & 0.60 \\ |
| 22 | 23 | \bottomrule\end{tabular} |
| 24 | +\end{adjustbox} | |
| 23 | 25 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Diversity = number of categories with RAA $\ge 1$. ECI standardised; sign fixed so that corr(ECI, diversity) $\ge 0$.\end{minipage} |
| 24 | 26 | \end{table} |
modified
paper/tables/h7_validation.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\small |
| 2 | 2 | \caption{H7 --- Validation of the region--category complexity indicator}\label{tab:h7} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lr}\toprule |
| 4 | 5 | Validation statistic & Value \\\midrule |
| 5 | 6 | Matrix density (share of cells with RAA $\ge$ 1) & 0.409 \\ |
@@ -11,5 +12,6 @@ V2 spectral radius of the bipartite graph: observed, null p95, $p$ & 7.90, 8.79, | ||
| 11 | 12 | V2 corr(ECI, diversity): observed, null [p5; p95] & 0.24, [-0.06; 0.57] \\ |
| 12 | 13 | V4 Louvain communities: mode of count, median NMI across 200 seeds & 2, 1.0 \\ |
| 13 | 14 | \bottomrule\end{tabular} |
| 15 | +\end{adjustbox} | |
| 14 | 16 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} $M_{rc} = 1[\mathrm{RAA}_{rc} \ge 1]$ on merchant-equal weights, regional sample. Null = 2\,000 store-level region reshuffles. Per the preregistration, the ECI is reported as unstable when V1 fails and is omitted from the QDACI.\end{minipage} |
| 15 | 17 | \end{table} |
modified
paper/tables/match_validation.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Validation of the cross-merchant matching tiers (60 pairs per tier)}\label{tab:match_val} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrr}\toprule |
| 4 | 5 | Tier & Pairs with consensus & Same product & Different & Same product, comparable-variant pairs \\\midrule |
| 5 | 6 | A & 56 & 0.92 & 0.02 & 0.90 \\ |
@@ -7,5 +8,6 @@ B & 54 & 0.90 & 0.00 & 0.96 \\ | ||
| 7 | 8 | C & 52 & 0.77 & 0.10 & 0.77 \\ |
| 8 | 9 | D & 48 & 0.17 & 0.60 & 0.19 \\ |
| 9 | 10 | \bottomrule\end{tabular} |
| 11 | +\end{adjustbox} | |
| 10 | 12 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Two independent LLM annotators (agreement 0.88; consensus on 88\% of pairs). Tier A = shared merchant SKU; B = same brand and identical normalised title; C = same brand, fuzzy title; D = identical title without brand (never used for inference).\end{minipage} |
| 11 | 13 | \end{table} |
modified
paper/tables/qdaci.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\scriptsize |
| 2 | 2 | \caption{QDACI components by region}\label{tab:qdaci} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrrrrrrrrrrr}\toprule |
| 4 | 5 | Region & diversity\_rarefied & diversity\_lo & diversity\_hi & specialization & specialization\_lo & specialization\_hi & concentration\_gini & coverage\_stores\_per\_100k & price\_effect & price\_effect\_se & composite\_equal & composite\_pca & composite\_borda \\\midrule |
| 5 | 6 | Abitibi-Témiscamingue & 0.85 & 0.81 & 0.88 & 0.74 & 0.62 & 1.63 & 0.81 & 14.05 & -- & -- & 0.73 & 0.23 & 48.00 \\ |
@@ -20,5 +21,6 @@ Nord-du-Québec & -- & -- & -- & 1.08 & 0.77 & 1.48 & -- & 6.31 & -- & -- & -- & | ||
| 20 | 21 | Outaouais & 0.80 & 0.73 & 0.86 & 0.43 & 0.38 & 0.93 & 0.92 & 8.40 & -- & -- & 0.34 & -1.27 & 23.00 \\ |
| 21 | 22 | Saguenay--Lac-Saint-Jean & 0.79 & 0.70 & 0.86 & 0.34 & 0.33 & 0.52 & 0.80 & 33.87 & -- & -- & 0.67 & -0.53 & 44.00 \\ |
| 22 | 23 | \bottomrule\end{tabular} |
| 24 | +\end{adjustbox} | |
| 23 | 25 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Components describe observed online catalogues of Quebec-based merchants, not production or output. Complexity omitted because the ECI failed the preregistered stability criterion.\end{minipage} |
| 24 | 26 | \end{table} |
modified
paper/tables/raa_top.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Largest significant revealed assortment advantages (merchant-equal weights)}\label{tab:raa_top} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrr}\toprule |
| 4 | 5 | Region & Category & RAA & 95\% CI & Merchant-equal weight \\\midrule |
| 5 | 6 | Gaspésie--Îles-de-la-Madeleine & Fashion & 3.79 & [2.05; 5.76] & 6.2 \\ |
@@ -16,5 +17,6 @@ Estrie & Alcohol & 1.57 & [1.05; 2.10] & 13.1 \\ | ||
| 16 | 17 | Lanaudière & Other & 1.49 & [1.03; 1.99] & 14.1 \\ |
| 17 | 18 | Montérégie & Alcohol & 1.46 & [1.01; 1.92] & 15.2 \\ |
| 18 | 19 | \bottomrule\end{tabular} |
| 20 | +\end{adjustbox} | |
| 19 | 21 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Cells with a store-bootstrap 95\% interval above 1, sorted by RAA. The weight column is the merchant-equal count $N_{rc}$ (sum of store shares).\end{minipage} |
| 20 | 22 | \end{table} |
modified
paper/tables/region_summary.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Regional sample: stores, listings, certification and assortment diversity}\label{tab:region_summary} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrrrr}\toprule |
| 4 | 5 | Region & Stores & Listings & Median catalogue & Certified share & $\tilde H$ (M) & $\tilde H$ rarefied (15 stores) [2.5; 97.5] \\\midrule |
| 5 | 6 | Montréal & 237 & 61\,419 & 65 & 0.59 & 0.834 & 0.779 [0.683; 0.857] \\ |
@@ -21,5 +22,6 @@ Abitibi-Témiscamingue & 21 & 5\,206 & 36 & 0.38 & 0.870 & 0.845 [0.808; 0.879] | ||
| 21 | 22 | Côte-Nord & 16 & 587 & 18 & 0.38 & 0.791 & 0.788 [0.762; 0.802] \\ |
| 22 | 23 | Nord-du-Québec & 3 & 276 & 27 & 0.00 & 0.655 & -- \\ |
| 23 | 24 | \bottomrule\end{tabular} |
| 25 | +\end{adjustbox} | |
| 24 | 26 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Assortment sample. $\tilde H$ = normalised Shannon entropy of category shares (20 categories); M = merchant-equal weights. Rarefied entropy = mean over 2\,000 draws of 15 stores without replacement; brackets give the 2.5th and 97.5th percentiles of the draws. `Inconnue' = stores whose location could not be established (excluded from regional inference).\end{minipage} |
| 25 | 27 | \end{table} |
modified
paper/tables/sample_flow.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\small |
| 2 | 2 | \caption{Sample flow from database rows to the analysis samples}\label{tab:sample_flow} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lr}\toprule |
| 4 | 5 | Step & Listings \\\midrule |
| 5 | 6 | DB product rows (all statuses, all stores) & 465\,388 \\ |
@@ -11,5 +12,6 @@ active = 1 and listing\_status = 'published' & 390\,108 \\ | ||
| 11 | 12 | \ldots and CAD-priced store/listing & 369\,325 \\ |
| 12 | 13 | \ldots and a positive listed price <= 50 000 CAD, not on request \textbf{[PRICE SAMPLE]} & 359\,612 \\ |
| 13 | 14 | \bottomrule\end{tabular} |
| 15 | +\end{adjustbox} | |
| 14 | 16 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Snapshot of 2026-11-01T17:38Z. Nothing is deleted: each step is a flag in the cleaned listing table. The assortment sample is used for H1--H4 and H7; the price sample for H5.\end{minipage} |
| 15 | 17 | \end{table} |
modified
paper/tables_model/category_audit.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Audit of the rule-based category labels (500-listing stratified sample)}\label{tab:cat_audit} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrr}\toprule |
| 4 | 5 | Rule label & Listings with annotator consensus & Precision of the rule label \\\midrule |
| 5 | 6 | Maple \& honey & 24 & 0.50 \\ |
@@ -24,5 +25,6 @@ Industrial & 24 & 0.42 \\ | ||
| 24 | 25 | Other & 25 & 0.00 \\ |
| 25 | 26 | \textbf{All} & 474 & \textbf{0.46} \\ |
| 26 | 27 | \bottomrule\end{tabular} |
| 28 | +\end{adjustbox} | |
| 27 | 29 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} 25 random listings per category annotated independently by two LLMs (claude-opus-5-5, gpt-5.5) with the platform's taxonomy; agreement rule vs A 0.45, rule vs B 0.45, A vs B 0.95; consensus exists for 95\% of listings. Precision = share of consensus labels equal to the rule label. Disagreements listed in the replication package.\end{minipage} |
| 28 | 30 | \end{table} |
modified
paper/tables_model/cert_contrast.tex
+2 −0
@@ -1,9 +1,11 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\small |
| 2 | 2 | \caption{Descriptive store-certification price contrast (not a test of H6)}\label{tab:cert} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lr}\toprule |
| 4 | 5 | Statistic & Value \\\midrule |
| 5 | 6 | Observations / stores / certified stores & 288\,663 / 1\,264 / 491 \\ |
| 6 | 7 | Certified store, log price difference within category (SE, store-clustered) & -0.204 (0.138) \\ |
| 7 | 8 | \bottomrule\end{tabular} |
| 9 | +\end{adjustbox} | |
| 8 | 10 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} descriptive store-certification contrast (Aliments du Québec / Les Produits du Québec), category FE, store-clustered SE — NOT a test of H6\end{minipage} |
| 9 | 11 | \end{table} |
modified
paper/tables_model/external_coverage.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Coverage of the regional sample against external business and population counts}\label{tab:external} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrrr}\toprule |
| 4 | 5 | Region & Fabri-Ka stores & Business locations & Stores per 1\,000 businesses & Population & Stores per 100\,000 pop. \\\midrule |
| 5 | 6 | Bas-Saint-Laurent & 39 & 7\,441 & 5.24 & 204\,755 & 19.0 \\ |
@@ -20,5 +21,6 @@ Laurentides & 99 & 22\,002 & 4.50 & 679\,190 & 14.6 \\ | ||
| 20 | 21 | Montérégie & 190 & 44\,787 & 4.24 & 1\,522\,372 & 12.5 \\ |
| 21 | 22 | Centre-du-Québec & 61 & 9\,270 & 6.58 & 264\,820 & 23.0 \\ |
| 22 | 23 | \bottomrule\end{tabular} |
| 24 | +\end{adjustbox} | |
| 23 | 25 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Business locations = ISQ, locations with employees, December 2025 (all industries; retail NAICS 44-45; manufacturing 31-33); population = ISQ 1 July 2025 provisional. Fabri-Ka stores are online storefronts of Quebec-based merchants discovered through certification registries, associations and search; coverage ratios are not sampling rates.\end{minipage} |
| 24 | 26 | \end{table} |
modified
paper/tables_model/h1_raa.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{H1 --- Region $\times$ category dependence against the store-reshuffle null}\label{tab:h1} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrrrrrr}\toprule |
| 4 | 5 | Sample / variant & Weights & Stores & Regions & Cramér's $V$ & Null mean & Null p95 & $p$ (perm.) & Cells RAA$>1$/$<1$ \\\midrule |
| 5 | 6 | S\_R & M & 1\,331 & 17 & 0.111 & 0.086 & 0.093 & 0.0005 & 12/64 \\ |
@@ -18,5 +19,6 @@ drop\_autre & M & 1\,306 & 17 & 0.109 & 0.084 & & 0.001 & \\ | ||
| 18 | 19 | excl\_resellers\_collectives & M & 1\,306 & 17 & 0.111 & 0.086 & & 0.001 & \\ |
| 19 | 20 | excl\_region\_conflicts & M & 1\,301 & 17 & 0.114 & 0.087 & & 0.001 & \\ |
| 20 | 21 | \bottomrule\end{tabular} |
| 22 | +\end{adjustbox} | |
| 21 | 23 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} $V$ = Cramér's $V$ of the region $\times$ category table of listing weights (L = one per listing; M = merchant-equal, each store sums to one; T = listings after dropping the 1\% largest stores; `stores' = count of stores present in the category). Null = 2\,000 permutations of region labels across stores (each region keeps its number of stores, each store keeps its catalogue); $p$ is one-sided. Last column: number of the $R\times C$ cells whose store-bootstrap 95\% interval for RAA lies entirely above / below 1. Variants from the preregistered robustness list (1\,000 permutations).\end{minipage} |
| 22 | 24 | \end{table} |
modified
paper/tables_model/h2_scale.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{H2 --- Regional assortment diversity and regional scale}\label{tab:h2} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrr}\toprule |
| 4 | 5 | Outcome $\sim$ covariate & $n$ & Spearman $\rho$ & 95\% CI & OLS slope (HC3 SE) \\\midrule |
| 5 | 6 | H\_rarefied15 ~ log\_population & 16 & 0.00 & [-0.63; 0.60] & -0.004 (0.017) \\ |
@@ -18,5 +19,6 @@ log\_stores\_per\_100k ~ log\_population & 17 & -0.19 & [-0.61; 0.30] & -- \\ | ||
| 18 | 19 | log\_stores\_per\_100k ~ log\_density & 17 & -0.22 & [-0.71; 0.36] & -- \\ |
| 19 | 20 | log\_stores\_per\_100k ~ disposable\_income & 17 & -0.02 & [-0.49; 0.46] & -- \\ |
| 20 | 21 | \bottomrule\end{tabular} |
| 22 | +\end{adjustbox} | |
| 21 | 23 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} 17 regions at most (Nord-du-Québec has no located store); rarefied diversity needs >= 15 stores. Associations only; CIs from 5 000 region-level bootstrap draws; OLS slope with HC3 SE.\end{minipage} |
| 22 | 24 | \end{table} |
modified
paper/tables_model/h3_concentration.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\small |
| 2 | 2 | \caption{H3 --- Concentration of listings across merchants (assortment sample)}\label{tab:h3} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lr}\toprule |
| 4 | 5 | Statistic & Value \\\midrule |
| 5 | 6 | Stores / listings & 1\,557 / 370\,054 \\ |
@@ -12,5 +13,6 @@ Discrete power law: $x_{\min}$, $\alpha$, KS, tail $n$ & 165, 1.929, 0.028, 288 | ||
| 12 | 13 | Vuong LR (power law vs log-normal on the tail): $z$, $p$ & 4.99, 6e-07 (power-law) \\ |
| 13 | 14 | Preregistered criterion (Gini $\ge$ 0.70 and top-10\% $\ge$ 0.50) & met \\ |
| 14 | 15 | \bottomrule\end{tabular} |
| 16 | +\end{adjustbox} | |
| 15 | 17 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Bootstrap CIs from 2\,000 resamples of stores. Power-law fit by maximum likelihood with $x_{\min}$ chosen by KS minimisation (Clauset et al.\ 2009); the log-normal is fitted on the same tail. Inconnue-region stores included (all stores).\end{minipage} |
| 16 | 18 | \end{table} |
modified
paper/tables_model/h3_within_region.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Within-region concentration of catalogue sizes}\label{tab:h3_region} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrr}\toprule |
| 4 | 5 | Region & Stores & Gini [95\% CI] & Top-10\% share \\\midrule |
| 5 | 6 | Outaouais & 36 & 0.922 [0.632; 0.937] & 0.946 \\ |
@@ -20,5 +21,6 @@ Mauricie & 31 & 0.730 [0.495; 0.792] & 0.701 \\ | ||
| 20 | 21 | Côte-Nord & 16 & 0.517 [0.318; 0.565] & 0.455 \\ |
| 21 | 22 | Nord-du-Québec & 3 & -- & -- \\ |
| 22 | 23 | \bottomrule\end{tabular} |
| 24 | +\end{adjustbox} | |
| 23 | 25 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} 500 store-bootstrap resamples per region; regions with fewer than five stores omitted.\end{minipage} |
| 24 | 26 | \end{table} |
modified
paper/tables_model/h4_dynamics.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\small |
| 2 | 2 | \caption{H4 (exploratory) --- Entry into related categories within stores}\label{tab:h4} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lr}\toprule |
| 4 | 5 | Statistic & Value \\\midrule |
| 5 | 6 | Baseline / outcome windows & 2026-08-31 to 2026-09-27 / 2026-09-28 to 2026-11-01 \\ |
@@ -11,5 +12,6 @@ Placebo (category-relabelled proximity, 200 draws): mean, p95, $p$ & -0.002, 0.0 | ||
| 11 | 12 | Region-level category entries / exits & 3 / 0 \\ |
| 12 | 13 | Share of entering stores with an `added' burst $>$50\% of baseline catalogue & 0.12 \\ |
| 13 | 14 | \bottomrule\end{tabular} |
| 15 | +\end{adjustbox} | |
| 14 | 16 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Linear probability model with store and category fixed effects; density = share of a category's proximity mass covered by the store's baseline portfolio (Hidalgo-type proximity from co-occurrence across stores). Exploratory by preregistration: no causal claim.\end{minipage} |
| 15 | 17 | \end{table} |
modified
paper/tables_model/h5_hedonic.tex
+19 −5
@@ -1,9 +1,23 @@ | ||
| 1 | −\begin{table}[htbp]\centering\scriptsize | |
| 1 | +\begin{table}[htbp]\centering\small | |
| 2 | 2 | \caption{H5 --- Matched-product price dispersion across merchants}\label{tab:h5} |
| 3 | −\begin{tabular}{lrrrrrrrrrrrrr}\toprule | |
| 4 | −Spec. & Obs. & Groups & Stores & Regions & Wald region (df) & $p$ wild-boot & Reseller (SE) & $p$ wild-boot & Certified (SE) & log catalogue (SE) & Within $R^2$ & Gap median / p90 & Share gap $>$5\% \\\midrule | |
| 5 | −primary\_AB & 2\,203 & 1\,064 & 143 & 15 & 164.4 (14) & 0.0045 & -0.116 (0.026) & 0.0012 & -0.073 (0.023) & 0.002 (0.008) & 0.166 & 0.047 / 0.288 & 0.49 \\ | |
| 6 | −sens\_ABC & 2\,512 & 1\,189 & 156 & 15 & 83.3 (14) & 0.0162 & -0.101 (0.025) & 0.0029 & -0.028 (0.018) & 0.009 (0.007) & 0.139 & 0.051 / 0.333 & 0.50 \\ | |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 4 | +\begin{tabular}{lrr}\toprule | |
| 5 | +Statistic & primary\_AB & sens\_ABC \\\midrule | |
| 6 | +Observations & 2\,203 & 2\,512 \\ | |
| 7 | +Match groups & 1\,064 & 1\,189 \\ | |
| 8 | +Stores & 143 & 156 \\ | |
| 9 | +Regions (with $\ge$ 5 matched stores) & 15 (9) & 15 (9) \\ | |
| 10 | +Wald statistic, region effects (df) & 164.4 (14) & 83.3 (14) \\ | |
| 11 | +\quad $p$, wild cluster bootstrap & 0.0045 & 0.0162 \\ | |
| 12 | +Reseller / collective store (SE) & -0.116 (0.026) & -0.101 (0.025) \\ | |
| 13 | +\quad $p$, wild cluster bootstrap & 0.0012 & 0.0029 \\ | |
| 14 | +Certified store (SE) & -0.073 (0.023) & -0.028 (0.018) \\ | |
| 15 | +log catalogue size (SE) & 0.002 (0.008) & 0.009 (0.007) \\ | |
| 16 | +Within-group $R^2$ & 0.166 & 0.139 \\ | |
| 17 | +Within-group gap: median / p90 & 0.047 / 0.288 & 0.051 / 0.333 \\ | |
| 18 | +Share of groups with gap $>$ 5\% & 0.49 & 0.50 \\ | |
| 19 | +Share of groups with identical prices & 0.29 & 0.29 \\ | |
| 7 | 20 | \bottomrule\end{tabular} |
| 21 | +\end{adjustbox} | |
| 8 | 22 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Dependent variable: log posted price at the snapshot. Match-group fixed effects absorbed; region and platform dummies, log catalogue size, reseller/collective and certification indicators. SE clustered by store; $p$-values from a wild cluster bootstrap (Rademacher, 9\,999 draws, restricted residuals). primary\_AB = tiers A (shared SKU) and B (same brand, identical title); sens\_ABC adds fuzzy tier C. Gap = within-group max--min log price.\end{minipage} |
| 9 | 23 | \end{table} |
modified
paper/tables_model/h7_indicators.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Region-level indicators (reported for transparency; unstable under bootstrap)}\label{tab:h7ind} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrr}\toprule |
| 4 | 5 | Region & Stores & Diversity & ECI & Fitness \\\midrule |
| 5 | 6 | Chaudière-Appalaches & 102 & 8 & 1.63 & 1.26 \\ |
@@ -20,5 +21,6 @@ Gaspésie--Îles-de-la-Madeleine & 30 & 5 & -1.25 & 0.50 \\ | ||
| 20 | 21 | Nord-du-Québec & 3 & 5 & -1.39 & 0.57 \\ |
| 21 | 22 | Côte-Nord & 16 & 5 & -1.77 & 0.51 \\ |
| 22 | 23 | \bottomrule\end{tabular} |
| 24 | +\end{adjustbox} | |
| 23 | 25 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Diversity = number of categories with RAA $\ge 1$. ECI standardised; sign fixed so that corr(ECI, diversity) $\ge 0$.\end{minipage} |
| 24 | 26 | \end{table} |
modified
paper/tables_model/h7_validation.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\small |
| 2 | 2 | \caption{H7 --- Validation of the region--category complexity indicator}\label{tab:h7} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lr}\toprule |
| 4 | 5 | Validation statistic & Value \\\midrule |
| 5 | 6 | Matrix density (share of cells with RAA $\ge$ 1) & 0.397 \\ |
@@ -11,5 +12,6 @@ V2 spectral radius of the bipartite graph: observed, null p95, $p$ & 7.73, 8.79, | ||
| 11 | 12 | V2 corr(ECI, diversity): observed, null [p5; p95] & 0.43, [-0.09; 0.57] \\ |
| 12 | 13 | V4 Louvain communities: mode of count, median NMI across 200 seeds & 2, 1.0 \\ |
| 13 | 14 | \bottomrule\end{tabular} |
| 15 | +\end{adjustbox} | |
| 14 | 16 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} $M_{rc} = 1[\mathrm{RAA}_{rc} \ge 1]$ on merchant-equal weights, regional sample. Null = 2\,000 store-level region reshuffles. Per the preregistration, the ECI is reported as unstable when V1 fails and is omitted from the QDACI.\end{minipage} |
| 15 | 17 | \end{table} |
modified
paper/tables_model/match_validation.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Validation of the cross-merchant matching tiers (60 pairs per tier)}\label{tab:match_val} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrr}\toprule |
| 4 | 5 | Tier & Pairs with consensus & Same product & Different & Same product, comparable-variant pairs \\\midrule |
| 5 | 6 | A & 56 & 0.92 & 0.02 & 0.90 \\ |
@@ -7,5 +8,6 @@ B & 54 & 0.90 & 0.00 & 0.96 \\ | ||
| 7 | 8 | C & 52 & 0.77 & 0.10 & 0.77 \\ |
| 8 | 9 | D & 48 & 0.17 & 0.60 & 0.19 \\ |
| 9 | 10 | \bottomrule\end{tabular} |
| 11 | +\end{adjustbox} | |
| 10 | 12 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Two independent LLM annotators (agreement 0.88; consensus on 88\% of pairs). Tier A = shared merchant SKU; B = same brand and identical normalised title; C = same brand, fuzzy title; D = identical title without brand (never used for inference).\end{minipage} |
| 11 | 13 | \end{table} |
modified
paper/tables_model/qdaci.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\scriptsize |
| 2 | 2 | \caption{QDACI components by region}\label{tab:qdaci} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrrrrrrrrrrr}\toprule |
| 4 | 5 | Region & diversity\_rarefied & diversity\_lo & diversity\_hi & specialization & specialization\_lo & specialization\_hi & concentration\_gini & coverage\_stores\_per\_100k & price\_effect & price\_effect\_se & composite\_equal & composite\_pca & composite\_borda \\\midrule |
| 5 | 6 | Abitibi-Témiscamingue & 0.89 & 0.86 & 0.91 & 0.54 & 0.55 & 1.17 & 0.81 & 14.05 & -- & -- & 0.64 & -1.67 & 42.00 \\ |
@@ -20,5 +21,6 @@ Nord-du-Québec & -- & -- & -- & 1.03 & 0.85 & 1.31 & -- & 6.31 & -- & -- & -- & | ||
| 20 | 21 | Outaouais & 0.81 & 0.73 & 0.88 & 0.57 & 0.51 & 1.54 & 0.92 & 8.40 & -- & -- & 0.42 & -0.97 & 28.00 \\ |
| 21 | 22 | Saguenay--Lac-Saint-Jean & 0.79 & 0.70 & 0.86 & 0.51 & 0.43 & 0.75 & 0.80 & 33.87 & -- & -- & 0.70 & -0.39 & 46.00 \\ |
| 22 | 23 | \bottomrule\end{tabular} |
| 24 | +\end{adjustbox} | |
| 23 | 25 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Components describe observed online catalogues of Quebec-based merchants, not production or output. Complexity omitted because the ECI failed the preregistered stability criterion.\end{minipage} |
| 24 | 26 | \end{table} |
modified
paper/tables_model/raa_top.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Largest significant revealed assortment advantages (merchant-equal weights)}\label{tab:raa_top} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrr}\toprule |
| 4 | 5 | Region & Category & RAA & 95\% CI & Merchant-equal weight \\\midrule |
| 5 | 6 | Montérégie & Pets & 2.89 & [1.40; 4.23] & 4.5 \\ |
@@ -15,5 +16,6 @@ Estrie & Maple \& honey & 1.78 & [1.22; 2.39] & 17.5 \\ | ||
| 15 | 16 | Estrie & Alcohol & 1.75 & [1.09; 2.41] & 12.5 \\ |
| 16 | 17 | Montréal & Children & 1.74 & [1.06; 2.43] & 7.5 \\ |
| 17 | 18 | \bottomrule\end{tabular} |
| 19 | +\end{adjustbox} | |
| 18 | 20 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Cells with a store-bootstrap 95\% interval above 1, sorted by RAA. The weight column is the merchant-equal count $N_{rc}$ (sum of store shares).\end{minipage} |
| 19 | 21 | \end{table} |
modified
paper/tables_model/region_summary.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\footnotesize |
| 2 | 2 | \caption{Regional sample: stores, listings, certification and assortment diversity}\label{tab:region_summary} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lrrrrrr}\toprule |
| 4 | 5 | Region & Stores & Listings & Median catalogue & Certified share & $\tilde H$ (M) & $\tilde H$ rarefied (15 stores) [2.5; 97.5] \\\midrule |
| 5 | 6 | Montréal & 237 & 61\,419 & 65 & 0.59 & 0.829 & 0.741 [0.638; 0.833] \\ |
@@ -21,5 +22,6 @@ Abitibi-Témiscamingue & 21 & 5\,206 & 36 & 0.38 & 0.914 & 0.887 [0.855; 0.912] | ||
| 21 | 22 | Côte-Nord & 16 & 587 & 18 & 0.38 & 0.735 & 0.731 [0.704; 0.750] \\ |
| 22 | 23 | Nord-du-Québec & 3 & 276 & 27 & 0.00 & 0.661 & -- \\ |
| 23 | 24 | \bottomrule\end{tabular} |
| 25 | +\end{adjustbox} | |
| 24 | 26 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Assortment sample. $\tilde H$ = normalised Shannon entropy of category shares (20 categories); M = merchant-equal weights. Rarefied entropy = mean over 2\,000 draws of 15 stores without replacement; brackets give the 2.5th and 97.5th percentiles of the draws. `Inconnue' = stores whose location could not be established (excluded from regional inference).\end{minipage} |
| 25 | 27 | \end{table} |
modified
paper/tables_model/sample_flow.tex
+2 −0
@@ -1,5 +1,6 @@ | ||
| 1 | 1 | \begin{table}[htbp]\centering\small |
| 2 | 2 | \caption{Sample flow from database rows to the analysis samples}\label{tab:sample_flow} |
| 3 | +\begin{adjustbox}{max width=\textwidth} | |
| 3 | 4 | \begin{tabular}{lr}\toprule |
| 4 | 5 | Step & Listings \\\midrule |
| 5 | 6 | DB product rows (all statuses, all stores) & 465\,388 \\ |
@@ -11,5 +12,6 @@ active = 1 and listing\_status = 'published' & 390\,108 \\ | ||
| 11 | 12 | \ldots and CAD-priced store/listing & 369\,325 \\ |
| 12 | 13 | \ldots and a positive listed price <= 50 000 CAD, not on request \textbf{[PRICE SAMPLE]} & 359\,612 \\ |
| 13 | 14 | \bottomrule\end{tabular} |
| 15 | +\end{adjustbox} | |
| 14 | 16 | \begin{minipage}{0.95\textwidth}\vspace{2pt}\footnotesize\textit{Notes:} Snapshot of 2026-11-01T17:38Z. Nothing is deleted: each step is a flag in the cleaned listing table. The assortment sample is used for H1--H4 and H7; the price sample for H5.\end{minipage} |
| 15 | 17 | \end{table} |
modified
src/reports/make_figures.py
+4 −3
@@ -152,14 +152,15 @@ def fig_map(): | ||
| 152 | 152 | if layer is not None: break |
| 153 | 153 | if layer is None: |
| 154 | 154 | log.warning("no region layer: map skipped"); return |
| 155 | − layer["region"] = layer.region.map(lambda v: next((r for r in REGIONS if r == v or r.replace("–", "-") == v), v)) | |
| 155 | + layer["region"] = layer.region.map(lambda v: next((r for r in REGIONS if r == v or r.replace("–", "-") == v), v)); layer["geometry"] = layer.geometry.simplify(1500) | |
| 156 | 156 | sp = pd.read_parquet(PROC / "store_panel.parquet"); cnt = sp[sp.region_final != "Inconnue"].groupby("region_final").agg(stores=("id", "size"), listings=("n_listings", "sum")) |
| 157 | 157 | layer = layer.merge(cnt, left_on="region", right_index=True, how="left") |
| 158 | 158 | pts = sp[sp.lat.notna()]; gp = gpd.GeoDataFrame(pts, geometry=gpd.points_from_xy(pts.lng, pts.lat), crs=4326).to_crs(32198) |
| 159 | − fig, axes = plt.subplots(1, 2, figsize=(9, 4.6)) | |
| 159 | + fig, axes = plt.subplots(1, 2, figsize=(9, 3.6)) | |
| 160 | 160 | layer.plot(column="stores", cmap=SEQ, ax=axes[0], edgecolor="white", linewidth=0.5, legend=True, legend_kwds={"shrink": 0.5, "label": "stores with known region"}) |
| 161 | 161 | layer.plot(color="#f2f2ef", edgecolor="white", linewidth=0.5, ax=axes[1]); gp.plot(ax=axes[1], markersize=np.sqrt(gp.n_listings.clip(1, 5000)) * 0.6, color=C[1], alpha=0.5, linewidth=0) |
| 162 | − for ax in axes: ax.set_axis_off(); ax.set_xlim(layer.total_bounds[0] - 5e4, min(layer.total_bounds[2], -5.5e5) + 2e5) | |
| 162 | + xs, ys = gp.geometry.x, gp.geometry.y; x0, x1 = np.percentile(xs, [0.5, 99.5]); y0, y1 = np.percentile(ys, [0.5, 99.5]) | |
| 163 | + for ax in axes: ax.set_axis_off(); ax.set_xlim(x0 - 6e4, x1 + 6e4); ax.set_ylim(y0 - 6e4, y1 + 6e4); ax.set_aspect("equal") | |
| 163 | 164 | axes[0].set_title("Stores per administrative region", fontsize=9); axes[1].set_title("Store locations (FSA centroids), size ∝ √listings", fontsize=9) |
| 164 | 165 | save(fig, "coverage_map"); caption("coverage_map", f"Coverage of the regional sample: {int(cnt.stores.sum())} stores with a known region (left) and FSA-centroid locations of {len(gp)} geocoded stores (right); the southern part of the province is shown. Official administrative-region boundaries. {SRC}") |
| 165 | 166 | |
modified
src/reports/make_tables.py
+11 −12
@@ -18,8 +18,8 @@ def J(name): return json.load(open(EXP / name)) | ||
| 18 | 18 | def write(name, header, rows, caption, label, notes="", align=None, size="\\small"): |
| 19 | 19 | align = align or "l" + "r" * (len(header) - 1) |
| 20 | 20 | body = "\n".join(" & ".join(map(str, r)) + " \\\\" for r in rows) |
| 21 | − tex = (f"\\begin{{table}}[htbp]\\centering{size}\n\\caption{{{caption}}}\\label{{tab:{label}}}\n\\begin{{tabular}}{{{align}}}\\toprule\n" + " & ".join(header) + " \\\\\\midrule\n" + body + | |
| 22 | − "\n\\bottomrule\\end{tabular}\n" + (f"\\begin{{minipage}}{{0.95\\textwidth}}\\vspace{{2pt}}\\footnotesize\\textit{{Notes:}} {notes}\\end{{minipage}}\n" if notes else "") + "\\end{table}\n") | |
| 21 | + tex = (f"\\begin{{table}}[htbp]\\centering{size}\n\\caption{{{caption}}}\\label{{tab:{label}}}\n\\begin{{adjustbox}}{{max width=\\textwidth}}\n\\begin{{tabular}}{{{align}}}\\toprule\n" + " & ".join(header) + " \\\\\\midrule\n" + body + | |
| 22 | + "\n\\bottomrule\\end{tabular}\n\\end{adjustbox}\n" + (f"\\begin{{minipage}}{{0.95\\textwidth}}\\vspace{{2pt}}\\footnotesize\\textit{{Notes:}} {notes}\\end{{minipage}}\n" if notes else "") + "\\end{table}\n") | |
| 23 | 23 | (TAB / f"{name}.tex").write_text(tex); log.info("table %s", name) |
| 24 | 24 | |
| 25 | 25 | |
@@ -75,16 +75,15 @@ def t_h3(): | ||
| 75 | 75 | |
| 76 | 76 | |
| 77 | 77 | def t_h5(): |
| 78 | − h = J("h5_hedonic.json"); rows = [] | |
| 79 | − for m in h["models"]: | |
| 80 | − if m.get("status") == "insufficient": continue | |
| 81 | − c = m["coef"] | |
| 82 | − rows.append([m["label"].replace("_", "\\_"), n(m["obs"]), n(m["groups"]), m["stores"], m["regions"], f"{m['wald_region']:.1f} ({m['df_region']})", f"{m['p_region_wildboot']:.4f}", | |
| 83 | − f"{c['reseller']['b']:.3f} ({c['reseller']['se_cluster']:.3f})", f"{m['p_reseller_wildboot']:.4f}", f"{c['certified']['b']:.3f} ({c['certified']['se_cluster']:.3f})", f"{c['log_n']['b']:.3f} ({c['log_n']['se_cluster']:.3f})", | |
| 84 | − f"{m['within_R2']:.3f}", f"{m['gap_median']:.3f} / {m['gap_p90']:.3f}", f"{m['share_gap_gt5pct']:.2f}"]) | |
| 85 | − write("h5_hedonic", ["Spec.", "Obs.", "Groups", "Stores", "Regions", "Wald region (df)", "$p$ wild-boot", "Reseller (SE)", "$p$ wild-boot", "Certified (SE)", "log catalogue (SE)", "Within $R^2$", "Gap median / p90", "Share gap $>$5\\%"], rows, | |
| 86 | − "H5 --- Matched-product price dispersion across merchants", "h5", | |
| 87 | − "Dependent variable: log posted price at the snapshot. Match-group fixed effects absorbed; region and platform dummies, log catalogue size, reseller/collective and certification indicators. SE clustered by store; $p$-values from a wild cluster bootstrap (Rademacher, 9\\,999 draws, restricted residuals). primary\\_AB = tiers A (shared SKU) and B (same brand, identical title); sens\\_ABC adds fuzzy tier C. Gap = within-group max--min log price.", size="\\scriptsize", align="l" + "r" * 13) | |
| 78 | + h = J("h5_hedonic.json"); ms = [m for m in h["models"] if m.get("status") != "insufficient"] | |
| 79 | + def row(lbl, f): return [lbl] + [f(m) for m in ms] | |
| 80 | + c = lambda m, k: f"{m['coef'][k]['b']:.3f} ({m['coef'][k]['se_cluster']:.3f})" | |
| 81 | + rows = [row("Observations", lambda m: n(m["obs"])), row("Match groups", lambda m: n(m["groups"])), row("Stores", lambda m: str(m["stores"])), row("Regions (with $\\ge$ 5 matched stores)", lambda m: f"{m['regions']} ({m['regions_with_ge5_stores']})"), | |
| 82 | + row("Wald statistic, region effects (df)", lambda m: f"{m['wald_region']:.1f} ({m['df_region']})"), row("\\quad $p$, wild cluster bootstrap", lambda m: f"{m['p_region_wildboot']:.4f}"), | |
| 83 | + row("Reseller / collective store (SE)", lambda m: c(m, "reseller")), row("\\quad $p$, wild cluster bootstrap", lambda m: f"{m['p_reseller_wildboot']:.4f}"), row("Certified store (SE)", lambda m: c(m, "certified")), row("log catalogue size (SE)", lambda m: c(m, "log_n")), | |
| 84 | + row("Within-group $R^2$", lambda m: f"{m['within_R2']:.3f}"), row("Within-group gap: median / p90", lambda m: f"{m['gap_median']:.3f} / {m['gap_p90']:.3f}"), row("Share of groups with gap $>$ 5\\%", lambda m: f"{m['share_gap_gt5pct']:.2f}"), row("Share of groups with identical prices", lambda m: f"{m['share_gap_zero']:.2f}")] | |
| 85 | + write("h5_hedonic", ["Statistic"] + [m["label"].replace("_", "\\_") for m in ms], rows, "H5 --- Matched-product price dispersion across merchants", "h5", | |
| 86 | + "Dependent variable: log posted price at the snapshot. Match-group fixed effects absorbed; region and platform dummies, log catalogue size, reseller/collective and certification indicators. SE clustered by store; $p$-values from a wild cluster bootstrap (Rademacher, 9\\,999 draws, restricted residuals). primary\\_AB = tiers A (shared SKU) and B (same brand, identical title); sens\\_ABC adds fuzzy tier C. Gap = within-group max--min log price.", align="l" + "r" * len(ms)) | |
| 88 | 87 | cc = h["certification_contrast"] |
| 89 | 88 | write("cert_contrast", ["Statistic", "Value"], [["Observations / stores / certified stores", f"{n(cc['obs'])} / {n(cc['stores'])} / {n(cc['certified_stores'])}"], ["Certified store, log price difference within category (SE, store-clustered)", f"{cc['b_log_price']:.3f} ({cc['se']:.3f})"]], |
| 90 | 89 | "Descriptive store-certification price contrast (not a test of H6)", "cert", esc(cc["note"]), align="lr") |
| 91 | 90 | |