R Academy · Oppitunti

Sisäkkäisten JSON-rakenteiden käsittely

Muun­takaa syvästi sisäkkäinen JSON analyysia varten selkeärakenteisiksi data frameiksi.

Oppitunti 4/413 vaihetta

Sisäkkäisten JSON-rakenteiden käsittely on ilmainen R Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu R Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. R Academy-kurssilla on yhteensä 4 oppituntia.

Miksi sisäkkäinen JSON on hankalaa

REST API -rajapinnat palauttavat usein syvästi sisäkkäistä JSON-dataa, jossa yksi kenttä voi sisältää objektien taulukon, joka puolestaan sisältää lisää objekteja. Tämän rakenteen litistäminen tidy-muotoiseksi data frameksi edellyttää, että ymmärrätte, miten jsonlite, purrr ja tidyr toimivat yhdessä.

# Example nested JSON from a REST API:
json_str <- '{
  "user": {
    "id": 1,
    "name": "Alice",
    "orders": [
      {"order_id": 101, "total": 59.99, "status": "shipped"},
      {"order_id": 102, "total": 24.50, "status": "pending"}
    ]
  }
}'

# The challenge: 'orders' is an array of objects inside 'user'
cat('Nested JSON loaded as string, length:', nchar(json_str))

fromJSON() — perusteet

jsonlite::fromJSON() muuntaa JSON-merkkijonon tai tiedostopolun R-objekteiksi. Yksinkertaisesta litteästä JSON-datasta tulee lista tai data frame. Sisäkkäisestä JSON-datasta tulee sisäkkäinen lista — objektien taulukoista muodostuu data frameja, jotka tallennetaan listasarakeisiin.

library(jsonlite)

# Parse flat JSON
flat_json <- '{"name": "Alice", "age": 30, "score": 95.5}'
result <- fromJSON(flat_json)
cat('Name:', result$name, '\n')
cat('Age: ', result$age,  '\n')

# Parse an array of objects — becomes a data frame
array_json <- '[{"id":1,"val":10},{"id":2,"val":20},{"id":3,"val":30}]'
df <- fromJSON(array_json)
cat('Class:', class(df), '\n')
print(df)

fromJSON() ja flatten = TRUE

Argumentti flatten = TRUE käskee fromJSON()-funktiota purkamaan sisäkkäiset data framet rekursiivisesti sarakkeiksi, joiden nimet erotellaan pisteillä. Tämä toimii hyvin yhdellä sisäkkäisyyden tasolla ja on nopein tapa käsitellä kohtalaisen sisäkkäistä JSON-dataa.

library(jsonlite)

json_str <- '[{
  "id": 1,
  "name": "Alice",
  "address": {"city": "Berlin", "country": "Germany"}
},{
  "id": 2,
  "name": "Bob",
  "address": {"city": "Paris", "country": "France"}
}]'

# Without flatten:
nested_df <- fromJSON(json_str, flatten = FALSE)
cat('address class:', class(nested_df$address), '\n')

# With flatten = TRUE:
flat_df <- fromJSON(json_str, flatten = TRUE)
cat('Columns:', names(flat_df), '\n')
print(flat_df)

Sisäkkäisistä taulukoista tulee listasarakkeita

Kun JSON-kenttä sisältää objektien taulukon, fromJSON() tallentaa sen data framen listasarakkeeksi — jokainen solu sisältää data framen. Nämä on käsiteltävä tai purettava erikseen.

library(jsonlite)

json_str <- '[{
  "user_id": 1,
  "tags": ["R", "Python", "SQL"]
},{
  "user_id": 2,
  "tags": ["Java", "Kotlin"]
}]'

df <- fromJSON(json_str)
cat('tags column class:', class(df$tags), '\n')

# Access tags for user 1:
cat('User 1 tags:', df$tags[[1]], '\n')
cat('User 2 tags:', df$tags[[2]])

purrr::map() — sisäkkäisten kenttien poimiminen

purrr::map() käyttää funktiota listan jokaiseen alkioon. Kun kukin alkio on nimetty lista (jäsennetty JSON-objekti), voitte antaa merkkijonon poimimaan nimetyn kentän jokaisesta alkiosta — tämä korvaa silmukan tiiviillä tavalla.

library(jsonlite)
library(purrr)

json_str <- '[{
  "id": 1,
  "meta": {"score": 88, "grade": "B"}
},{
  "id": 2,
  "meta": {"score": 95, "grade": "A"}
},{
  "id": 3,
  "meta": {"score": 72, "grade": "C"}
}]'

records <- fromJSON(json_str, simplifyDataFrame = FALSE)

# Extract 'score' from each record's 'meta' object
scores <- map_dbl(records, function(r) r$meta$score)
grades <- map_chr(records, function(r) r$meta$grade)

cat('Scores:', scores, '\n')
cat('Grades:', grades)

purrr::map() ja merkkijonolyhenne

purrr::map(list, 'field_name') on lyhyt muoto nimetyn kentän poimimiseen jokaisesta alkiosta — vastaa komentoa map(list, function(x) x[['field_name']]). Käyttäkää map_chr()-, map_dbl()- ja muita vastaavia funktioita saadaksenne listojen sijaan tyypitettyjä atomivektoreita.

library(jsonlite)
library(purrr)

json_str <- '[{"name":"Alice","score":90},{"name":"Bob","score":78},{"name":"Carol","score":85}]'

# Parse as list of lists
records <- fromJSON(json_str, simplifyDataFrame = FALSE)

# String shortcut to extract field
names_vec  <- map_chr(records, 'name')
scores_vec <- map_dbl(records, 'score')

cat('Names: ', names_vec, '\n')
cat('Scores:', scores_vec, '\n')

# Build a clean data frame
clean_df <- data.frame(name = names_vec, score = scores_vec)
print(clean_df)

Syvä sisäkkäisyys map()-ketjuilla

Syvästi sisäkkäistä JSON-dataa käsiteltäessä ketjuttakaa useita map()-kutsuja. Jokainen kutsu siirtyy yhden tason alemmas. Käyttäkää kullakin tasolla komentoa map(list, 'field') ja poimikaa lopullinen arvo sisimmällä tasolla tyypitetyllä map_*()-funktiolla.

library(jsonlite)
library(purrr)

json_str <- '[{
  "id": 1,
  "company": {"hq": {"city": "Berlin", "country": "Germany"}}
},{
  "id": 2,
  "company": {"hq": {"city": "Tokyo",  "country": "Japan"}}
}]'

records <- fromJSON(json_str, simplifyDataFrame = FALSE)

# Navigate: records -> company -> hq -> city
cities <- map_chr(records, function(r) r$company$hq$city)
cat('Cities:', cities, '\n')

# Or using nested map shortcut:
ids <- map_int(records, 'id')
cat('IDs:', ids)

tidyr::unnest() — listasarakkeiden litistäminen

tidyr::unnest() laajentaa data frameja sisältävän listasarakkeen ja luo yhden rivin jokaista sisäkkäistä alkiota kohden. Tämä on tidy-mallin mukainen vakiotapa JSON-datan yksi-moneen-suhteiden litistämiseen.

library(jsonlite)
library(tidyr)
library(dplyr)

json_str <- '[{
  "user_id": 1,
  "orders": [{"oid":101,"total":50},{"oid":102,"total":30}]
},{
  "user_id": 2,
  "orders": [{"oid":103,"total":80}]
}]'

df <- fromJSON(json_str)
cat('Before unnest, rows:', nrow(df), '\n')
cat('orders class:', class(df$orders), '\n')

# Unnest expands one row per order
expanded <- unnest(df, cols = orders)
cat('After unnest, rows:', nrow(expanded), '\n')
print(expanded)

jsonlite::flatten() data frameille

jsonlite::flatten() toimii valmiiksi jäsennellylle data framelle (ei JSON-merkkijonolle) ja laajentaa rekursiivisesti kaikki sisäkkäisiä data frameja sisältävät sarakkeet pisteillä erotelluiksi nimisarakeiksi. Se on hyödyllinen fromJSON(..., flatten = FALSE)-kutsun jälkeen, kun haluatte tehdä litistyksen jälkikäsittelyvaiheena.

library(jsonlite)

json_str <- '[{
  "id": 1,
  "profile": {"age": 25, "city": "Rome"}
},{
  "id": 2,
  "profile": {"age": 31, "city": "Oslo"}
}]'

# Parse without auto-flatten
nested <- fromJSON(json_str, flatten = FALSE)
cat('Columns before flatten:', names(nested), '\n')
cat('profile class:', class(nested$profile), '\n')

# Apply flatten() post-hoc
flat <- flatten(nested)
cat('Columns after flatten:', names(flat), '\n')
print(flat)

Null-arvojen käsittely sisäkkäisessä JSON-datassa

JSON:n null-arvot jäsentyvät R:ssä arvoksi NULL, mikä aiheuttaa ongelmia data frameja rakennettaessa — listassa oleva NULL poistaa alkion kokonaan. Käyttäkää purrr::map()-funktiota argumentin .default kanssa tai operaattoria %||% puuttuvien arvojen turvalliseen korvaamiseen.

library(jsonlite)
library(purrr)

json_str <- '[{"id":1,"email":"alice@example.com"},{"id":2,"email":null},{"id":3,"email":"carol@example.com"}]'

records <- fromJSON(json_str, simplifyDataFrame = FALSE)

# Unsafe: NULL drops the element
# emails <- map_chr(records, 'email')  # ERROR on null

# Safe: provide a default for missing values
emails <- map_chr(records, function(r) {
  if (is.null(r$email)) NA_character_ else r$email
})

cat('Emails:', emails)
cat('NAs:', sum(is.na(emails)))

Koko työnkulku: API:n JSON-datasta tidy-muotoiseksi data frameksi

Kootaan kaikki yhteen: realistinen työnkulku, joka jäsentää API-rajapinnasta saadun sisäkkäisen JSON-datan, poimii kentät purrr-paketilla, käsittelee null-arvot ja tuottaa analyysiin valmiin tidy-muotoisen data framen.

library(jsonlite)
library(purrr)
library(dplyr)

# Simulated API response
api_json <- '[{
  "id": 1, "name": "Alice",
  "stats": {"score": 92, "rank": 1}
},{
  "id": 2, "name": "Bob",
  "stats": null
},{
  "id": 3, "name": "Carol",
  "stats": {"score": 85, "rank": 3}
}]'

records <- fromJSON(api_json, simplifyDataFrame = FALSE)

result <- tibble(
  id    = map_int(records,  'id'),
  name  = map_chr(records,  'name'),
  score = map_dbl(records,  function(r) if (is.null(r$stats)) NA_real_ else r$stats$score),
  rank  = map_int(records,  function(r) if (is.null(r$stats)) NA_integer_ else r$stats$rank)
)

print(result)

Pikatesti

Teillä on data frame df, jonka sarake orders on listasarakkeena ja sisältää data frameja (yhden käyttäjää kohden). Millä funktiolla tästä saadaan yksi rivi jokaista tilausta kohden?

Sisäkkäinen JSON – tärkeimmät opit

Sisäkkäisen JSON-datan käsittely R:ssä edellyttää kerroksittaista työkalupakkia:

  • fromJSON(json, flatten = TRUE) — litistää sisäkkäisyyttä automaattisesti yhden tason verran
  • fromJSON(json, simplifyDataFrame = FALSE) — palauttaa listojen listan manuaalista käsittelyä varten
  • Sisäkkäiset taulukot → tuloksena syntyvän data framen list-sarakkeita
  • purrr::map_chr/dbl/int(list, 'field') — poimii tyypitetyt arvot jokaisesta alkiosta
  • Ketjutetut map()-kutsut etenevät syvän sisäkkäisyyden tasolta toiselle
  • tidyr::unnest(df, cols = col) — laajentaa data frameja sisältävät list-sarakkeet
  • jsonlite::flatten(df) — litistää sisäkkäiset data frame -sarakkeet jäsentämisen jälkeen
  • Varaudu aina NULL-arvoon rakenteella if (is.null(x)) NA else x
library(jsonlite)
library(purrr)

# Quick reference:
json <- '[{"id":1,"info":{"val":10}},{"id":2,"info":null}]'
recs <- fromJSON(json, simplifyDataFrame = FALSE)

# Safe extraction with null guard
vals <- map_dbl(recs, function(r) {
  if (is.null(r$info)) NA_real_ else r$info$val
})

result <- data.frame(id = map_int(recs, 'id'), val = vals)
print(result)
Aloita maksutta

Opi R tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
43
Oppitunnit
159

Usein kysytyt kysymykset

Onko oppitunti ”Sisäkkäisten JSON-rakenteiden käsittely” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa R Academy-oppimispolun 3 oppituntia, myös oppitunnin “Sisäkkäisten JSON-rakenteiden käsittely”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. R Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Sisäkkäisten JSON-rakenteiden käsittely”?

Muun­takaa syvästi sisäkkäinen JSON analyysia varten selkeärakenteisiksi data frameiksi. Harjoittelet R Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni R Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin R Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”Sisäkkäisten JSON-rakenteiden käsittely”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä R Academy-oppitunnilla?

Kyllä. Jokainen R Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. JSON-jäsentäminen jsonlite-paketilla
  2. HTTP-pyyntöjen tekeminen httr2-paketilla
  3. REST-rajapintojen käyttäminen R:ssä
  4. Sisäkkäisten JSON-rakenteiden käsittely
← Takaisin: R Academy