Commit 2f4a5bb0 authored by Branko Kokanovic's avatar Branko Kokanovic Committed by Branko Kokanovic

Inicijalna verzija

parent e71bb8e2
.idea
*.pbf
stambene-jedinice-analysis.log*
result.csv
progress.pickle
index.html
# stambene-zajednice-analysis
# Najbitniji linkovi
Analiza registra stambenih zajednica - https://data.gov.rs/sr/datasets/registar-stambenikh-zajednitsa-2/
\ No newline at end of file
* [Registar stambenih zajednica](https://data.gov.rs/sr/datasets/registar-stambenikh-zajednitsa-2/)
* [Analiza rezultata u Jupyeter-u](https://notebooks.azure.com/brankokokanovic/projects/stambene-zajednice/html/StambeneZajednice.ipynb)
* [Thread na OSM forumu](https://forum.openstreetmap.org/viewtopic.php?id=66945)
* [Tabela (avgust 2019.) sa spojenim podacima (PAŽNJA: veličina je 25MB!)](https://stambenezajednice.z6.web.core.windows.net/avgust2019.html)
* [CSV (avgust 2019.) sa spojenim podacima](https://stambenezajednice.z6.web.core.windows.net/avgust2019.csv)
* [Moj blog post na ovu temu](https://blog.kokanovic.org/analiza-stambenih-zajednica/)
# Analiza stambenih zajednica (zgrada)
Portal otvorenih podataka je ponudio registar stambenih zajednica (zgrada) na adresi:
https://data.gov.rs/sr/datasets/registar-stambenikh-zajednitsa-2/
Ovaj projekat ima za cilj da iskoristi gorepomenuti registar da bi na najbolji način doprineo
[OSM](https://www.openstreetmap.org) (OpenStreetMap) projektu.
Za cilj je da se vidi koje zgrade već postoje u OSM-u, da se vidi njihov kvalitet tagovanja u OSM-u i da ovaj projekat
izgeneriše šta sve fali da se unese u OSM.
Originalni thread na OSM forumu: https://forum.openstreetmap.org/viewtopic.php?id=66945
## Zašto analizirati
> preuzeto sa bloga, preskočite ako ste ga vec pročitali
Posle konsultacija na [forumu](https://forum.openstreetmap.org/viewtopic.php?id=66945) (a ako čitate ovo i želite da
se uključite nekako, javite se na forumu!), shvatili smo da je registar stambenih zajednica zapravo… spisak zgrada u
Srbiji:) Možda ne deluje kao mnogo, ali to je nažalost sve što imamo od RGZ-a. I dalje mislim da treba da analiziramo
_shit-out-of-it_, a evo i zašto:
* Analiziranjem ovog registra pokazujemo da možemo da iskoristimo otvorene podatke u praksi
* Registar sadrži 43.000 zgrada. Neka u svakoj zgradi u proseku živi 20 ljudi (verovatno i više). To je preko 800.000 duša u Srbiji koji će dobiti svoju zgradu u OSM-u. To je preko 10% stanovnika do kojih će navigacija bazirana na OSM-u raditi!
* Ovom analizom možemo objektivno da vidimo kakvo je kvalitativno i kvantitativno stanje OSM-a u Srbiji i možemo da pratimo stanje kroz vreme (kada su zgrade dodavane)
* Ovom analizom dobijamo i indirektne podatke (tačna imena ulica, okruga, opština…)
* I poslednje, ali ne i najmanje bitno ovom analizom “pokazujemo” državi da otvoreni podaci koji se daju zajednici imaju nekog smisla, da ih država ne baca preko zida bespotrebno, da su nam korisni i upotrebljivi. To onda može da napravi pozitivnu povratnu spregu i da pokaže da te otvorene podatke, kao u razvijenim državama, treba sve više i više otvarati.
Stvari koje mi padaju na pamet da možemo izvući odavde (a na forumu možemo da nastavimo diskusiju i da raspravljamo
predloge), a pošto spojimo podatke iz registra i iz OSM-a:
* Tu možemo da vidimo kako “stojimo”
* Da analiziramo stanje po okruzima i opštinama
* Da vidimo kako je vremenski OSM dobijao podatke (nije još urađeno ovde)
* Da vidimo kvalitet tagova. Npr. zgrade treba tagovati kao “building=apartments” i treba da budu way-ovi (ne node-ovi). To je nešto što može lako da se pri(o)meni
* Obrnuta logika isto važi ako je nešto tagovano kao building=apartments, a nije u registru, to verovatno znači da je u pitanju greška u OSM-u.
* Čak i nedostatak zgrade u OSM-u nam govori dosta:
* Ime ulice ili kućnog broja je pogrešno (greška u kucanju, pravopisu ili latinični naziv)
* Pogrešan je okrug ili opština (boundaries ucrtani u OSM-u nisu dobri)
* Zgrada prosto nije ucrtana u OSM
## Dohvatanje podataka
Da bi se ovo uradilo, napravljena je prosta Python skripta (`main.py`) koja svaku zgradu iz registra pokušava da nađe u OSM-u.
Korišćeni su .PBF i Overpass. Prvo nađemo sve entitete (nodes, ways) koji imaju odgovarajuću ulicu i broj, a onda im
nalazimo okrug i opštinu preko Overpass Turbo query-ja. Takve rezultate čuvamo u pickle formatu (da možemo da nastavimo
posle restarta programa) i u .CSV-u. Rezultat programa je novi CSV koji je korišćen u daljoj analizi.
Osim ako ne želite da ga opet generišete, **nema potrebe da pokrećete ovu skriptu**. Rezultat je već [ovde
kao result.csv (avgust 2019.)](https://stambenezajednice.z6.web.core.windows.net/avgust2019.csv).
Inače, da bi se skripta pokrenula, potreban je Python 3.5 (ili noviji) i biblioteke pomenute u requirements.txt. Posto
se koristi Osmium da se čita .pbf, preporučuje se Linux. Skripti treba oko dan-dva neprekidnog rada da završi.
Po generisanju result.csv fajla, potrebno je i izvršiti `generate_html.py` da bi se dobila konačna HTML strana.
### Uočene mane programa/moguća unapređenja
* Postoje entiteti koji nisu pronađeni pošto im se ime ulice ili broj razlikuju u odnosu na registar. Namerno o njima nije vođeno računa, da primetimo i pogrešno nazvane ulice!
* Nije rađena nikakava transliteralizacija prilikom pretrage entiteta. Npr. kućni broj "17Г" nije nađen ako je u OSM-u unesen kao "17G". Opet - i ovo može da se okarakteriše kao namerna odluka.
* Nominatim pretraga nekad daje bolje rezultate nego prosta .pbf pretraga. Tako je moguće da Nominatim vrati node koji nema "addr:street", ali je pored te ulice. Odluka je bila da je ovo ipak nepravilno i da je bolje da te rezultate ne vraćamo (ipak na taj node treba da se doda "addr:street" tag).
* Generisani izlaz pamti samo da ima više entiteta za datu ulicu i broj, ali ne pamti ih sve (pamti najviše jedan node i jedan way). Idealno bi bilo da ih pamti sve i da se to prikazuje u generisanom HTML-u.
* Trenutno generisanje traje dan-dva. Kada bi se paralelizovalo, bilo bi brže. Međutim, usko grlo je Overpass, pa više threadova treba da pucaju na različite Overpass instance, nikako na istu!
* Bilo bi dobro kada bi pamtili još neke stvari koje možemo/trebamo imati, kao building:levels i sl., ali tu već ulazimo u teritoriju osmose projekta.
* Ako RGZ da novi dataset i budemo ponovo radili analizu, značilo bi da ne radimo sve, već samo da merge-ujemo postojeće rezultate sa novim (nema potrebe tražiti ponovo node za neku ulicu i broj, dovoljno je proveriti da li dati node ID još uvek postoji i pokazuje na istu ulicu/broj)
* Overpass ima mogućnost da vidimo kada je entitet napravljen. To bi nam omogućilo da vidimo kako je OSM kroz vreme dobijao ove zgrade (i da vidimo da li je ovaj projekat popravio "brzinu" dodavanja zgrada u OSM)
## Analiza
Poslednju analizu možete videti na Jupyter notebook-u:
https://notebooks.azure.com/brankokokanovic/projects/stambene-zajednice/html/StambeneZajednice.ipynb
Tu je i najbolja vizualizacija ovog projekta, pa pogledajte tamo!
## Prikupljeni podaci
Prikupljene podatke ove skripte možete videti ovde (skinućete 25MB klikom ispod, pazite):
https://stambenezajednice.z6.web.core.windows.net/avgust2019.html
Ovo je korisno ako želite da se fokusirate na neku konkretnu opštinu/okrug, ili da vidite šta sve fali, pošto ova web
strana ima mogućnost filtriranja, sortiranja itd. Možete je snimiti i lokalno sa "Save As" i gledati i bez interneta.
# Download Serbia latest PBF
wget http://download.geofabrik.de/europe/serbia-latest.osm.pbf
# Upload to my account
az storage blob upload --account-name stambenezajednice --container-name "\$web" --file result.csv --name avgust2019.csv
az storage blob upload --account-name stambenezajednice --container-name "\$web" --file index.html --name avgust2019.html
\ No newline at end of file
This diff is collapsed.
geopy==1.20.0
overpy==0.4
Jinja2==2.8.1
osmium==2.15.2
\ No newline at end of file
# -*- coding: utf-8 -*-
import csv
from operator import itemgetter
from jinja2 import Environment, PackageLoader
def main():
env = Environment(loader=PackageLoader('__main__', '../templates'))
template = env.get_template('index_template.html')
stambene_zajednice = []
districts = {'': 0}
max_district_id = 0
with open('result.csv') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
#if len(stambene_zajednice) > 100:
# break
stambene_zajednice.append(row)
for sz in stambene_zajednice:
if sz['district'] not in districts:
max_district_id += 1
districts[sz['district']] = max_district_id
sz['district_id'] = districts[sz['district']]
sz['street'] = sz['street'].replace('"', '\\"')
sz['found'] = sz['node'] != "" or sz['way'] != ""
sz['multiple_entities_same_housenumber'] = sz['multiple_entities_same_housenumber'] or False
sz['building_tag_present'] = sz['building_tag_present'] or False
sz['building_is_apartments'] = sz['building_is_apartments'] or False
stambene_zajednice.sort(key=itemgetter('district', 'municipality', 'street', 'number'))
output = template.render(stambene_zajednice=stambene_zajednice, districts=districts)
with open('index.html', 'w', encoding='utf-8') as fh:
fh.write(output)
if __name__ == '__main__':
main()
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment