Kvalita života seniorů v Brně

Market a Simca
13 min readNov 27, 2022

Autorky projektu: Markéta Jurčíová, Simona Piršelová

O čem je náš projekt?

S Market nás spojil zájem o sociální témata a preference pracovat s otevřenými daty. Původně jsme se chtěli věnovat tématu z oblasti školství co ztroskotalo na neexistujících datech, tak jsme byli nuceni hledat dál a po týdnech rozmýšlení přišla Market s tématem analyzovat jak se žije seniorům v Brně, protože Florida (ráj seniorů) je daleko :)

Za cíl jsme si stanovili určení úrovně kvality života seniorů v jednotlivých městských částí Brna pomocí indexu inspirující se v evropském Indexu aktivního stárnutí.

Evropský index jsme použili jen jako výchozí bod pro vytvoření vlastního z důvodu nedostupnosti dat na městské úrovni. Největší rozdíl mezi originálním a naším indexem je druh sběru dat. Evropský originální index využívá ke sběru dat sociologický výzkum se seniory, kdežto my využíváme
opendata.

Rozhodli jsme se zkoumat následující kategorie a podkategorie:

Charakter městské části (MČ) — možnost získání práce, bezpečnost, počet lidí bez domova v MČ. Tato kategorie udává skóre pro úroveň městské části na život bez ohledu na cílovou skupinu.

Participace ve společnosti — počet seniorských organizací, veřejné angažování seniorů v MČ.

Nezávislost — dostupnost bydlení s pečovatelskou službou, počet sociálních služeb pro cílovou skupinu seniorů, počet bezbariérových přístupů k objektům služeb, obchodu, kultury a počet zdravotnických zařízení (všeobecný praktický lékař, zubař, lékárna).

K jednotlivým výsledkům hlavních kategorií jsme nakonec ještě přidali váhu podle toho, jak moc, podle nás, ovlivňují aktivní život seniorů. Jak je ze schématu vidět, největší váhu přikládáme kategorii nezávislost, jednak z důvodu početnosti měřených oblastí, ale i pro námi vnímanou důležitost. O výpočtu konečných hodnot indexu se zmiňujeme později. V obrázku je možné vidět první verzi přístupu k výpočtu indexu.

Sběr a čištění dat

Šly jsme cestou opendat. Data jsme primárně čerpali z portálu otevřených dat města Brna data data.brno a Českého statistického úřadu a vše poctivě zaznamenávali do Google sheetu, abychom měli lepší přehled o formátech souborů, sloupcích, které budeme potřebovat a jak jednotlivé soubory dokážeme propojit přes primární a cizí klíče.

Při procházení datových souborů jsme zjišťovali, že data nejsou konzistentní. Největší trápení jsme zažívaly s územním rozdělením Brna a nekonzistencí zápisu adres. Například městské části byly pojmenovány v každém souboru jinak (Brno-Starý Lískovec, Brno_Starý Lískovec,
Starý Lískovec) nebo obsahovaly neúplné adresy bez PSČ, popisného čísla nebo naopak obsahovali název katastrálního území nebo jen souřadnice. Prostě chyběl údaj o městské části, který byl pro náš klíčový. Háček byl ve zjištění, že Brno si uchovává nešvar a hranice městské části vede i skrz parcelu. Po diskuzích jak co nejpřesněji určit příslušnost objektu do městské části bylo rozhodnuto o principu — jaká městská část obsahuje větší část území, ta jej bere. Mentorka Renča nám pomohla vytvořit číselník k zařazení, kde ve výsledku úplně vypadly Vinohrady, neboť tato městská část obsahuje jen katastrální část Židenic a byly tedy přidány k datům Židenic.

Některá data např. bezbariérovost jsme potřebovali groupovat podle stanovených kategorií, v čem nám velmi pomohlo PowerBI, které nám tímto elegantně ušetřilo čas. Námi vnímaný největší problém byl s daty, která místo adres obsahovaly pouze souřadnice, navíc datový zdroj byl ve formátu geojson. Tehdy nás zachránila mentorka Renča, která nám ukázala QGIS aplikaci, pomocí které jsme na základě souřadnic určili např. počet kriminálních činů nebo služeb v městské části. Renča pro nás vytvořila jednoduchý návod, podle kterého se nám velmi jednoduše v aplikaci pracovalo:

Zde je ukázka spojení vrstev pro zjištění počtu sportovišť

Zpracování dat

Brainstormingem nad metodikou výpočtu našeho indexu jsme strávili skoro celý Hackhaton, ale výsledek se nakonec dostavil. Měly jsme vybrané zdrojové datasety, sestaveny vzorečky pro výpočet a šlo se do výpočtů. První kategorii jsme si vzaly jako zkušební a spočítaly jsme ji obě. Simča v pythonu a Market v SQL.

Pro výpočet subkategorií, hlavních kategorií i finálního indexu za MČ jsme využívali hlavně Python, který nám přišel „more friendly“ a přímočarý pro zvolenou práci dat. A nezatěžovala ho tak čeština. Pro prevenci jsme si vytvořili entitu ID městské části, bez ní byl život komplikovanější a při spojování dat pak nedocházelo k vytracení pár městských částí. I když městská část má unikátní název, jeho zápis již tak unikátní není.

Výpočet některých subkategorií jsme zkusily i přes knihovnu Pandas, s kterou jsme se seznámily v jedné z hodin. Zde bylo potřeba přeběhnout v lekcích a primárně pomocí kodim.cz se doučit další příkazy.

Práci s daty komplikovaly špatné zápisy adres, kde pro přiřazení k městské části jsme potřebovaly čisté a jednotné zápisy adres. S tím pro jeden dataset pomohl python, pro jiný Power BI.

Další výzvou bylo napasovat finální výsledky, které dosahovaly skoro až nekonečných rozpětí, na spravedlivou škálu. Původní nápad bodového seřazení (městská část s největším skóre získá 28 bodů, nejhorší 28. městská část 1 bod) nám přestal připadat spravedlivý. Upnuly jsme se
k myšlence, že výsledky chceme napasovat na škálu 0 (nejhorší výsledek) až 10 (nejlepší výsledek), abychom je mohli snadno srovnávat a byly pro veřejnost snadno interpretovatelné. Po pár hodinách googlení a inspirování se v projektu Obec v datech využívající také indexy, jsme narazily na metodu normalizace, která nám dokonale posloužila.

# vypocet kategori Charakter MC
import json
# nezamestnani file
with open('Pocet_nezamestnanych_MC_2021.csv', encoding='utf-8') as input:
text_nezamestnani = input.readlines()

# obyvatelstvo file
with open('obyvatelstvo_final.csv', encoding='utf-8') as input:
text_obyvatelstvo = input.readlines()


# file krimi
with open('krimi_pocet.csv', encoding= 'utf-8') as input:
text_krimi = input.readlines()

# obyvatelstvo podle zpusobu bydleni
with open('Obyvatelstvo_podle_bydleni.csv', encoding = 'utf-8') as input:
text_zpusob_bydleni = input.readlines()


#########################################################################

# index stlpca vsichni_muzi_zeny, aby som ho dokazala vybrat a pocitat s nim
obyv_vsichni_muzi_zeny_index = 0

# urcime index stlpca pocet_nezamestnanych_celkem, aby som ho dokazala vybrat a pocitat s nim
pocet_nezamestnanych_celkem_index = 0

# urcime index stlpca pocet_nezamestnanych_celkem, aby som ho dokazala vybrat a pocitat s nim
pocet_krimi_index = 0

# urcim idex stlpca osoby bez domova, ktory potrebujem pre vypocet
osoby_bez_domova_index = 0

# urcim index stlpca s nazvom MC
mc_nazov_index = 0
#########################################################################

# funkcia v ktorej urcim co potrebujem k vypoctu indexu na vybratie stlpca pre vypocet - parametre column_name, file z kt. to beriem
def find_column_index(column_name, file):
header = file[0].strip().split(',')

result = 0
index = 0
for h in header:
if h == column_name:
result = index
index += 1

return result


# file obyvatelstvo
obyv_vsichni_muzi_zeny_index = find_column_index('vsichni_muzi_zeny', text_obyvatelstvo)
mc_nazov_index = find_column_index('Uzemi', text_obyvatelstvo)


# rozdel zahlavie a datovu cast
data_obyv = [text.split(',') for text in text_obyvatelstvo[1:]]

################################################################################

# file nezamestnanost
pocet_nezamestnanych_celkem_index = find_column_index('pocet_nezamestnanych_celkem', text_nezamestnani)

data_nezam = [text.split(',') for text in text_nezamestnani[1:]]


#######################################################################################

# rozdeli riadok na polia podla stlpcov (datova cast)
pocet_krimi_index = find_column_index('krimi_pocet', text_krimi)
data_krimi = [text.strip().split(',') for text in text_krimi[1:]]

##############################################################################

osoby_bez_domova_index = find_column_index('osoby_bez_domova', text_zpusob_bydleni)
# datova cast, zoberiem pole velkeho zoznamu data a kazde pole (co predstavuje riadok v file) rozdeli na polia podla stlpcov (datova cast),
# stripnem - lebo posledne pole v riadku obsahuje znak \n - python by vyhadzoval chybu u pocitania
# vysledok, kazdy riadok je v zozname a kazde pole v zozname predstavuje urcity stlpec
data_zpusob_bydleni = [text.strip().split(',') for text in text_zpusob_bydleni[1:]]


#################################################################################
# vypocet subkategorii a vyslednoeho indexu za kategoriu charakter MC

index = 0
vysledek = []

for riadok in data_obyv:
mc_dict = {}

nazov_MC = riadok[mc_nazov_index]
stlpec_obyv = int(riadok[obyv_vsichni_muzi_zeny_index])
stlpec_nezam = int(data_nezam[index][pocet_nezamestnanych_celkem_index])
stlpec_krimi = float(data_krimi[index][pocet_krimi_index])
stlpec_zpusob_bydleni = int(data_zpusob_bydleni[index][osoby_bez_domova_index])
index += 1

result_nezam = round((stlpec_nezam/stlpec_obyv) * 100, 2)
result_krimi = round((stlpec_krimi/stlpec_obyv) * 100, 2)
result_zpusob_bydleni = round((stlpec_zpusob_bydleni/stlpec_obyv) * 100,2)

index_charakter_MC = (result_nezam - result_krimi - result_zpusob_bydleni)



mc_dict['nazov_MC'] = nazov_MC
mc_dict['result_nezam'] = result_nezam
mc_dict['result_krimi'] = result_krimi
mc_dict['result_zpusob_bydleni'] = result_zpusob_bydleni
mc_dict['index_charakter_MC'] = index_charakter_MC
vysledek.append(mc_dict)


# normalizacia
max = max(vysledek, key=lambda x: x['index_charakter_MC'])[
'index_charakter_MC']
min = min(vysledek, key=lambda x: x['index_charakter_MC'])[
'index_charakter_MC']

for mc in vysledek:
mc['index_charakter_MC'] = round(((mc['index_charakter_MC'] - min) / (
max - min)) * 10, 2)

with open('charakter_MC.json', mode='w', encoding='utf-8') as vystup:
json.dump(vysledek, vystup, ensure_ascii=False, indent=4)
#  vypocet finalneho indexu aktivneho starnutia
import json
import pandas as pd
from pathlib import Path


# json charakter MC kategoria
with open('charakter_MC_zaloha.json', encoding='utf-8') as soubor:
charakter_MC = json.load(soubor)

# json participace v spolecnosti kategoria
with open('participace_spolecnosti_output.json', encoding='utf-8') as soubor:
participace_v_spolecnosti = json.load(soubor)

# json nezavislost
with open('nezavislost_MC.json', encoding='utf-8') as soubor:
nezavislost = json.load(soubor)


index = 0
vysledek = []
id_mc = 0
for mc in charakter_MC:

mc_dict = {}
id_mc +=1

result_final = (participace_v_spolecnosti[index]['index_participace_v_spolecnosti'] * 0.15) +(nezavislost[index]['index_nezavislost'] * 0.60) + (mc['index_charakter_MC'] * 0.25)

mc_dict['ID'] = id_mc
mc_dict['nazov_MC'] = mc['nazov_MC']
mc_dict['index_final'] = result_final
vysledek.append(mc_dict)
index +=1

# normalizacia
MC_max = max(vysledek, key=lambda x:x['index_final'])[
'index_final']
MC_min = min(vysledek, key=lambda x:x['index_final'])[
'index_final']

for mc in vysledek:
mc['index_final'] = round(((mc['index_final'] - MC_min) / (
MC_max - MC_min)) * 10, 2)


with open('final_index.json', mode='w', encoding='utf-8') as vystup:
json.dump(vysledek, vystup, ensure_ascii=False, indent=4)


# absolute path to json file
jsonpath = Path('final_index.json')

# reading the json file
with jsonpath.open('r', encoding='utf-8') as dat_f:
dat = json.loads(dat_f.read())

# creating the dataframe
df = pd.json_normalize(dat)

# converted a file to csv
df.to_csv('index_final.csv', encoding='utf-8', index=False)

Výsledky

Jelikož populace v Brně stárne, k roku 2021 senioři (lidé ve věku 65+) tvoří podíl 20% z obyvatel Brna, zajistit důsledné podmínky pro kvalitní život seniorů bude nezbytné i s ohledem, že lidé ve věku 50–64 let tvoří 16% obyvatel Brna.

Podle našich zjištění pouze 5 městských částí zajišťuje kvalitní podmínky pro život seniorů a to Brno-střed, Brno-Medlánky, Brno-Kohoutovice, Brno-Židenice a Brno-Jih. Nejlepšího výsledku dosahuje městská část Brno-střed díky svému prvenství v kategorii s největší váhou Nezávislost i když ve zbylých kategorií dosahuje podprůměrných výsledků. Naopak městské části Útěchov, Jehnice a Ořechov ve zbylých dvou kategorií, Charakter MČ a Participace ve společnosti, dosahují nadprůměrných výsledků, ale výrazně zaostávají v poskytování služeb. Tento jev lze vysvětlit optikou struktury zástavby, která pramení z polohy v rámci Brna. Podle Kanceláře architekta města Brna právě historické jádro (leží v městské části Střed) nabízí optimální strukturu v kombinaci bytů, ale i prostoru pro služby. Naopak okrajové části uchovávající původní venkovský charakter (např. Útěchov) nenabízí prostor pro služby (Kanceláře architekta města Brna).

CO MAJÍ NEJLEPŠÍ MĚSTSKÉ ČÁSTI SPOLEČNÉ (min platí pro 3 MČ z 5)

Všech pět městských částí s nejvyšším výsledkem indexu nemají v žádném sledovaném bodě vše společné. Již v top 5 výrazně odsakuje Brno Jih v rámci srovnání výsledné hodnoty skóre, což je dáno jeho nejhorším skóre v kategorii charakter městské části. Lze vysledovat tyto charakteristiky:

Podíl seniorů v populaci

  • Jedná se o městské části s nižším podílem seniorů v obyvatelstvu kolem 15% (pro srovnání celkově za Brno je to 20%)
  • Výjimkou tvoří Kohoutovice, které dosahují druhého nejvyššího podílu seniorů v obyvatelstvu městské části

Nezávislost

  • Všechny městské části dosahují nadprůměrného skóre v měřené kategorii — jedná se o hlavní kategorii s největší váhou, tudíž výsledky hodnotíme pozitivně
  • I přes nadprůměrné celkové skóre, pouze dvě městské části Střed a Jih překonávají průměrný výsledek ve všech subkategorií — lze vysvětlit jejich podobnou rozlohou (největší ze všech pěti městských částí) a jejich vnitřní polohou v územním rozdělením města Brna
  • Objevuje se jev excelentního výsledku v jedné ze sledovaných subkategorií a v dalších dosáhnutí i podprůměrných výsledků
  • Tento jev se neobjevuje pouze ve sledované subkategorii obecní bydlení (počet bytů s pečovatelskou službou) top pětka dosahuje nadprůměrných hodnot, výjimku tvoří městská část Medlánky s nulovým počtem

Participace ve společnosti

  • Městské části dosahují podprůměrného výsledného skóre v měřené kategorii, výjimkou je městská část Brno jih (z pětice dosahuje nejlepšího výsledku v měřené subkategorii politické participace)
  • Obdobně neúspěšně městské části dopadly v subkategorii zaměřující se na počet seniorských organizací, pouze Brno střed dosahuje lepšího skóre

Charakter městské části

  • Nerovnost v dosaženého výsledného skóre v kategorii — objevují se jak nadprůměrné výsledky, tak nízké hodnoty
  • Vyšší míra nezaměstnanosti a nulový či minimální počet lidí bez domova je typický jev pro top pět městských částí, výjimkou zde je Brno střed, které dosahuje i nejvyšší skóre v subkategorii nezaměstnanost
  • Velmi nízký výskyt trestných činů dělá městské části bezpečným místem nejen pro seniory, pozor však Střed a Jih zde dosahují nejvyššího skóre
  • Městské části Kohoutovice a Medlánky pak ve všech sledovaných subkategorií dosahují optimálního výsledku (jejich skóre je menší než průměr — jedná se o jevy s negativní hodnotou, tj. vyšším skóre je ukázán špatný výsledek)

Velká výzva ke zlepšení podmínek stojí před městskými částmi Starý Lískovec a Nový Lískovec. Starý Lískovec, který má nejvyšší podíl seniorů (27%) na obyvatelstvo MČ v celkovém indexu dosahuje hodnoty 1.4 což je pátý nejhorší výsledek ze všech MČ. Městská část Nový Lískovec má největší podíl obyvatel 50+ (obyvatelé blížící se k důchodovému věku) 22%, ale v celkovém indexu patří s hodnotou 2.33 k městským částem s podprůměrnými podmínkami pro kvalitní život seniorů. Obě městské části by měly podporovat vznik seniorských organizací a zařízení sociálních služeb, přetvořit služby na bezbariérové, jakož i investovat do výstavby bytů s pečovatelskou službou.

ZKOUŠKA VZÁJEMNOSTI

Na výsledky jsme se pokusily ještě kouknout optikou hledání vazeb vysvětlující pořadí městských částí. K tomu slouží výpočet korelačního koeficientu, jeho výpočty jsme počítaly v DAXU. Podle návodu jsme vzoreček rozsekaly na menší proměnné obsahující sumy a jiné mezivýpočty, což nám přehledně umožnilo je jednodušeji dosadit do finálního vzorce.

Hodnoty korelačního koeficientu vychází velmi nízko, musíme tedy konstatovat že závislost se neprokázala. Nulová vazba byla nalezena pro vztah katastrální výměra městské části a výsledek finálního indexu (r = 0,04). Větší hodnota koeficientu se pak objevuje pro vztah výměry a výsledku kategorie nezávislost (r = 0,21). Dále jsme se zajímaly o existenci vazby mezi podílem seniorů v městské části a finálním výsledkem indexu — zde je neprokázaná nepřímá závislost, která by v případě větších hodnot ukazovala na vztah čím větší podíl seniorů, tím horší výsledek (r = -0,14). Obdobně vazba vychází i ve vztahu ke skóre nezávislosti, což je přirozené s ohledem na vyšší váhu kategorie na celkovém výsledku (r =-0,19).

Závěr

Výstup našeho projektu může posloužit seniorům při výběru vhodné městské části k životu, ale hlavně zastupitelství městských částí k určení oblastí, ve kterých v kvalitě života seniorů zaostávají nebo excelují.

Projekt by se dal dále rozvíjet nejlépe ve spolupráci přímo s městskými zastupitelstvami, které by mohly rozšířit index o další kategorie nebo subkategorie na základě vlastních požadavků, které jsme my nebraly v úvahu. V rámci našeho projektu jsme posuzovaly výsledky přes optiku počtu seniorů v městské části nebo struktury zástavby a bylo by určitě zajímavé interpretovat výsledky i na základě jiných kritérií.

Na závěr bychom chtěly velmi poděkovat naší mentorce Renči, že se nás ujala, za její rady, připomínky a pomoc nejen během Hackathonů.

Kdo na čem pracoval?

Markéta Jurčíová

Od začátku jsem chtěla zpracovávat data ze sociální oblasti, což se mi splnilo. Začátky práce byly náročné, protože jsme se motaly v tématu a cílech. Mé nalezení evropského indexu zkoumající aktivní stárnutí bylo vyloženě spasení a přísun nového impulsu. Při hledání dat jsem nepřestávala být překvapená kolik sociodemografických dat se sbírá, ale ve většině případů pouze na vyšší územní úrovni jako je kraj, okres. Jsem ráda, že jsme se nevzdaly a zůstaly věrné městským částím Brna, i když nám působily neštěstí. Největší energie a času šlo do výpočtů pro sestavení našeho navrženého indexu. Já se rozhodla na první výpočty jít cestou SQL., kde cesta k výpočtu výsledného skóre kategorie nebyla tak přímočará jak v pythonu.

Při práci s dalšími daty přicházely překážky v podobě neúplných adres, adres v nejednotném formátu, počítání počtu objektů a jejich přiřazení k městské části, což zbrzďovalo mé finální výpočty, na které čekala Simča. Při zpracování výpočtů jsem navíc využila příležitosti, že „to samé“ děláme pro několik samostatných datasetů a po SQL jsem pracovala v pythonu a pandasu primárně s využitím znalostí z hodin. Až v okamžicích kdy to nešlo podle plánu bylo potřeba samostudia pro nalezení řešení problémů.

Po celou dobu projektu jsme pracovaly dohromady a dělily si práci na jednotlivých mezivýpočtech. Finální výpočty byly na Simči a já se vrhla na vizualizaci v Power BI. Byla jsem přesvědčená, že vše půjde lehce a rychle oproti části výpočtů. Velmi snadno se mi povedlo nahrát mapu Brna s městskými částmi a vytvořit vizualizace dle našeho papírového návrhu. Z nadšení mě vyvedly bookmakerky, které ne a ne mi zachovat navolené filtry a rozhazovaly moje veškeré výsledky.

Přes řešení překážek k cíli, tak by se dalo shrnout má práce na projektu. Teď se naštěstí můžu těšit na pokračování, např. srovnávání výsledků našeho indexu s dalšími parametry, které bychom jako vstupy mohly dostat od zastupitelů městských částí nebo zjistit, jak kvalitní podmínky pro aktivní stárnutí nabízí jiné obce.

Simona Piršelová

S Market sme riešili projekt od začiatku až po koniec spoločne. Náročný bol už samotný výber témy, nad ktorým sme strávili nejaký ten piatok. Obidve sme chceli robiť projekt, ktorý by bol nejakým spôsobom užitočný pre spoločnosť a od školstva, cez demografiu obyvateľov Brna sme sa dostali až k seniorom, keď Market prišla s návrhom určiť index aktívneho stárnutia mestských častí Brna. A tak sme sa do toho vrhli, zbierali dáta a delili si výpočty jednotlivých kategórií. Ja som spracovávala Charakter MČ, kategóriu Participace ve společnosti a následne aj finálny index. Od začiatku som pracovala hlavne v Pythone, pretože vzhľadom na vykonávané príkazy mi prišiel oveľa vhodnejší ako SQL, a práve vďaka projektu som sa pre Python veľmi nadchla. Pre napísanie kódu mi z veľkej časti stačili vedomosti z lekcií, nad rámec som sa zoznámila s funkciou lambda. Vizualizácie riešila hlavne Market, ale jednotlivé výstupy sme spolu konzultovali.

Seznam použitých zdrojů

https://data.brno.cz/, https://mozaika-ur.cz/cz/metodiky/active-ageing-index, https://www.czso.cz/, https://nrpzs.uzis.cz/, https://kambrno.cz/

--

--