A Chicago kertvárosában játszódó, 1990-ben készült amerikai film főszereplője egy nyolc éves bajkeverő fiúcska, Kevin McCallister, aki egy félreértés miatt otthon marad egyedül, miközben a népes – általa egyébként utált – családja Párizsba repül a karácsonyi vakációra. Kevin először nagyon élvezi a szabadságot, ám hamarosan rádöbben, hogy betörők garázdálkodnak a környéken. Két bűnöző, Harry és Marv ugyanis aktívan fosztogatja az utca üresen álló házait. Kevin mindenféle különleges ötlettel és ravasz csapdával készül a megjelenésükre, s végül sikerül is meghiúsítania a betörési kísérletet. A film végén természetesen hazatérnek Kevin szülei és a kölcsönös szeretettől áthatva ölelik meg újra egymást. Happy end. Igazi karácsonyi történet ez, mai szemmel nézve visszafogott mennyiségű erőszakkal fűszerezve.

Harry és Marv napjainkban élő magyar betörő kollégáinak azonban nem Kevinnel, hanem a rendőrséggel kell megküzdeniük. Nézzük meg, hogy jelenleg ki áll nyerésre ebben a játszmában!

A mai feladatunk tehát az, hogy valamiféle vizualizációt készítsünk a hivatalos betörési statisztikákból R nyelven. Ezt az adatvizualizációs technikát egyébként azért érdemes megtanulni, mert automatizálhatók vele az ilyesféle munkák. Egy bizonyos típusú ábra kinézetét egyszer kell csak megtervezni, és a későbbiekben elég a hozzá tartozó bemeneti adatokat cserélgetni.

Az alapanyagok beszerzése

A rendőrség azon kevés magyar állami szerv közé tartozik, amely a működése során keletkezett adatok egy részét strukturált formában letölthető módon a szélesebb közönség számára is elérhetővé teszi. A Prevenciós Bűnözés-Statisztikai Adattár (PRE-STAT) nevet viselő oldalra ügyfélkapus azonosítást követően lehet belépni. A lekérdezés során különböző területi szintekre (például ország, régió, megye, járás, település) vonatkoztatva, számos abszolút vagy relatív mutatóból választhatjuk ki a minket érdeklő bűneseteket. Jelen pillanatban – amennyire szúrópróbaszerűen meg lehetett ezt állapítani – a legrégebbi adatok 2010-ből, a legújabbak pedig 2019-2020-ból származnak. Tehát nem naprakész az adatbázis. Azt sajnos nem tudtam kideríteni, hogy a PRE-STAT egy befejezett és magára hagyott projekt, vagy inkább arról van szó, hogy a nyilvánosság számára csak késleltetve jelennek meg benne az adatok. Ki tudja.

A Reszkessetek, betörők! témájához alkalmazkodva én a 100000 lakásra jutó települési szintű betörési adatokat, valamint az országos esetszámokat kérdeztem le. (Egyébként a lakásbetörés a rendőrségi szakzsargonban így hangzik: “lakhatás céljára szolgáló helyre, dolog elleni erőszakkal bemenve elkövetett lopás bűncselekménye”.) A települési szintű adatoknál a 2010 és 2019 közötti időszakban bekövetkezett változásokat, az országos szintűeknél pedig a 2010 és 2020 közötti évek esetszámait töltöttem le egy-egy CSV formátumú táblázatban. (Ezeket a poszt kipróbálásához itt és itt lehet letölteni.)

Az országos adatokból egy diagramot fogok készíteni, a települési szintű adatok ábrázolásához viszont szükségünk lesz egy digitális alaptérképre. Ez tulajdonképpen egy vonalas térképvázlatnak fogható fel, amelyet majd “kiszínezünk” a PRE-STAT adatbázisból származó adatainkkal. Magyarország településeiről és vármegyéiről az interneten is találhatunk ilyet. Én az OpenStreetMap közigazgatási határokat tartalmazó alaptérképeit használom fel, amelyekből a forrás feltüntetése mellett szabadon lehet származékos műveket készíteni a CC BY-SA 2.0 licenc alapján.

Az OpenStreetMap oldaláról a kozighatarok.zip fájlt kell letölteni. Ebben az ábrázolás lehetséges területi szintjeinek megfelelően különböző poligon típusú shapefile rétegek találhatók. Egy-egy shapefile réteg fizikailag több – jelen esetben 5 darab – fájlból áll. A letöltött és kicsomagolt állományból az admin6 elnevezésű fájlok a vármegyei, az admin8 elnevezésűek pedig a települési szintű térképhez tartoznak. Nekünk most csak ezek kellenek.

Első lépésként hozzunk létre egy munkakönyvtárat a számítógépünkön és másoljuk bele ebbe a PRE-STAT adatbázisból letöltött két CSV fájt, valamint a szükséges shapefile rétegeket!

A térkép és a diagram elkészítése

Az alábbiakban R nyelven (v4.2.2) írt kódot használok a feladat végrehajtásához. A magyarázó szövegek közé ékelt fekete kódblokkok tartalmát az RStudio-ban egymás alá illesztve elvileg bárki által reprodukálható az itt bemutatott műveletsor. A kódblokkok # kezdetű sorai pusztán magyarázó funkcióval bírnak, ezekre a program futtatásakor nincs szükség.

Az elkészítendő kódban a shapefile rétegeket az sf csomaggal olvasom be az R-be. Az táblázatos adatok manipulálásához a dplyr csomagot (is) használom, az adatok vizualizálása pedig a ggplot2 csomaggal történik. (Egy adott függvény származási helyének egyértelmű beazonosításához a csomag::függvény() formulát használom a kódban. Az automatikusan betöltődő függvényeket nem jelölöm külön.)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# A szükséges csomagok betöltése.
# Ezeket a legelső használat előtt az install.packages("csomag_neve") utasítással telepíteni kell.
library(sf)
library(dplyr)
library(ggplot2)

# Ide a saját munkakönyvtárunk elérését kell beírni!
setwd("C:/Munkakönyvtár")

# A shapefile réteg beolvasása.
telepulesek <- sf::st_read("admin8.shp")
varmegyek <- sf::st_read("admin6.shp")

# A 100000 lakásra jutó lakásbetörések számának beolvasása.
adatok <- read.csv("PRE-STAT_100_000_lakásra_jutó_lakásbetörések_száma.csv", skip = 1, col.names = c("telepNev","eset"))

A fenti kódblokk lefuttatását követően a shapefile rétegek bekerültek a telepulesek és a varmegyek nevű, a PRE-STAT adatbázisból származó CSV fájl pedig az adatok nevű adatkeretbe.

A telepulesek és az adatok nevű táblázatoknak elvileg ugyanannyi sorból kellene állniuk, hiszen a bűnözési adatok konkrét településekre vonatkoznak. E poszt megírásának idején 3155 önkormányzattal rendelkező település van Magyarországon, vagyis ezzel megegyező számú sorra számíthatunk.

Ehhez képest az adatok tábla 3177, a telepulesek tábla pedig 3174 sorból áll. Megvizsgálva ezeket a táblázatokat, az eltérések oka a következő:

  1. A rendőrségi adatokban Budapest kerületei külön vannak felsorolva, a települési szintű térképen viszont Budapestet egyetlen térképi egység képviseli. Ebben az esetben a megoldás az lesz, hogy a fővárosi kerületek adatait összevonjuk. Így végül pontosan 3155 sorunk marad. Annyi, amennyinek lennie kell.

  2. A települések shapefile rétege technikailag úgy van kivitelezve, hogy az exklávékkal rendelkező – vagyis földrajzilag egymással nem érintkező területdarabokból álló – helységek minden egyes darabja különálló térképi egységként van rögzítve. Azaz vannak olyan települések, amelyekhez több sor tartozik a táblázatban. Ezeket a konzolba beírt pull(telepulesek[duplicated(telepulesek$NAME),], NAME) utasítással tudjuk kilistázni, ha esetleg kíváncsiak vagyunk rájuk. De egyébként az ábrázolást ez a jelenség nem fogja zavarni, itt további teendőnk nincs.

Az alábbiakban tehát először összevonom Budapest kerületeit, majd az így korrigált, immáron 3155 sort tartalmazó adatok nevű táblát az inner join típusú kapcsolattal egyesítem a telepulesek nevű táblával.

1
2
3
4
5
6
7
8
9
# A budapesti kerületek adatainak összesítése.
adatok$telepNev[grep("^Budapest", adatok$telepNev)] <- "Budapest"
adatok <- dplyr::group_by(adatok, telepNev) %>% dplyr::summarise_all(.funs = sum)

# Erre a műveletre azért van szükség, hogy azok a települések, ahol nem történt változás, fehérre színezhetők legyenek majd a térképen.
adatok[adatok == 0] <- NA

# Az adatok nevű tábla egyesítése a telepulesek táblával.
telepulesek <- dplyr::inner_join(telepulesek, adatok, by = c("NAME" = "telepNev"))

Ezt követően az előkészített adatokból és shapefile rétegekből a ggplot csomag segítségével összerakom a tematikus települési térképet.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# A tematikus térkép felrajzolása.
ggplot2::ggplot() +
  # A települések térképi réteg hozzáadása. Ezt az eset oszlop tartalma alapján színezzük be.
  geom_sf(data = telepulesek, mapping = aes(fill = eset), color = "#000000") +
  # A térkép színezésének és jelmagyarázatának kalibrálása.
  scale_fill_binned(breaks = c(-1000,-750,-500,-250,0,250,500,750,1000),
                    palette = function(x) {c("#043d46","#065b69", "#087a8c", "#0a99af", "#3aadbf", "#ff6f6f","#ff4c4c","#cc3c3c","#992d2d","#661e1e")},
                    na.value = "#ffffff",
                    labels = c("-1000","-750","-500","-250","0","+250","+500","+750","+1000"),
                    guide = guide_bins(title = "A változás\nmértéke\n(eset)", reverse = T)) +
  # A vármegyei térképi réteg hozzáadása.
  geom_sf(data = varmegyek, fill = NA, linewidth = 0.7, color = "#000000") +
  # A térkép feliratainak hozzáadása.
  labs(title = "Reszkessetek, betörők!?",
       subtitle = "A 100000 lakásra jutó betörések számának változása Magyarországon \na 2010-2019 közötti évek adatai alapján",
       caption = "Az adatok forrása: Prevenciós Bűnüldözés-Statisztikai Adattár (PRE-STAT)\nAz alaptérkép forrása: OpenStreetMap CC BY-SA 2.0\nhttps://aprogramozotortenesz.hu/") +
  # A térkép további jellemzőinek testreszabása.
  theme(axis.text = element_blank(),
        axis.ticks = element_blank(),
        panel.background = element_blank(),
        legend.title = element_text(face = "bold", size = 20),
        legend.text = element_text(size = 20),
        plot.title = element_text(face = "bold", size = 65),
        plot.subtitle = element_text(size = 22),
        plot.caption = element_text(size = 18),
        plot.margin = margin(0.5,0.5,0.5,0.5, "cm"),
        plot.caption.position = "plot")

A 100000 lakásra jutó betörések száma Magyarországon 2010-2019

Az elkészült térkép a 100000 lakásra jutó betörések számának változását mutatja a 2010 és 2019 közötti időszak adatai alapján. A kékes színnel megjelölt 1624 településen (51,5%) csökkent, míg a piros különböző árnyalataival beszínezett 497 helységben (15,7%) növekedett a lakásbetöréses esetek száma. Az 1034 fehér színű településen (32,8%) vagy nem történt változás, vagy ezeken – és számomra ez tűnik inkább valószínűbbnek – a vizsgált időszakban egyáltalán nem volt ilyen típusú bűncselekmény. (A PRE-STAT adatbázis sajnos nem tájékoztat arról, hogy milyen módszertan alapján állítja elő a két időpont közötti elmozdulást mutató adatokat.)

De érdemes egy pillantást vetni az országos adatokra is, amelyekből egy diagramot készítek. (A PRE-STAT adatbázis egyébként itt sem mondja meg pontosan, hogy mik ezek az adatok. Feltehetően az adott év január 1-jén folyamatban lévő eljárásokról van szó.)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# A lakásbetörések országos számának beolvasása.
adatok2 <- read.csv("PRE-STAT_lakásbetörések_száma.csv", col.names = c("ev","eset"))
adatok2$ev <- as.factor(2010:2020)

# A diagram felrajzolása.
ggplot2::ggplot(data = adatok2) +
  # Egy vonal típusú réteg hozzáadása.
  geom_line(mapping = aes(x = ev, y = eset, group = 1), linewidth = 2) +
  # Két darab pont típusú réteg hozzáadása.
  geom_point(mapping = aes(x = ev, y = eset), size = 4, color = "#000000") +
  geom_point(mapping = aes(x = ev, y = eset), size = 2, color = "#ffffff") +
  # A diagram y tengelyének kalibrálása.
  scale_y_continuous(breaks = seq(0, 26000, 2000), limits = c(0, 26000)) +
  # A diagram feliratainak hozzáadása.
  labs(title = "Reszkessetek, betörők!?",
       subtitle = "A lakásbetörések száma Magyarországon a 2010-2020 közötti időszakban\n",
       caption = "\nAz adatok forrása: Prevenciós Bűnüldözés-Statisztikai Adattár (PRE-STAT)\nhttps://aprogramozotortenesz.hu/") +
  # A diagram egyéb jellemzőinek testreszabása.
  theme(axis.text = element_text(size = 20, color = "#000000"),
        axis.title = element_blank(),
        panel.grid.minor.x = element_blank(),
        legend.title = element_text(face = "bold", size = 20),
        legend.text = element_text(size = 20),
        plot.title = element_text(face = "bold", size = 65),
        plot.subtitle = element_text(size = 22),
        plot.caption = element_text(size = 18),
        plot.margin = margin(0.5,0.5,0.5,0.5, "cm"),
        plot.caption.position = "plot")

A lakásbetörések száma Magyarországon 2010-2020

A térkép és a diagram alapján immáron kijelenthető, hogy általánosságban a betörők állnak vesztésre a rendőrökkel szemben. Országos szinten a 2014-es csúcsot jelentő 24477 esetről 2020-ra 6983 esetre csökkent a lakásbetörések száma. S habár a PRE-STAT adatbázisban nincsenek frissebb adatok, más forrásból tudható, hogy a csökkenő tendencia azóta is tartós maradt. (Ami bizonyára nem vigasztalja azon települések lakóit, ahol ez éppenséggel nem így van.)

Kevin McCallister

Mindezek után nincs más hátra, minthogy boldog karácsonyt kívánjak A programozó történész blog minden olvasójának! 🎄🎁😊

Az előző évek karácsonyi posztjai megtekinthetők itt:

- 2022: A karácsony tizenkét napja versgenerátor

- 2021: Karácsonyi képeslap készítése ggplot-tal

- 2020: Karácsonyfa-diagram létrehozása ggplot-tal