SPB Git

spb/wp37_uqo

Public
7.5 KB · 97 lines python
1"""Phase 1.2 — canonical `retailers` table: company → banner → source feed → channel.23Ownership/affiliation is taken from the Food-Ka registry text (`region`, `tech`) and from public corporate4information; the column `ownership_basis` records which. Items marked 'public-corporate' are re-verified in5Phase 2 (institutional context) and any correction is logged.6"""7from __future__ import annotations8import pandas as pd9from src.common import path, get_logger, ledger1011log = get_logger("retailers")1213# feed id -> (company, banner, channel, format, ownership_basis)14MAP = {15 "metro": ("Metro Inc.", "Metro", "online_storefront", "supermarket", "public-corporate"),16 "metro_flyer": ("Metro Inc.", "Metro", "circular", "supermarket", "public-corporate"),17 "superc": ("Metro Inc.", "Super C", "online_storefront", "discount", "public-corporate"),18 "superc_flyer": ("Metro Inc.", "Super C", "circular", "discount", "public-corporate"),19 "adonis": ("Metro Inc.", "Marché Adonis", "online_storefront", "ethnic_supermarket", "public-corporate"),20 "adonis_flyer": ("Metro Inc.", "Marché Adonis", "circular", "ethnic_supermarket", "public-corporate"),21 "richelieu": ("Metro Inc. (affiliate)", "Marché Richelieu", "circular", "proximity", "registry"),22 "marche_ami": ("Metro Inc. (affiliate)", "Marché Ami", "circular", "proximity", "registry"),23 "axep": ("Metro Inc. (affiliate)", "Axep", "circular", "proximity", "registry"),24 "jean_coutu": ("Metro Inc.", "Jean Coutu", "circular", "pharmacy", "public-corporate"),25 "brunet": ("Metro Inc.", "Brunet", "circular", "pharmacy", "public-corporate"),26 "maxi": ("Loblaw Companies", "Maxi", "online_storefront", "discount", "public-corporate"),27 "maxi_flyer": ("Loblaw Companies", "Maxi", "circular", "discount", "public-corporate"),28 "provigo": ("Loblaw Companies", "Provigo", "online_storefront", "supermarket", "public-corporate"),29 "provigo_flyer": ("Loblaw Companies", "Provigo", "circular", "supermarket", "public-corporate"),30 "club_entrepot": ("Loblaw Companies", "Club Entrepôt", "online_storefront", "wholesale_club", "registry"),31 "pharmaprix": ("Loblaw Companies", "Pharmaprix", "circular", "pharmacy", "public-corporate"),32 "tt": ("Loblaw Companies", "T&T Supermarket", "online_storefront", "ethnic_supermarket", "public-corporate"),33 "inter_marche": ("Loblaw Companies (affiliate)", "L'Inter-Marché", "circular", "proximity", "registry"),34 "inter_marche_intl": ("Loblaw Companies (affiliate)", "L'Inter-Marché International", "circular", "ethnic_supermarket", "registry"),35 "iga": ("Sobeys / Empire", "IGA", "online_storefront", "supermarket", "public-corporate"),36 "iga_flyer": ("Sobeys / Empire", "IGA", "circular", "supermarket", "public-corporate"),37 "tradition": ("Sobeys / Empire", "Les Marchés Tradition", "circular", "proximity", "registry"),38 "bonichoix": ("Sobeys / Empire", "Marché Bonichoix", "circular", "proximity", "registry"),39 "rachelle_bery": ("Sobeys / Empire", "Rachelle-Béry", "circular", "health_specialty", "public-corporate"),40 "walmart": ("Walmart Canada", "Walmart", "online_storefront", "mass_merchant", "public-corporate"),41 "walmart_flyer": ("Walmart Canada", "Walmart", "circular", "mass_merchant", "public-corporate"),42 "costco": ("Costco Wholesale Canada", "Costco", "online_storefront", "warehouse_club", "public-corporate"),43 "costco_flyer": ("Costco Wholesale Canada", "Costco", "circular", "warehouse_club", "public-corporate"),44 "giant_tiger": ("Giant Tiger Stores", "Giant Tiger", "online_storefront", "discount_general", "public-corporate"),45 "avril": ("Avril Supermarché Santé", "Avril", "online_storefront", "health_specialty", "registry"),46 "avril_flyer": ("Avril Supermarché Santé", "Avril", "circular", "health_specialty", "registry"),47 "pa": ("Supermarché PA", "PA Supermarché", "online_storefront", "independent_supermarket", "registry"),48 "pa_nature": ("Supermarché PA", "PA Nature", "circular", "health_specialty", "registry"),49 "uniprix": ("McKesson Canada", "Uniprix", "circular", "pharmacy", "public-corporate"),50 "saq": ("Société des alcools du Québec", "SAQ", "online_storefront", "alcohol_monopoly", "registry"),51 "mayrand": ("Groupe Mayrand", "Mayrand", "online_storefront", "cash_and_carry", "registry"),52 "epipresto": ("Epipresto", "Epipresto", "online_storefront", "online_only", "registry"),53 "nuvo": ("Marché Nuvo", "Marché Nuvo", "online_storefront", "independent_supermarket", "registry"),54 "boite_a_grains": ("La Boîte à Grains", "La Boîte à Grains", "online_storefront", "health_specialty", "registry"),55 "bocoboco": ("BocoBoco", "BocoBoco", "online_storefront", "online_only", "registry"),56 "aliments_merci": ("Aliments Merci", "Aliments Merci", "online_storefront", "online_only", "registry"),57 "akhavan": ("Akhavan", "Akhavan", "online_storefront", "ethnic_supermarket", "registry"),58 "aubut": ("Aubut", "Aubut", "online_storefront", "cash_and_carry", "registry"),59 "maturin": ("Maturin", "Maturin", "online_storefront", "online_only", "registry"),60 "tau": ("Marché Tau", "Marché Tau", "online_storefront", "health_specialty", "registry"),61 "loco": ("Épiceries LOCO", "LOCO", "online_storefront", "zero_waste", "registry"),62 "kim_phat": ("Kim Phat", "Kim Phat", "circular", "ethnic_supermarket", "registry"),63 "fu_tai": ("Marché Fu Tai", "Fu Tai", "circular", "ethnic_supermarket", "registry"),64 "marche_ct": ("Marché C&T", "C&T", "circular", "ethnic_supermarket", "registry"),65 "aures": ("Supermarché Aurès", "Aurès", "circular", "ethnic_supermarket", "registry"),66 "euro_marche": ("Euro Marché", "Euro Marché", "circular_hybrid", "ethnic_supermarket", "registry"),67 "val_mont": ("Marché Val-Mont", "Val-Mont", "circular", "independent_supermarket", "registry"),68 "bonanza": ("Marché Bonanza", "Bonanza", "circular", "independent_supermarket", "registry"),69 "pasquier": ("Pasquier", "Pasquier", "circular", "independent_supermarket", "registry"),70 "marche_vegetarien": ("Le Marché Végétarien", "Marché Végétarien", "circular", "health_specialty", "registry"),71 "aliments_mm": ("Les Aliments M&M", "M&M", "circular", "frozen_specialty", "registry"),72 "bulk_barn": ("Bulk Barn Foods", "Bulk Barn", "none", "bulk_specialty", "public-corporate"),73 "dollarama": ("Dollarama", "Dollarama", "none", "discount_general", "public-corporate"),74 "lufa": ("Fermes Lufa", "Lufa", "none", "online_only", "registry"),75 "frenco": ("Frenco", "Frenco", "none", "bulk_specialty", "registry"),76}7778def main() -> None:79    src = pd.read_parquet(path("interim") / "sources.parquet")80    rows = []81    for _, r in src.iterrows():82        comp, banner, channel, fmt, basis = MAP[r["id"]]83        rows.append(dict(feed_id=r["id"], feed_name=r["name"], company=comp, banner=banner, channel=channel,84                         store_format=fmt, ownership_basis=basis, registry_status=r["status"], registry_region=r["region"],85                         tech=r["tech"], url=r["url"],86                         circular_postal_zone=("H2X 1Y4 (Montréal)" if channel.startswith("circular") else None),87                         store_identified=False, is_grocery=(fmt not in ("pharmacy", "alcohol_monopoly"))))88    ret = pd.DataFrame(rows)89    ret.to_parquet(path("processed") / "retailers.parquet", index=False)90    ret.to_csv(path("processed") / "retailers.csv", index=False)91    log.info("retailers: %d feeds, %d banners, %d companies; channels=%s", len(ret), ret.banner.nunique(), ret.company.nunique(),92             ret.channel.value_counts().to_dict())93    ledger("1", "retailers", f"{len(ret)} feeds -> {ret.banner.nunique()} banners -> {ret.company.nunique()} companies")9495if __name__ == "__main__":96    main()97
Files · b5f3894d9cb67d3aa03e6d556c3801e0b8998456
Menu

Theme