Kitkaton data, Suomen rakennukset ja R

R
Tekijä

Markus Kainu

Julkaistu

2. syyskuuta 2020

Digi- ja väestövirasto (DVV) on julkaissut uuden version Suomalaisten rakennusten osoitteet, postinumerot ja WGS84-koordinaatit ja tällä kertaa ns. kitkattomana datana (frictionless data).

Frictionless data -projektissa pyritään luomaan (taas kerran) tekstipohjainen paketointiformaatti, joka on yhteensopiva eri alustojen ja ohjelmistojen kesken. Syyskuussa 2020 työkalut löytyvät jo seuraaviin ohjelmointikieliin:

Ideana siis on että paketti sisältää json-muotoiset metadatat pakettiin kuuluvien datojen sisällöstä, sijainnista, lisensseistä sekä teknisistä spesifikaatioista. Eri kielille hehitetyillä työkaluilla nämä tiedot on helppo lukea kullekin kielelle ominaisella tavalla.


Seuraavaksi katsotaan DVV:n uutta dataa tarkemmin R-kielen avulla.

Aluksi ladataan zipattu paketti levylle, puretaan se kansioon sekä listataan paketista löytyvät data.

Koodi
library(dplyr) # CRAN
library(sp) # CRAN
library(sf) # CRAN
library(fs) # CRAN
library(glue) # CRAN
library(archive) # remotes::install_github("jimhester/archive")
library(jsonlite) # CRAN
library(tableschema.r) # CRAN
library(datapackage.r) # CRAN

datadir <- glue('{Sys.getenv("blogin_datapolku")}dvv_kitkaton/')
Koodi
dir_create(datadir)
datazip <- glue('{datadir}/datazuo.7z')
# Ladataan paketti
download.file("https://www.avoindata.fi/data/dataset/941b70c8-3bd4-4b4e-a8fb-0ae29d2647a1/resource/3c277957-9b25-403d-b160-b61fdb47002f/download/finland_addresses_2022-08-12-json.7z",
              destfile = datazip)
# Puretaan paketti
archive::archive_extract(datazip,
                         dir = datadir)
# Poistetaan paketti
file_delete(datazip)
Koodi
# Listataan paketin tiedostot
dir_info(datadir, recurse = TRUE) %>% 
  select(path,size,modification_time) %>% 
  arrange(size) -> flies
print(flies %>% 
          mutate(path = sub("^.+dvv_", "dvv_", path)), 
      n = 50)
# A tibble: 46 × 3
   path                                                 size modification_time  
   <fs::path>                                        <fs::b> <dttm>             
 1 dvv_kitkaton/csv_dialect.json                         180 2022-08-12 12:50:59
 2 dvv_kitkaton/json_table_schema.json                 2.11K 2022-08-12 12:50:59
 3 dvv_kitkaton/data/XX_addresses_2022-08-12.csv       3.49K 2022-08-12 12:50:59
 4 dvv_kitkaton/datapackage.json                       3.98K 2022-08-12 12:50:59
 5 dvv_kitkaton/data                                      4K 2022-08-25 09:06:36
 6 dvv_kitkaton/data/19_addresses_2020-11-13.csv       1.96M 2020-11-13 11:07:55
 7 dvv_kitkaton/data/19_addresses_2022-08-12.csv       2.05M 2022-08-12 12:51:04
 8 dvv_kitkaton/data/15_addresses_2020-11-13.csv       3.42M 2020-11-13 11:08:02
 9 dvv_kitkaton/data/15_addresses_2022-08-12.csv       3.53M 2022-08-12 12:52:24
10 dvv_kitkaton/data/17_addresses_2020-11-13.csv       4.59M 2020-11-13 11:07:58
11 dvv_kitkaton/data/17_addresses_2022-08-12.csv       4.72M 2022-08-12 12:51:39
12 dvv_kitkaton/data/08_addresses_2020-11-13.csv       7.41M 2020-11-13 11:08:17
13 dvv_kitkaton/data/08_addresses_2022-08-12.csv       7.52M 2022-08-12 12:54:59
14 dvv_kitkaton/data/07_addresses_2022-08-12.csv        7.7M 2022-08-12 12:55:13
15 dvv_kitkaton/data/07_addresses_2020-11-13.csv       8.31M 2020-11-13 11:08:19
16 dvv_kitkaton/data/04_addresses_2020-11-13.csv       8.39M 2020-11-13 11:08:25
17 dvv_kitkaton/data/04_addresses_2022-08-12.csv       8.63M 2022-08-12 12:56:26
18 dvv_kitkaton/data/06_addresses_2020-11-13.csv       8.63M 2020-11-13 11:08:20
19 dvv_kitkaton/data/06_addresses_2022-08-12.csv       9.55M 2022-08-12 12:55:31
20 dvv_kitkaton/data/13_addresses_2020-11-13.csv       9.95M 2020-11-13 11:08:06
21 dvv_kitkaton/data/14_addresses_2020-11-13.csv      10.01M 2020-11-13 11:08:04
22 dvv_kitkaton/data/14_addresses_2022-08-12.csv      10.42M 2022-08-12 12:52:44
23 dvv_kitkaton/data/13_addresses_2022-08-12.csv      10.49M 2022-08-12 12:53:03
24 dvv_kitkaton/data/11_addresses_2020-11-13.csv       10.5M 2020-11-13 11:08:10
25 dvv_kitkaton/data/11_addresses_2022-08-12.csv      11.18M 2022-08-12 12:53:55
26 dvv_kitkaton/data/18_addresses_2020-11-13.csv      11.59M 2020-11-13 11:07:57
27 dvv_kitkaton/data/03_addresses_2020-11-13.csv       11.7M 2020-11-13 11:08:28
28 dvv_kitkaton/data/03_addresses_2022-08-12.csv      11.97M 2022-08-12 12:56:50
29 dvv_kitkaton/data/18_addresses_2022-08-12.csv      12.02M 2022-08-12 12:51:29
30 dvv_kitkaton/data/09_addresses_2022-08-12.csv      12.15M 2022-08-12 12:54:45
31 dvv_kitkaton/data/09_addresses_2020-11-13.csv      12.77M 2020-11-13 11:08:15
32 dvv_kitkaton/data/10_addresses_2020-11-13.csv      13.36M 2020-11-13 11:08:13
33 dvv_kitkaton/data/12_addresses_2020-11-13.csv       13.9M 2020-11-13 11:08:08
34 dvv_kitkaton/data/12_addresses_2022-08-12.csv       14.3M 2022-08-12 12:53:32
35 dvv_kitkaton/data/10_addresses_2022-08-12.csv       14.8M 2022-08-12 12:54:23
36 dvv_kitkaton/data/16_addresses_2020-11-13.csv      17.73M 2020-11-13 11:08:01
37 dvv_kitkaton/data/16_addresses_2022-08-12.csv      18.34M 2022-08-12 12:52:14
38 dvv_kitkaton/data/05_addresses_2020-11-13.csv       18.8M 2020-11-13 11:08:24
39 dvv_kitkaton/data/05_addresses_2022-08-12.csv      19.88M 2022-08-12 12:56:08
40 dvv_kitkaton/data/02_addresses_2020-11-13.csv       20.7M 2020-11-13 11:08:33
41 dvv_kitkaton/data/02_addresses_2022-08-12.csv      21.67M 2022-08-12 12:57:33
42 dvv_kitkaton/data/01_addresses_2020-11-13.csv       30.7M 2020-11-13 11:08:37
43 dvv_kitkaton/data/01_addresses_2022-08-12.csv      31.58M 2022-08-12 12:58:15
44 dvv_kitkaton/datazuo.7z                             73.6M 2022-08-25 09:06:20
45 …v_kitkaton/data/Finland_addresses_2020-11-13.csv  224.5M 2020-11-13 11:08:31
46 …v_kitkaton/data/Finland_addresses_2022-08-12.csv 232.49M 2022-08-12 12:57:24

Paketissa siis on 46 tiedostoa ja yksi kansio ./data. Paketissa on 46 .json-tiedostoa ja katsotaan ensin niiden sisältö.

Koodi
# Printataan .JSON tiedostojen sisältö
flies %>% 
  filter(grepl("json", path)) %>% 
  pull(path) -> jsons
jsons %>% sub("^.+dvv_", "dvv_", .)
dvv_kitkaton/csv_dialect.json       dvv_kitkaton/json_table_schema.json 
dvv_kitkaton/datapackage.json       

csv_dialect.json -tiedostossa kerrotaan datatiedostojen csv:n murre seuraavasti.

Koodi
plyr::ldply(fromJSON(jsons[1]), data.frame) %>% as_tibble()
# A tibble: 7 × 2
  .id              X..i..
  <chr>            <chr> 
1 csvddfVersion    "1.2" 
2 delimiter        ","   
3 doubleQuote      "TRUE"
4 lineTerminator   "\r\n"
5 quoteChar        "\""  
6 skipInitialSpace "TRUE"
7 header           "TRUE"

json_table_schema.json -tiedostossa taas kerrotaan datatiedostojen sarakkeiden nimet, datatyypit ja kuvaukset.

Koodi
plyr::ldply(fromJSON(jsons[2]), data.frame) %>% as_tibble()
# A tibble: 9 × 4
  .id    name            type    description                                    
  <chr>  <chr>           <chr>   <chr>                                          
1 fields building_id     string  Identifier for Finnish buildings               
2 fields region          string  Identification number for Finnish regions. See…
3 fields municipality    string  Identification number for Finnish municipaliti…
4 fields street          string  Street name: an identifying name given to a st…
5 fields house_number    string  Unique number to each building in a street or …
6 fields postal_code     string  Series of digits included in a postal address …
7 fields latitude_wgs84  number  Coordinate latitude in the WGS 84 standard. Th…
8 fields longitude_wgs84 number  Coordinate longitude in the WGS 84 standard. T…
9 fields building_use    integer Intended use of building. The identification c…

datapackage.json -tiedostossa puolestaan on yleistä metatietoa datasta ja julkaisijasta kuten datan lisenssi.

Koodi
jsonlite::prettify(readLines(jsons[3]))
{
    "name": "finnish-addresses-postalcodes-and-coordinates",
    "title": "Data of finnish addresses with postal codes and coordinates",
    "description": "The data is provided for separately for each region (e.g.: xx_addresses_yyyy-mm-dd.csv) and alternatively as a single csv file (e.g.: Finland_addresses_yyyy-mm-dd.csv). See this link for region codes: https://dvv.fi/tilastot-ja-luettelot, file Maakunnat.xlsx",
    "licenses": [
        {
            "url": "https://creativecommons.org/licenses/by/4.0/",
            "name": "Creative Commons Attribution 4.0 International",
            "version": "4.0"
        },
        {
            "url": "http://www.jhs-suositukset.fi/suomi/jhs189",
            "name": "Finnish public sector open data license"
        }
    ],
    "sources": [
        {
            "name": "DVV Population Information System",
            "web": "http://dvv.fi/en/population-information-system"
        }
    ],
    "maintainers": [
        {
            "name": "Mika Honkanen",
            "email": "mika.honkanen@dvv.fi",
            "web": "https://www.avoindata.fi/en"
        }
    ],
    "publishers": [
        {
            "name": "Mika Honkanen",
            "email": "mika.honkanen@dvv.fi",
            "web": "https://www.avoindata.fi/en"
        }
    ],
    "resources": [
        {
            "name": "addresses",
            "path": "./data/*.csv",
            "format": "csv",
            "mediatype": "text/csv",
            "schema": {
                "fields": [
                    {
                        "name": "building_id",
                        "type": "string",
                        "description": "Identifier for Finnish buildings"
                    },
                    {
                        "name": "region",
                        "type": "string",
                        "description": "Identification number for Finnish regions. See: https://dvv.fi/tilastot-ja-luettelot, file Maakunnat.xlsx"
                    },
                    {
                        "name": "municipality",
                        "type": "string",
                        "description": "Identification number for Finnish municipalities. See: http://tilastokeskus.fi/meta/luokitukset/kunta/001-2019/index.html"
                    },
                    {
                        "name": "street",
                        "type": "string",
                        "description": "Street name: an identifying name given to a street"
                    },
                    {
                        "name": "house_number",
                        "type": "string",
                        "description": "Unique number to each building in a street or area, with the intention of making it easier to locate a particular building"
                    },
                    {
                        "name": "postal_code",
                        "type": "string",
                        "description": "Series of digits included in a postal address for the purpose of sorting mail."
                    },
                    {
                        "name": "latitude_wgs84",
                        "type": "number",
                        "description": "Coordinate latitude in the WGS 84 standard. The World Geodetic System (WGS) is a standard for use in cartography, geodesy, and navigation including GPS."
                    },
                    {
                        "name": "longitude_wgs84",
                        "type": "number",
                        "description": "Coordinate longitude in the WGS 84 standard. The World Geodetic System (WGS) is a standard for use in cartography, geodesy, and navigation including GPS."
                    },
                    {
                        "name": "building_use",
                        "type": "integer",
                        "description": "Intended use of building. The identification codes with the corresponding letter codes from stat.fi are: 0 The intended use of building is lacking, 1 Residental building or business premises (A - H), and 2 Production building or other building (J - N). See: http://www.stat.fi/meta/luokitukset/rakennus/001-2018-07-12/index_en.html"
                    }
                ]
            }
        }
    ]
}
 

Katsotaan sitten tarkemmin datapackage.json:n resources-kohtaa

Koodi
fromJSON(jsons[3]) %>% 
  .$resources -> resources
str(resources)
'data.frame':   1 obs. of  5 variables:
 $ name     : chr "addresses"
 $ path     : chr "./data/*.csv"
 $ format   : chr "csv"
 $ mediatype: chr "text/csv"
 $ schema   :'data.frame':  1 obs. of  1 variable:
  ..$ fields:List of 1
  .. ..$ :'data.frame': 9 obs. of  3 variables:
  .. .. ..$ name       : chr  "building_id" "region" "municipality" "street" ...
  .. .. ..$ type       : chr  "string" "string" "string" "string" ...
  .. .. ..$ description: chr  "Identifier for Finnish buildings" "Identification number for Finnish regions. See: https://dvv.fi/tilastot-ja-luettelot, file Maakunnat.xlsx" "Identification number for Finnish municipalities. See: http://tilastokeskus.fi/meta/luokitukset/kunta/001-2019/index.html" "Street name: an identifying name given to a street" ...

Sieltä käy ilmi mm. datatiedostojen sijainti (./data) sekä schema-kohdan alta vielä toistamiseen datojen kenttien tiedot.

Koodi
resources$schema$fields[[1]] %>% as_tibble()
# A tibble: 9 × 3
  name            type    description                                           
  <chr>           <chr>   <chr>                                                 
1 building_id     string  Identifier for Finnish buildings                      
2 region          string  Identification number for Finnish regions. See: https…
3 municipality    string  Identification number for Finnish municipalities. See…
4 street          string  Street name: an identifying name given to a street    
5 house_number    string  Unique number to each building in a street or area, w…
6 postal_code     string  Series of digits included in a postal address for the…
7 latitude_wgs84  number  Coordinate latitude in the WGS 84 standard. The World…
8 longitude_wgs84 number  Coordinate longitude in the WGS 84 standard. The Worl…
9 building_use    integer Intended use of building. The identification codes wi…

Nyt kun on tiedossa datojen sijainnit, voimme ladata datat R:ään. Sivun alussa olevasta tiedostolistauksesta saattoi huomata että datat ovat sekä maakunnittaisina tiedostoina maakuntakoodilla merkittynä sekä koko maan tiedostona. Maakuntatatoista suurin on Uudenmaan data /home/aurelius/btsync/web/markuskainu19/local_data/dvv_kitkaton/data/Finland_addresses_2022-08-12.csv ja tehdään sen pohjalta pieni kartta.

Koska sarake-erottimena on pilkku, R:ssä meille riittää kun luetaan data normaalilla read.csv-funktiolla. Koska datat ovat melko suuria, käytän readr-paketin funktioita tässä esimerkissä

Koodi
library(readr)
d <- read_csv(flies[nrow(flies),]$path)
head(d)
# A tibble: 6 × 9
  building_id region municipality street house…¹ posta…² latit…³ longi…⁴ build…⁵
  <chr>       <chr>  <chr>        <chr>  <chr>   <chr>     <dbl>   <dbl>   <dbl>
1 100085724R  <NA>   <NA>         <NA>   <NA>    25830      60.1    22.7       2
2 100170063B  <NA>   <NA>         <NA>   <NA>    34550      62.1    23.4       1
3 100170070K  <NA>   <NA>         <NA>   <NA>    34550      62.1    23.3       2
4 100170071L  <NA>   <NA>         <NA>   <NA>    39700      62.0    23.3       1
5 100170072M  <NA>   <NA>         <NA>   <NA>    39700      61.9    23.3       1
6 100170073N  <NA>   <NA>         <NA>   <NA>    34550      62.0    23.4       2
# … with abbreviated variable names ¹​house_number, ²​postal_code,
#   ³​latitude_wgs84, ⁴​longitude_wgs84, ⁵​building_use

Datat näyttää oikein fiksulta, rakennuksia on yhteensä 3793204. Piiretään datan rakennuksista vielä loppuun kartta niin että siinä ovat kaikki Helsingin Mannerheimintiellä olevat rakennukset.

Koodi
manskun_rakennukset <- d %>% 
  filter(municipality == "091",
         street == "Mannerheimintie") 
manskun_rakennukset
# A tibble: 180 × 9
   building_id region municipal…¹ street house…² posta…³ latit…⁴ longi…⁵ build…⁶
   <chr>       <chr>  <chr>       <chr>  <chr>   <chr>     <dbl>   <dbl>   <dbl>
 1 100809206V  01     091         Manne… 15b     00260      60.2    24.9       1
 2 100809208X  01     091         Manne… 15a     00260      60.2    24.9       1
 3 1013132799  01     091         Manne… 113     00300      60.2    24.9       1
 4 1017008098  01     091         Manne… 166     00300      60.2    24.9       1
 5 101797595C  01     091         Manne… 113     00280      60.2    24.9       1
 6 102320284A  01     091         Manne… 117     00280      60.2    24.9       1
 7 102384058J  01     091         Manne… 81a     00270      60.2    24.9       1
 8 102384059K  01     091         Manne… 81a     00270      60.2    24.9       2
 9 102384063P  01     091         Manne… 81-83   00270      60.2    24.9       1
10 102394189B  01     091         Manne… <NA>    00280      60.2    24.9       2
# … with 170 more rows, and abbreviated variable names ¹​municipality,
#   ²​house_number, ³​postal_code, ⁴​latitude_wgs84, ⁵​longitude_wgs84,
#   ⁶​building_use

Datan sarakkeiden kuvauksessa kerrotaan building_use-sarakkeesta seuraavaa: Intended use of building. The identification codes with the corresponding letter codes from stat.fi are: 0 The intended use of building is lacking, 1 Residental building or business premises (A - H), and 2 Production building or other building (J - N). See: http://www.stat.fi/meta/luokitukset/rakennus/001-2018-07-12/index_en.html. Eli luetaan se mukaan osoitteesta: http://www.stat.fi/meta/luokitukset/rakennus/001-2018-07-12/tekstitiedosto.txt

Mannerheimintiellä rakennuksia on 179 ja kartalla ne sijoittuvat näin käyttötarkoituksen mukaan:

Koodi
rak_sf <- st_as_sf(manskun_rakennukset,
                            coords = c("longitude_wgs84", 
                                       "latitude_wgs84"),
                            crs = "+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs")

tmpflie <- tempfile()
download.file("https://www.stat.fi/fi/luokitukset/rakennus/rakennus_1_20180712/export/", 
              destfile = tmpflie) 

kayttotark <- read.csv(tmpflie, sep = ";", skip = 3, header = TRUE) %>% 
  mutate(koodi = as.integer(gsub("'", "", code))) %>% 
  rename(nimike = classificationItemName)
rak_sf2 <- left_join(rak_sf,kayttotark, 
                     by = c("building_use" = "koodi"))

library(leaflet)
labels <- sprintf(
  "%s<br/>Käyttötarkoitus: %s",
  paste(rak_sf2$street, rak_sf2$house_number), rak_sf2$nimike
) %>% lapply(htmltools::HTML)
paletti <- colorFactor(
  palette = "Set1",
  domain = rak_sf2$nimike)
leaflet(rak_sf2) %>%
  addTiles(options = tileOptions(opacity = .7)) %>% 
  addCircleMarkers(color = ~paletti(rak_sf2$nimike),label = labels) %>% 
  addLegend("bottomleft", pal = paletti, 
            values = ~nimike,
    opacity = 1
  )

Aivan lopuksi piirretään vielä kartta kaikista datan Helsingin rakennuksista 500m x 500m kuusikulmio-ruuduissa. Tolpan pituus tarkoittaa kussakin ruudussa sijaitsevien rakennusten lukumäärää.

Koodi
library(mapdeck)
set_token(Sys.getenv("MAPDECK_TOKEN"))

mapdeck( style = mapdeck_style("dark"), pitch = 45) %>%
  add_hexagon(
    data = d %>% filter(municipality == "091", 
                        !is.na(longitude_wgs84))
    , lat = "latitude_wgs84"
    , lon = "longitude_wgs84"
    , layer_id = "hex_layer"
    , elevation_scale = 30
    , radius = 500
    , colour_range = colourvalues::colour_values(1:6, palette = colourvalues::get_palette("viridis")[70:256,])
  )