"""Control de sesgo: ¿está OSM igual de mapeado en toda España? Importa porque el modelo mide aislamiento como "distancia al edificio más cercano". Si una comunidad tiene los edificios a medio mapear, sus celdas saldrán aisladas por un hueco en los datos y no por estar lejos de nada. El import del Catastro cubre casi toda España pero no Navarra ni Euskadi, que tienen catastro propio, así que el sesgo es esperable y hay que cuantificarlo. Como no usamos datos externos de población, el contraste es interno: viales por km2 (que en España están mapeados de forma homogénea) frente a edificios por km2. Si la proporción se desploma en una región, es un agujero de datos. """ import pickle import sys import numpy as np import rasterio.features from shapely.geometry import mapping sys.path.insert(0, str(__file__.rsplit("/", 1)[0])) import config as C STEP_M = 60.0 # espaciado de densificación usado en extract_osm def main(): with open(C.INTERIM / "area_admin_region.pkl", "rb") as fh: regs = [r for r in pickle.load(fh) if r["geom"].area > 1e6] regs.sort(key=lambda r: -r["geom"].area) rid = rasterio.features.rasterize( [(mapping(r["geom"]), i + 1) for i, r in enumerate(regs)], out_shape=(C.HEIGHT, C.WIDTH), transform=C.TRANSFORM, fill=0, dtype=np.uint8, all_touched=False) def counts_for(base): a = np.load(C.INTERIM / f"{base}.npy") r, c = C.xy_to_rowcol(a[0], a[1]) ok = C.inside(r, c) ids = rid[r[ok], c[ok]] return np.bincount(ids, minlength=len(regs) + 1) b = counts_for("buildings") v = counts_for("line_minor") + counts_for("line_track") cells = np.bincount(rid.ravel(), minlength=len(regs) + 1) print(f"{'comunidad':24s} {'km2':>8s} {'edif':>10s} {'edif/km2':>9s} " f"{'vial km':>9s} {'edif/vial-km':>13s}") print("-" * 78) ratios = [] for i, r in enumerate(regs, start=1): km2 = cells[i] * 0.01 if km2 < 100: continue vial_km = v[i] * STEP_M / 1000.0 ratio = b[i] / vial_km if vial_km else 0 ratios.append((ratio, r["name"])) print(f"{r['name'][:24]:24s} {km2:8,.0f} {b[i]:10,} {b[i]/km2:9.1f} " f"{vial_km:9,.0f} {ratio:13.2f}") med = np.median([x for x, _ in ratios]) print("-" * 78) print(f"mediana edif/vial-km: {med:.2f}") print("\nregiones con menos de la mitad de la mediana " "(sospecha de infra-mapeo de edificios):") flagged = [n for x, n in ratios if x < 0.5 * med] for n in flagged: print(f" - {n}") if not flagged: print(" ninguna") if __name__ == "__main__": main()