0Pricing
R Academy · 강의

중첩된 JSON 구조 처리

깊게 중첩된 JSON을 분석에 사용할 깔끔한 데이터 프레임으로 평탄화합니다.

중첩된 JSON 구조 처리은(는) CoddyKit의 무료 R Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 R Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

중첩 JSON이 까다로운 이유

REST API는 하나의 필드에 객체 배열이 들어 있고, 그 객체 안에 다시 다른 객체가 들어 있는 깊이 중첩된 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()에 중첩된 데이터 프레임을 재귀적으로 풀어 점으로 구분된 이름의 열로 만들도록 지시합니다. 한 단계의 중첩에 잘 맞으며, 중간 정도로 중첩된 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() 호출을 연결해 사용합니다. 각 호출은 한 단계씩 안쪽으로 내려갑니다. 각 단계에서 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()는 데이터 프레임이 들어 있는 목록 열을 확장해 중첩된 요소마다 한 행을 만듭니다. 이는 JSON 데이터의 일대다 관계를 평탄화하는 표준 정돈 방식입니다.

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은 해당 요소를 완전히 제거하므로 데이터 프레임을 만들 때 문제가 발생합니다. 누락된 값을 안전하게 대체하려면 purrr::map()에 .default 인수를 사용하거나 %||%를 사용하세요.

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 열이 사용자마다 하나씩 데이터 프레임을 포함하는 목록 열인 데이터 프레임 df가 있습니다. 이를 주문마다 한 행이 되도록 확장하는 함수는 무엇인가요?

중첩된 JSON — 핵심 요점

R에서 중첩된 JSON을 처리하려면 여러 계층의 도구 모음이 필요합니다:

  • fromJSON(json, flatten = TRUE) — 중첩을 한 단계 자동으로 평탄화합니다
  • fromJSON(json, simplifyDataFrame = FALSE) — 수동 처리할 수 있도록 리스트의 리스트를 가져옵니다
  • 중첩된 배열 → 결과 데이터 프레임의 리스트 열
  • purrr::map_chr/dbl/int(list, 'field') — 모든 요소에서 지정한 자료형의 값을 추출합니다
  • 연결된 map() 호출은 깊이 중첩된 여러 수준을 따라 내려갑니다
  • tidyr::unnest(df, cols = col) — 데이터 프레임으로 이루어진 리스트 열을 확장합니다
  • jsonlite::flatten(df) — 구문 분석 후 중첩된 데이터 프레임 열을 평탄화합니다
  • 항상 NULL을 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)

자주 묻는 질문

“중첩된 JSON 구조 처리” 강의는 무료인가요?

네 — “중첩된 JSON 구조 처리” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 R Academy 강의 전체를 잠금 해제할 수 있습니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“중첩된 JSON 구조 처리”에서 뭘 배우나요?

깊게 중첩된 JSON을 분석에 사용할 깔끔한 데이터 프레임으로 평탄화합니다. 브라우저에서 직접 실행하는 실습 코드로 R Academy을(를) 배우며, 24/7 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(으)로 돌아가기