RでのR JSONおよびXMLデータ:jsonliteの完全ガイド
前回のレッスンでは、CSVとExcelについて学びましたが、Webの時代において、データはますますJSON形式(APIの応答、設定ファイル、NoSQLデータベースなど)で扱われるようになっています。このレッスンでは、RでJSONを読み書きするための標準的な方法:
jsonlite、およびXMLデータの扱い方:xml2について学びます。
このレッスンを修了すると、APIから返されたネストされたJSONを5秒でデータフレームに展開し、独自のJSON設定ファイルを作成できるようになります。
1. 学習内容
- JSONとXMLとは何ですか?また、それぞれどのような場合に使用すべきですか?
- jsonlite パッケージと 4 つの主要関数のインストール
- fromJSON:JSONを読み込みます(ネストされたデータをフラット化します)
- toJSON は JSON を出力します
- ネストされたJSON(APIのレスポンス)の実践ガイド
- xml2: XMLファイルを読み込む
- JSON ↔ data.frame の変換
- 実践ガイド:APIデータの一括抽出
2. APIデータセットの物語
(1) 課題:APIがネストされたJSONを返す
ボブは天気アプリを開発中で、天気APIからデータを取得する必要があります:
{
"status": "ok",
"data": {
"city": "Beijing",
"date": "2024-01-15",
"forecast": [
{"day": "Monday", "high": 5, "low": -3, "weather": "Sunny"},
{"day": "Tuesday", "high": 7, "low": -1, "weather": "Cloudy"},
{"day": "Wednesday", "high": 3, "low": -5, "weather": "Snowy"}
]
}
}
彼は「7日間の天気予報」を抽出して、分析のためにRに保存したかった。Pythonでは10行のコード requests + json が必要だったが、Rではたった1行で済んだ――
(2) Rを用いた解決策
library(jsonlite)
# 1. Reading nested data with a single line of code JSON
weather <- fromJSON("https://api.weather.com/forecast?city=Beijing")
# 2. Extract 7 Weather Forecast(Nested → Data Frame)
forecast <- weather$data$forecast # It's a data frame!
# 3. Write JSON Layout
config <- list(api_key = "xxx", cities = c("Beijing", "Shanghai"))
write_json(config, "config.json", pretty = TRUE)
たった3行のコードでネストされたJSON。これこそがjsonliteの「魔法」です。
graph LR
A[API URL<br/>weather.com/forecast] --> B[jsonlite::fromJSON]
B --> C{Nested JSON}
C --> D[forecast Array<br/>Auto-rotate data.frame]
C --> E[current Object<br/>Auto-rotate list]
D --> F[dplyr Analysis<br/>7 Weather Forecast]
D --> G[ggplot2 Drawing<br/>Trend Visualization]
E --> H[Real-time Weather Data]
style A fill:#cce5ff
style B fill:#d4edda
style C fill:#fff3cd
style D fill:#f8d7da
style E fill:#e1d4ff
style F fill:#ffe1d4
style G fill:#cce5ff
style H fill:#d4edda
3. JSON 対 XML:どちらをいつ使うべきか?
graph TB
subgraph JSON[JSON Faction]
J1[Grammar: Key-value pairs Concise]
J2[Type: Numbers/String/Boolean/Array/Object]
J3[Analysis: Fast C Language Implementation]
J4[R Package: jsonlite]
end
subgraph XML[XML Faction]
X1[Grammar: Nested Tags Long-winded]
X2[Type: All strings]
X3[Analysis: slower]
X4[R Package: xml2]
end
JSON --> J5[Web API / NoSQL / Profile]
XML --> X5[Legacy Enterprise Systems / SOAP / RSS / SVG]
style JSON fill:#d4edda
style XML fill:#f8d7da
(1) 2つの形式の比較
| プロパティ | JSON | XML |
|---|---|---|
| 正式名称 | JavaScript Object Notation | eXtensible Markup Language |
| 構文 | {"key": "value"} |
<key>value</key> |
| 読みやすさ | 簡潔さ | 冗長さ |
| データ型 | 数値、文字列、ブール値、null、配列、オブジェクト | すべての文字列 |
| 解析速度 | 速い | 遅い |
| 主なユースケース | Web API、NoSQL、設定ファイル | レガシーなエンタープライズシステム、SOAP、ドキュメント(RSS、SVG) |
| Rパッケージ | jsonlite |
xml2 |
(2) JSONの例
{
"name": "Alice",
"age": 25,
"is_student": true,
"scores": [85, 90, 92],
"address": {
"city": "Beijing",
"zip": "100000"
}
}
(3) XMLの例
<student>
<name>Alice</name>
<age>25</age>
<scores>
<item>85</item>
<item>90</item>
<item>92</item>
</scores>
<address>
<city>Beijing</city>
<zip>100000</zip>
</address>
</student>
4. jsonliteの4つの主要な機能
(1) 関数クイックリファレンス表
| 機能 | 目的 |
|---|---|
fromJSON() |
JSON → Rオブジェクト(リスト/データフレーム) |
toJSON() |
Rオブジェクト → JSON文字列 |
read_json() |
JSONファイルやURLを読み込む |
write_json() |
JSON ファイルを作成する |
(2) fromJSON の詳細な説明
library(jsonlite)
# 1. Read JSON String
json_str <- '{"name": "Alice", "age": 25}'
fromJSON(json_str)
# $name
# [1] "Alice"
#
# $age
# [1] 25
# 2. Read JSON Documents
df <- fromJSON("data.json")
# 3. Read URL(API)
weather <- fromJSON("https://api.example.com/weather?city=beijing")
# 4. Expand directly into a data frame
json_array <- '[{"name": "A", "age": 20}, {"name": "B", "age": 25}]'
fromJSON(json_array)
# name age
# 1 A 20
# 2 B 25 ← Automatically Rotate Data Frames!
(3) ネストされたJSONの自動展開
nested <- '{
"status": "ok",
"data": {
"city": "Beijing",
"forecast": [
{"day": "Monday", "high": 5, "low": -3},
{"day": "Tuesday", "high": 7, "low": -1}
]
}
}'
result <- fromJSON(nested)
str(result)
# List of 2
# $ status: chr "ok"
# $ data : List of 2
# ..$ city : chr "Beijing"
# ..$ forecast :'data.frame': 2 obs. of 3 variables:
# .. ..$ day : chr [1:2] "Monday" "Tuesday"
# .. ..$ high: num [1:2] 5 7
# .. ..$ low : num [1:2] -3 -1
# Automatically Convert Nested Arrays to DataFrames!
result$data$forecast
# day high low
# 1 Monday 5 -3
# 2 Tuesday 7 -1
5. toJSON の詳細な解説
(1) 基本的な構文
toJSON(x, pretty = FALSE, auto_unbox = FALSE, dataframe = "columns")
(2) 実践的な応用
# 1. Data Frame → JSON
df <- data.frame(name = c("A", "B"), age = c(20, 25))
toJSON(df)
# [{"name":"A","age":20},{"name":"B","age":25}]
# 2. Format the output(Indented)
toJSON(df, pretty = TRUE)
# [
# {
# "name": "A",
# "age": 20
# },
# {
# "name": "B",
# "age": 25
# }
# ]
# 3. List → JSON
config <- list(
api_key = "secret123",
cities = c("Beijing", "Shanghai", "Guangzhou"),
options = list(timeout = 30, retry = 3)
)
toJSON(config, pretty = TRUE)
# {
# "api_key": "secret123",
# "cities": ["Beijing", "Shanghai", "Guangzhou"],
# "options": {
# "timeout": 30,
# "retry": 3
# }
# }
(3) 主要なパラメータ
| パラメータ | 機能 | デフォルト |
|---|---|---|
pretty |
書式設定(インデント付き) | FALSE |
auto_unbox |
長さが 1 のベクトルから配列を自動的に削除する | FALSE |
dataframe |
データフレームの表示モード | "columns" |
# auto_unbox:Prevent a single value from becoming an array
toJSON(list(name = "Alice", scores = c(85))) # Default
# {"name":["Alice"],"scores":[85]}
toJSON(list(name = "Alice", scores = c(85)), auto_unbox = TRUE)
# {"name":"Alice","scores":85} ← Do not convert single values to arrays
(4) write_json: ファイルへの書き込み
# Write JSON Document
write_json(config, "config.json", pretty = TRUE)
# Write concisely JSON(No indentation)
write_json(data, "data.json")
# Append to the file(Read first, Merge, then Write)
old <- read_json("data.json", simplifyVector = FALSE)
new <- c(old, list(updated_at = Sys.time()))
write_json(new, "data.json", pretty = TRUE)
6. 実践編:APIデータのバッチ抽出
(1) 実際のAPI呼び出し
library(jsonlite)
library(dplyr)
# Call a public API(GitHub User Information)
user_info <- fromJSON("https://api.github.com/users/hadley")
str(user_info)
# List of 50+
# $ login : chr "hadley"
# $ id : int 4192
# $ name : chr "Hadley Wickham"
# $ company : chr "@posit-pbc"
# $ location : chr "Houston, TX"
# $ public_repos : int 50
# ...
# Extract Key Fields
info <- tibble(
name = user_info$name,
company = user_info$company,
repos = user_info$public_repos,
followers = user_info$followers
)
print(info)
(2) 複数のユーザーの一括取得
# Retrieve multiple items in bulk GitHub Number of repositories per user
users <- c("hadley", "yihui", "jtleek", "rstudio")
repos_data <- lapply(users, function(user) {
info <- fromJSON(paste0("https://api.github.com/users/", user))
tibble(
user = user,
repos = info$public_repos,
followers = info$followers,
created_at = as.Date(info$created_at)
)
}) |> bind_rows()
print(repos_data)
7. xml2:XMLファイルの読み込み
(1) インストールと主要機能
install.packages("xml2")
library(xml2)
# 4 Core Functions
read_xml() # Read XML Document
xml_find_all() # XPath Query Node
xml_text() # Extract Node Text
xml_attr() # Retrieve Node Properties
(2) 実践編:RSSフィードの読み方
# 1. Read RSS(XML Format)
rss <- read_xml("https://www.r-bloggers.com/feed")
# 2. Extract All `<item>` Node
items <- xml_find_all(rss, "//item")
cat("Found", length(items), "Articles\n")
# 3. Extract the title of each article,Link,Date
articles <- tibble(
title = xml_text(xml_find_all(items, "./title")),
link = xml_attr(xml_find_all(items, "./link"), "href"),
pub_date = xml_text(xml_find_all(items, "./pubDate"))
)
print(head(articles, 3))
(3) 実践編:SVG(XML画像)の読み込み
# SVG is an XML format
svg <- read_xml("logo.svg")
# Extract All <circle> cx, cy, r attributes
circles <- xml_find_all(svg, "//circle")
data.frame(
cx = as.numeric(xml_attr(circles, "cx")),
cy = as.numeric(xml_attr(circles, "cy")),
r = as.numeric(xml_attr(circles, "r"))
)
8. 実践:JSON設定ファイルの読み込みと書き込み
(1) プロジェクトの構成
project/
├── config.json # Profile
├── R/
│ ├── main.R # Main Program
│ └── utils.R # Utility Functions
└── data/
└── input.json # Input Data
(2) config.json の例
{
"api": {
"key": "your-api-key",
"endpoint": "https://api.example.com",
"timeout": 30
},
"cities": ["Beijing", "Shanghai", "Guangzhou", "Shenzhen"],
"options": {
"log_level": "info",
"max_retries": 3
}
}
(3) Rプログラムの設定の読み込み
# Load Configuration
config <- read_json("config.json", simplifyVector = FALSE)
print(config$cities)
# [1] "Beijing" "Shanghai" "Guangzhou" "Shenzhen"
# Using the Configuration
for (city in config$cities) {
url <- paste0(config$api$endpoint, "?city=", city, "&key=", config$api$key)
data <- fromJSON(url)
# Processing data...
}
# Update Configuration
config$options$log_level <- "debug"
write_json(config, "config.json", pretty = TRUE, auto_unbox = TRUE)
9. 完全な例:APIデータ抽出とJSONへの保存
以下は、このレッスンで取り上げたすべての概念を結びつけた完全なワークフローの例です。
▶ サンプル:天気APIデータのスクレイピングと保存
# ============================================
# Weather API Data Extraction + Persistence
# Features:Simulated Crawling 4 City Weather,Save as JSON
# ============================================
library(jsonlite)
library(dplyr)
# 1. Simulation API Response(For use in actual projects fromJSON(url))
mock_api_response <- function(city) {
set.seed(match(city, c("Beijing", "Shanghai", "Guangzhou", "Shenzhen")))
list(
status = "ok",
data = list(
city = city,
date = Sys.Date(),
current = list(
temp = sample(0:30, 1),
humidity = sample(40:90, 1),
weather = sample(c("Sunny", "Cloudy", "Rainy", "Snowy"), 1)
),
forecast = data.frame(
day = c("Today", "Tomorrow", "The day after tomorrow", "The day after tomorrow"),
high = sample(5:30, 4),
low = sample(-5:15, 4),
weather = sample(c("Sunny", "Cloudy", "Rainy", "Snowy"), 4, replace = TRUE),
stringsAsFactors = FALSE
)
)
)
}
# 2. Batch Scraping 4 City
cities <- c("Beijing", "Shanghai", "Guangzhou", "Shenzhen")
cat("=== Fetching 4 City Weather ===\n")
all_weather <- lapply(cities, mock_api_response)
names(all_weather) <- cities
# 3. Retrieve All Forecasts(Nested → Data Frame)
all_forecast <- bind_rows(lapply(all_weather, function(w) {
fc <- w$data$forecast
fc$city <- w$data$city
fc
}))
cat("\n=== 4 The Future of Cities 4 Weather Forecast ===\n")
print(all_forecast)
# 4. Get the current weather(Nested → Data Frame)
current_weather <- bind_rows(lapply(all_weather, function(w) {
cw <- w$data$current
tibble(
city = w$data$city,
temp = cw$temp,
humidity = cw$humidity,
weather = cw$weather
)
}))
cat("\n=== Current Weather ===\n")
print(current_weather)
# 5. Save as JSON
write_json(all_weather, "all_weather.json", pretty = TRUE, auto_unbox = TRUE)
cat("\n=== Saved all_weather.json ===\n")
# 6. Save as a compressed file JSON(Remove Indentation)
write_json(all_weather, "all_weather_compact.json", auto_unbox = TRUE)
# 7. Read back JSON for verification
reloaded <- read_json("all_weather.json", simplifyVector = FALSE)
cat("\n=== Read-Back Verification ===\n")
cat("Number of cities:", length(reloaded), "\n")
cat("Current Temperature in Beijing:", reloaded$Beijing$data$current$temp, "°C\n")
# 8. Write a concise version for a single city JSON Layout
config <- list(
api_key = "secret-key-xxx",
default_city = "Beijing",
update_interval = 3600,
enabled_cities = cities
)
write_json(config, "config.json", pretty = TRUE, auto_unbox = TRUE)
cat("\n=== The configuration file has been generated config.json ===\n")
# 9. Read the configuration file
loaded_config <- read_json("config.json", simplifyVector = FALSE)
cat("Default City:", loaded_config$default_city, "\n")
cat("Enable City:", paste(loaded_config$enabled_cities, collapse = ", "), "\n")
# 10. Use jsonlite Processing API Error
cat("\n=== Error Handling Examples ===\n")
error_response <- '{"status": "error", "message": "Invalid API key"}'
result <- tryCatch(
{
parsed <- fromJSON(error_response)
if (parsed$status == "error") stop(parsed$message)
parsed
},
error = function(e) {
cat("API Error:", e$message, "\n")
NULL
}
)
期待される出力(抜粋):
=== 4 The Future of Cities 4 Weather Forecast ===
day high low weather city
1 Today 12 -3 Sunny Beijing
2 Tomorrow 15 0 Cloudy Beijing
3 The day after tomorrow 8 -5 Snowy Beijing
...
=== Current Weather ===
# A tibble: 4 × 4
city temp humidity weather
`<chr>` `<int>` `<int>` `<chr>`
1 Beijing 18 65 Sunny
2 Shanghai 22 78 Cloudy
3 Guangzhou 28 85 Rainy
4 Shenzhen 26 72 Cloudy
❓ よくある質問
fromJSON によって返されたリストを data.frame に変換するにはどうすればよいですか?as.data.frame() or dplyr::bind_rows() を使用することで、強制的に変換を行うことができます。nullをRに変換するにはどうすればよいですか?null → NA、true → TRUE、false → FALSE;配列 → リスト/データフレーム。jsonliteがこれを自動的に処理します。📖 まとめ
- JSONはWeb APIの標準フォーマットであるのに対し、XMLは依然としてレガシーな企業システムやRSS、SVGなどで使用されています。
- jsonlite は R における JSON 処理の標準です:R の機能のみに依存し、ネストされたデータを自動的にフラット化し、優れたパフォーマンスを発揮します
- 4つの主要機能:
fromJSON/toJSON/read_json/write_json - jsonliteの素晴らしさ:ネストされた配列は自動的にデータフレームに変換されます(他の言語では、手動でフラット化する必要があります)。
toJSON()主要なパラメータ:pretty(書式設定)、auto_unbox(単一の値を配列形式以外に変換)- xml2 XMLの読み込み:4つの関数
read_xmlxml_find_allxml_textxml_attr(XPath対応) - JSONは設定ファイルの保存に適しています(人間が読みやすく、汎用性が高い);Rは内部で
saveRDSを使用しています(型を保持する)
📝 練習問題
-
基本問題:ネストされたJSON文字列(配列
name、age、scoresを含む)を構築し、fromJSON()を使用してそれを解析した後、toJSON(pretty = TRUE)を使用して整形されたバージョンを出力し、ネストされたデータが正しくフラット化されていることを確認する。 -
基本演習:データフレーム(5行、3列)をJSONに変換し、
read_json()を使用してそれを読み込み直し、データが完全であることを確認してください。 -
基本的な問題:
xml2を使用して単純な XML 文字列を読み込み、すべての<item>ノードのname属性およびテキストコンテンツを抽出し、そのデータをデータフレームに出力する。 -
応用問題:APIのレスポンス(
status、data、forecastのネスト構造を含む)をシミュレートし、fromJSONを使用してそれを解析した後、bind_rowsを使用してforecast配列をデータフレームにマージしてください。 -
課題:以下の機能を持つ完全なプログラムを作成してください。① 3つの都市の気象データを含むJSONファイルを作成する。② すべての都市の現在の気温を読み取り、抽出する。③ 全国の平均気温を算出する。④
write_jsonを使用して、結果を新しいファイルに書き出す。コンソールの出力をスクリーンショットに撮り、保存してください。



