404 Not Found

404 Not Found


nginx

RでのR JSONおよびXMLデータ:jsonliteの完全ガイド

前回のレッスンでは、CSVとExcelについて学びましたが、Webの時代において、データはますますJSON形式(APIの応答、設定ファイル、NoSQLデータベースなど)で扱われるようになっています。このレッスンでは、RでJSONを読み書きするための標準的な方法:jsonlite、およびXMLデータの扱い方:xml2について学びます。

このレッスンを修了すると、APIから返されたネストされたJSONを5秒でデータフレームに展開し、独自のJSON設定ファイルを作成できるようになります。

1. 学習内容



2. APIデータセットの物語

(1) 課題:APIがネストされたJSONを返す

ボブは天気アプリを開発中で、天気APIからデータを取得する必要があります:

R
{
  "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を用いた解決策

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の「魔法」です。

100%
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:どちらをいつ使うべきか?

100%
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の例

R
{
  "name": "Alice",
  "age": 25,
  "is_student": true,
  "scores": [85, 90, 92],
  "address": {
    "city": "Beijing",
    "zip": "100000"
  }
}

(3) XMLの例

R
<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>
💡 ヒントほぼすべての新規プロジェクトではJSONが使用されています。JSONは簡潔で読みやすく、解析も高速です。XMLが依然として使用されているのは、レガシーのエンタープライズシステムや政府のデータに限られます



4. jsonliteの4つの主要な機能

(1) 関数クイックリファレンス表

機能 目的
fromJSON() JSON → Rオブジェクト(リスト/データフレーム)
toJSON() Rオブジェクト → JSON文字列
read_json() JSONファイルやURLを読み込む
write_json() JSON ファイルを作成する

(2) fromJSON の詳細な説明

R
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の自動展開

R
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
💡 ヒント: jsonliteの真骨頂は、ネストされた配列を自動的にフラット化してデータフレームに変換できる点にあります。他の言語(Pythonなど)では、この処理を手動で行う必要があります。



5. toJSON の詳細な解説

(1) 基本的な構文

R
toJSON(x, pretty = FALSE, auto_unbox = FALSE, dataframe = "columns")

(2) 実践的な応用

R
# 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"
R
# 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: ファイルへの書き込み

R
# 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呼び出し

R
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) 複数のユーザーの一括取得

R
# 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) インストールと主要機能

R
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フィードの読み方

R
# 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画像)の読み込み

R
# 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) プロジェクトの構成

R
project/
├── config.json          # Profile
├── R/
│   ├── main.R           # Main Program
│   └── utils.R          # Utility Functions
└── data/
    └── input.json       # Input Data

(2) config.json の例

R
{
  "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プログラムの設定の読み込み

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データのスクレイピングと保存

R
# ============================================
# 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
  }
)
▶ 試してみよう

期待される出力(抜粋):

R
=== 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

❓ よくある質問

Q fromJSON によって返されたリストを data.frame に変換するにはどうすればよいですか?
A ネストされた配列は自動的に data.frame に変換されます。通常のリストの場合は、as.data.frame() or dplyr::bind_rows() を使用することで、強制的に変換を行うことができます。
Q JSON内のnullをRに変換するにはどうすればよいですか?
A nullNAtrueTRUEfalseFALSE;配列 → リスト/データフレーム。jsonliteがこれを自動的に処理します。

📖 まとめ


📝 練習問題

  1. 基本問題:ネストされたJSON文字列(配列 nameagescores を含む)を構築し、fromJSON() を使用してそれを解析した後、toJSON(pretty = TRUE) を使用して整形されたバージョンを出力し、ネストされたデータが正しくフラット化されていることを確認する。

  2. 基本演習:データフレーム(5行、3列)をJSONに変換し、read_json() を使用してそれを読み込み直し、データが完全であることを確認してください。

  3. 基本的な問題xml2 を使用して単純な XML 文字列を読み込み、すべての <item> ノードの name 属性およびテキストコンテンツを抽出し、そのデータをデータフレームに出力する。

  4. 応用問題:APIのレスポンス(statusdataforecastのネスト構造を含む)をシミュレートし、fromJSONを使用してそれを解析した後、bind_rowsを使用してforecast配列をデータフレームにマージしてください。

  5. 課題:以下の機能を持つ完全なプログラムを作成してください。① 3つの都市の気象データを含むJSONファイルを作成する。② すべての都市の現在の気温を読み取り、抽出する。③ 全国の平均気温を算出する。④ write_json を使用して、結果を新しいファイルに書き出す。コンソールの出力をスクリーンショットに撮り、保存してください。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%