0Pricing
R Academy · レッスン

ネストされた JSON 構造を扱う

深くネストされた JSON をフラット化し、分析用の整然データフレームに変換します。

「ネストされた JSON 構造を扱う」はCoddyKit上の無料R Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはR Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 R Academyコースには全4レッスンが含まれています。

ネストされたJSONが難しい理由

REST APIは、1つのフィールドにオブジェクトの配列が含まれ、さらに各オブジェクトに別のオブジェクトが含まれるような、深くネストされたJSONを返すことがよくあります。この構造を整然データフレームに変換するには、jsonlite、purrr、tidyrがどのように連携するかを理解する必要があります。

# 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() — 基本的な解析

jsonlite::fromJSON()は、JSON文字列またはファイルパスをRオブジェクトに変換します。単純なフラットJSONはリストまたはデータフレームになります。ネストされたJSONはネストされたリストになり、オブジェクトの配列はリスト列に格納されたデータフレームになります。

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)

flatten = TRUEを指定したfromJSON()

flatten = TRUE引数を指定すると、fromJSON()はネストされたデータフレームを再帰的に展開し、ドット区切りの名前を持つ列に変換します。ネストが1階層の場合に適しており、中程度にネストされたJSONを扱う最も手早い方法です。

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)

ネストされた配列はリスト列になる

JSONのフィールドにオブジェクトの配列が含まれている場合、fromJSON()はそれをデータフレーム内のリスト列として格納します。各セルにはデータフレームが格納されます。これらには明示的にアクセスするか、アンネストする必要があります。

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() — ネストされたフィールドを取り出す

purrr::map()は、リストの各要素に関数を適用します。各要素が名前付きリスト(解析済みのJSONオブジェクト)の場合、文字列を渡すことで、すべての要素から名前付きフィールドを取り出せます。ループを簡潔に置き換える方法です。

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()

purrr::map(list, 'field_name')は、すべての要素から名前付きフィールドを取り出す省略記法です。map(list, function(x) x[['field_name']])と同等です。リストではなく型付きのアトミックベクトルを取得するには、map_chr()、map_dbl()などを使用します。

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)

map()チェーンで深いネストを処理する

深くネストされたJSONには、複数のmap()呼び出しを連鎖させます。各呼び出しで1階層ずつ下へ進みます。各階層でmap(list, 'field')を使用し、最も内側の段階で型付きのmap_*()を適用して最終的な値を取り出します。

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() — リスト列を展開する

tidyr::unnest()は、データフレームを含むリスト列を展開し、ネストされた要素ごとに1行を作成します。JSONデータの1対多の関係をフラット化する、tidyデータで標準的な方法です。

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()

jsonlite::flatten()は、解析済みのデータフレーム(JSON文字列ではありません)を処理し、ネストされたデータフレーム列を再帰的に展開して、ドット区切りの名前付き列に変換します。fromJSON(..., flatten = FALSE)の後に、後処理としてフラット化したい場合に便利です。

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)

ネストされたJSONのnullを扱う

JSONのnull値はRではNULLとして解析されます。リスト内のNULLは要素全体を削除するため、データフレームの作成時に問題になります。.default引数を指定したpurrr::map()や%||%を使って、欠損値を安全に置き換えます。

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)))

完全なパイプライン:APIのJSONから整然データフレームへ

これまでの内容をすべて組み合わせ、APIから取得したネストされたJSONを解析し、purrrでフィールドを取り出し、nullを処理して、分析に使用できる整然データフレームを作成する現実的なパイプラインを構築します。

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)

クイックチェック

orders列がユーザーごとに1つのデータフレームを含むリスト列になっているデータフレームdfがあります。これを注文ごとに1行へ展開する関数はどれでしょうか。

ネストされたJSON — 重要ポイント

RでネストされたJSONを扱うには、段階的なツールキットが必要です:

  • fromJSON(json, flatten = TRUE) — ネストを1階層自動的にフラット化します
  • fromJSON(json, simplifyDataFrame = FALSE) — 手動処理用のリストのリストを取得します
  • ネストされた配列 → 結果のデータフレームではリスト列になります
  • purrr::map_chr/dbl/int(list, 'field') — 各要素から型付きの値を抽出します
  • map()を連鎖させると、深いネストの階層を順にたどれます
  • tidyr::unnest(df, cols = col) — データフレームのリスト列を展開します
  • jsonlite::flatten(df) — パース後のネストされたデータフレーム列をフラット化します
  • if (is.null(x)) NA else xで、必ずNULLに対処します
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)

よくある質問

「ネストされた JSON 構造を扱う」レッスンは無料ですか?

はい。「ネストされた JSON 構造を扱う」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、R Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 R Academyコースには全4レッスンが含まれています。

「ネストされた JSON 構造を扱う」で何を学びますか?

深くネストされた JSON をフラット化し、分析用の整然データフレームに変換します。 ブラウザで直接実行するハンズオンコードでR Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

R Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのR Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「ネストされた JSON 構造を扱う」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このR Academyレッスンでコードを書いて実行できますか?

はい。すべてのR Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. jsonlite で JSON をパースする
  2. httr2 で HTTP リクエストを送信する
  3. R で REST API を利用する
  4. ネストされた JSON 構造を扱う
← R Academyに戻る