This repository contains the data-processing, descriptive-analysis, and regression code used to study the evolution of retail price dispersion across local markets in Montevideo, Uruguay.
The empirical analysis combines posted retail prices with information on stores, product categories, local income and labor-market conditions, population density, and supermarket chains. The final unit of observation in the baseline regressions is the product-market-month cell, where markets are Montevideo neighborhoods.
The current sample covers April 2007 to December 2024.
The scripts should be run in the following order. The filenames below are suggested names for the corresponding code files.
| Order | Suggested script | Main purpose |
|---|---|---|
| 1 | 01_prepare_store_metadata.R |
Checks the consistency of store identifiers across source files, identifies duplicate stores, and updates the store metadata database. |
| 2 | 02_prepare_ech_income.R |
Harmonizes neighborhood names, detects anomalous ECH observations, and imputes missing monthly income and labor-market variables. |
| 3 | 03_prepare_population_density.R |
Combines the 2004, 2011, and 2023 censuses, constructs monthly neighborhood population series, and calculates population density. |
| 4 | 04_create_price_database.R |
Builds the store-product-month price database and merges product, store, neighborhood, income, population, and CPI information. |
| 5 | 05_create_dispersion_databases.R |
Constructs aggregate, initial-store, between-chain, and within-chain price-dispersion databases. |
| 6 | 06_summary_statistics_figures.R |
Produces summary statistics and descriptive figures on store entry, market size, product coverage, and cell sizes. |
| 7 | 07_price_dispersion_regressions.R |
Estimates the baseline, robustness, chain-decomposition, short-run, lagged, and interaction regressions. |
The code currently uses relative paths such as ../../Bases/raw and ../../Bases/processed. The repository should therefore preserve an equivalent directory structure or update the paths in the scripts.
project/
├── code/
│ ├── 01_prepare_store_metadata.R
│ ├── 02_prepare_ech_income.R
│ ├── 03_prepare_population_density.R
│ ├── 04_create_price_database.R
│ ├── 05_create_dispersion_databases.R
│ ├── 06_summary_statistics_figures.R
│ └── 07_price_dispersion_regressions.R
├── Bases/
│ ├── raw/
│ └── processed/
├── Figures/
└── README.md
The raw and processed databases are not necessarily distributed with the public repository. Their availability depends on the terms of access applying to each source.
The analysis is written in R. The scripts use the following packages:
packages <- c(
"data.table",
"dplyr",
"fixest",
"ggplot2",
"haven",
"imputeTS",
"lubridate",
"readxl",
"scales",
"sf",
"stringi",
"stringr",
"zoo"
)
install.packages(setdiff(packages, rownames(installed.packages())))The sf package may require system libraries for GDAL, GEOS, and PROJ, depending on the operating system.
Package versions were not fixed in the original workflow. For a fully reproducible public archive, using renv is recommended:
install.packages("renv")
renv::init()
renv::snapshot()The store-preparation script uses establishment files for 2023 and 2025, together with a previously checked store-neighborhood crosswalk.
Main inputs include:
Bases/raw/Establecimiento2023.csv
Bases/raw/2025 Establecimientos.csv
Bases/processed/dgc_stores_final.csv
Bases/processed/P_6_MVD_BARRIOS.csv
The script standardizes names, removes accents, compares addresses across vintages, identifies duplicate store records, and selects new stores to add to the store database.
Neighborhood-level income, employment, and unemployment variables are constructed from the ECH database.
Main input:
Bases/raw/ECH_2007a2024.csv
The script:
- harmonizes ECH and INE neighborhood names;
- constructs the monthly time index;
- detects large month-to-month changes using fixed thresholds and neighborhood-specific median absolute deviations;
- replaces hard outliers with missing values;
- interpolates short gaps;
- uses Kalman smoothing for longer gaps; and
- applies city-level fallback rules when necessary.
Main outputs:
Bases/processed/ECH_for_imputation_2024.csv
Bases/processed/inc_long_imputed_mvd.csv
Bases/processed/inc_wide_imputed_mvd.csv
Neighborhood population is constructed from the 2004, 2011, and 2023 population censuses. The script harmonizes neighborhood identifiers, merges census totals, and uses neighborhood area from the 2023 geospatial census file.
Main inputs include:
Bases/raw/INE/Censo 2004 fase I/1.Base Microdatos/Bases 2004 SAV/Bases 2004 por departamentoSAV/d1.sav
Bases/processed/P_6_MVD_BARRIOS_poblacion censo 2011.csv
Bases/raw/INE/Unidades Geoestadisticas Censo 2023/barrios_mvd_23_pg.gpkg
The 2004 census microdata were downloaded from the UMAD repository of the Facultad de Ciencias Sociales. The script treats the census observations as dated in December of each census year and constructs monthly neighborhood population from March 2007 through December 2024. Population between censuses is linearly interpolated. Values before the first and after the last census are linearly extrapolated using the slope of the nearest census interval.
The script also creates a step-function population series as a diagnostic, although the price database uses the linear series. Monthly population density is calculated as linear population divided by neighborhood area in square kilometers.
Main outputs:
Bases/processed/population_INE_census.csv
Bases/processed/poblacion_mensual_2007m3_2024m12.csv
Bases/processed/population_density_monthly_2007m3_2024m12.csv
The price database is built from monthly posted prices and merged with product categories, store characteristics, neighborhood variables, and the CPI.
Main inputs include:
Bases/raw/Base2024MonthlyClean.csv
Bases/raw/lista_productos_2014_web_MEF_empresas_lz.xls
Bases/raw/IPC.csv
Bases/processed/dgc_stores_final.csv
Bases/processed/P_6_MVD_BARRIOS.csv
Bases/processed/inc_long_imputed_mvd.csv
Bases/processed/population_density_monthly_2007m3_2024m12.csv
Main output:
Bases/processed/2026_dbase.csv
This database has one observation per store-product-month before the construction of local-market aggregates.
Price dispersion is computed using the log CPI-adjusted price, lpmode_r.
For each product-market-month cell, the scripts construct:
ave_real_price: average log CPI-adjusted price;sd_real_price: standard deviation of log CPI-adjusted prices across stores;w_disp: number of stores with nonmissing prices in the cell;category_disp: entropy-based measure of category variety;num_stores_comp: number of competing stores in the market-month; andsd_sh_prod: dispersion in stores' product shares.
The following analysis databases are produced:
Bases/processed/2026_aggregate_dispersion.csv
Bases/processed/2026_dispersion_initial_stores.csv
Bases/processed/2026_dispersion_between_chains.csv
Bases/processed/2026_dispersion_within_chains.csv
The aggregate database retains one observation per product-market-month. Price dispersion is computed across all stores observed in the cell.
The initial-store database restricts the sample to stores already observed in 2007. It is used to assess whether the estimated trend is driven by store entry or changes in sample composition.
For chain stores, store-level observations are first collapsed to chain-level medians within product-market-month-chain cells. Independent stores remain separate sellers. Dispersion is then computed across these chain and independent-store units.
Within-chain dispersion is computed across stores belonging to the same chain within each product-market-month-chain cell.
The descriptive script reports statistics at three levels:
- Panel A: store-product-month observations;
- Panel B: product-market-month cells; and
- Panel C: market-month characteristics.
It also produces descriptive figures on:
- store entry by neighborhood and year;
- the distribution of stores per market-month;
- the distribution of stores per product-market-month; and
- the number of products observed by year.
Figures are written to the Figures/ directory or, in a few cases, to Bases/processed/. These paths can be standardized before public release.
The regression script uses fixest::feols() and weights each product-market-month cell by the number of stores used to compute price dispersion.
The main dependent variable is:
sd_real_price * 100Thus, coefficients are expressed in percentage-point units of the standard deviation of log real prices.
Standard errors are clustered by product category and neighborhood. The specifications include combinations of:
- product fixed effects;
- neighborhood fixed effects;
- month-of-year fixed effects; and
- product-by-neighborhood fixed effects.
The script estimates:
- baseline linear time trends;
- quadratic time trends;
- trends in average prices;
- regressions restricted to initial-sample stores;
- regressions excluding high-entry markets;
- between-chain and within-chain trends;
- contemporaneous local-market correlates;
- one- and three-month lag specifications; and
- interactions between time and local-market characteristics.
LaTeX tables are generated with fixest::etable().
From an R session located in the code directory, run the scripts sequentially:
source("01_prepare_store_metadata.R")
source("02_prepare_ech_income.R")
source("03_prepare_population_density.R")
source("04_create_price_database.R")
source("05_create_dispersion_databases.R")
source("06_summary_statistics_figures.R")
source("07_price_dispersion_regressions.R")Because the scripts use relative paths, running them from a different working directory may produce file-not-found errors. A more portable version of the repository could replace the current paths with here::here().
Temporary objects use the prefix tmp_. Each major section removes these objects after their final use. Regression objects are removed after the last etable() call in which they appear. This reduces memory use when the complete regression script is run in a single R session.
Before publishing the repository:
- verify which raw data files may legally be redistributed;
- remove confidential or restricted microdata;
- add a
.gitignoreexcluding raw and large processed databases; - include a data-access statement for files that cannot be shared; and
- record the R and package versions used for the final paper results.
A basic .gitignore could include:
.Rhistory
.RData
.Rproj.user/
.DS_Store
Bases/raw/
Bases/processed/*.csv
Do not exclude processed files that are intended to be part of the replication package.
If you use this code, please cite the associated paper. The final bibliographic reference and repository DOI should be added here once available.
Author: Leandro Zipitría
Contact: leandro.zipitria@cienciassociales.edu.uy