Bozeman CRE Market Report — Retail / Industrial / Office (For Lease)
Run Deploy Instructions
Run / Refresh Instructions — Bozeman CRE Market Report
This is a data + report deliverable. No server or build step is required to read it.
Read it
- Open
data/market-real-estate-report.mdin any Markdown viewer (or GitHub). - Open
data/listings.csvanddata/sector-lease-averages.csvin Excel, Google Sheets, or Numbers.
Re-compute the sector averages (verification)
The averages are the arithmetic mean of asking_rate_usd_per_sf_yr for Bozeman rows with a rate. Reproduce with Python 3:
import csv
from collections import defaultdict
rows = list(csv.DictReader(open("data/listings.csv", encoding="utf-8")))
by_sector = defaultdict(list)
for r in rows:
rate = r["asking_rate_usd_per_sf_yr"].strip()
if rate and r["city"] == "Bozeman":
by_sector[r["sector"]].append(float(rate))
for sector in sorted(by_sector):
vals = by_sector[sector]
print(f"{sector}: n={len(vals)} avg=${sum(vals)/len(vals):.2f} "
f"min=${min(vals):.2f} max=${max(vals):.2f}")
all_vals = [v for vals in by_sector.values() for v in vals]
print(f"BLENDED: n={len(all_vals)} avg=${sum(all_vals)/len(all_vals):.2f}")
Expected output:
Industrial: n=31 avg=$14.52 min=$6.50 max=$19.00
Office: n=19 avg=$27.55 min=$18.00 max=$38.00
Retail: n=22 avg=$28.06 min=$15.00 max=$50.00
BLENDED: n=72 avg=$22.09
Refresh the data (re-pull listings)
- Re-open the source URLs in
data/source-log.csv(LoopNet, Bozeman Real Estate Group, PropertyShark, etc.). - Update
asking_rate_usd_per_sf_yr,available_sf, andretrieved_atfor changed rows; add/remove listings as inventory turns. - Re-run the Python snippet above to recompute averages.
- Update the headline tables in
README.mdanddata/market-real-estate-report.md.
Smoke test
listings.csvopens with one header row + listing rows; everylisting_idis unique.- Every
listing_idinlistings.csvhas a matching row insource-log.csv. - Re-computed averages match
sector-lease-averages.csvandverification-report.json.