Gérer des structures JSON imbriquées
Aplatissez des objets JSON profondément imbriqués en trames de données ordonnées pour l’analyse.
Gérer des structures JSON imbriquées est une leçon R Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage R Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours R Academy comprend 4 leçons au total.
Pourquoi le JSON imbriqué est difficile à traiter
Les API REST renvoient souvent du JSON profondément imbriqué, dans lequel un seul champ peut contenir un tableau d’objets qui contiennent eux-mêmes d’autres objets. Transformer cette structure en une trame de données organisée nécessite de comprendre comment jsonlite, purrr et tidyr fonctionnent ensemble.
# 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() — analyse de base
jsonlite::fromJSON() convertit une chaîne JSON ou un chemin de fichier en objets R. Un JSON simple et plat devient une liste ou une trame de données. Un JSON imbriqué devient une liste imbriquée : les tableaux d’objets deviennent des trames de données stockées dans des colonnes de listes.
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() avec flatten = TRUE
L’argument flatten = TRUE indique à fromJSON() de décomposer récursivement les trames de données imbriquées en colonnes dont les noms sont séparés par des points. Cette option convient bien à un niveau d’imbrication et constitue la manière la plus rapide de traiter un JSON modérément imbriqué.
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)Les tableaux imbriqués deviennent des colonnes de listes
Lorsqu’un champ JSON contient un tableau d’objets, fromJSON() le stocke comme une colonne de listes dans la trame de données : chaque cellule contient une trame de données. Vous devez y accéder explicitement ou les désimbriquer.
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() — extraire des champs imbriqués
purrr::map() applique une fonction à chaque élément d’une liste. Lorsque chaque élément est une liste nommée, issue de l’analyse d’un objet JSON, vous pouvez lui transmettre une chaîne pour extraire un champ nommé de chaque élément : c’est un remplacement concis d’une boucle.
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() avec raccourci pour les chaînes
purrr::map(list, 'field_name') est une écriture abrégée pour extraire un champ nommé de chaque élément, équivalente à map(list, function(x) x[['field_name']]). Utilisez map_chr(), map_dbl(), etc. pour obtenir des vecteurs atomiques typés plutôt que des listes.
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)Imbrication profonde avec des chaînes de map()
Pour un JSON profondément imbriqué, enchaînez plusieurs appels à map(). Chaque appel descend d’un niveau. Utilisez map(list, 'field') à chaque niveau et appliquez un map_*() typé à l’étape la plus interne pour extraire la valeur finale.
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() — aplatir des colonnes de listes
tidyr::unnest() développe une colonne de listes contenant des trames de données et crée une ligne par élément imbriqué. Il s’agit de l’approche organisée standard pour aplatir les relations un-à-plusieurs dans des données 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() sur des trames de données
jsonlite::flatten() agit sur une trame de données déjà analysée, et non sur une chaîne JSON, en développant récursivement les colonnes imbriquées contenant des trames de données pour créer des colonnes dont les noms sont séparés par des points. Cette fonction est utile après fromJSON(..., flatten = FALSE) lorsque vous souhaitez effectuer l’aplatissement comme étape de post-traitement.
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)Gérer les valeurs nulles dans un JSON imbriqué
Les valeurs JSON null sont analysées comme NULL dans R, ce qui crée des problèmes lors de la construction de trames de données : une valeur NULL dans une liste supprime entièrement l’élément. Utilisez purrr::map() avec un argument .default ou %||% pour remplacer les valeurs manquantes de manière sûre.
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)))Chaîne complète : du JSON d’API à la trame de données organisée
Mettons tout cela en pratique : une chaîne réaliste qui analyse le JSON imbriqué d’une API, extrait des champs avec purrr, gère les valeurs nulles et produit une trame de données organisée, prête pour l’analyse.
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)Vérification rapide
Vous disposez d’une trame de données df dont la colonne orders est une colonne de listes contenant des trames de données, une par utilisateur. Quelle fonction développe cette colonne pour créer une ligne par commande ?
JSON imbriqué — Points clés à retenir
La gestion des JSON imbriqués dans R nécessite une boîte à outils à plusieurs niveaux :
fromJSON(json, flatten = TRUE)— aplatir automatiquement un niveau d’imbricationfromJSON(json, simplifyDataFrame = FALSE)— obtenir une liste de listes pour un traitement manuel- Tableaux imbriqués → colonnes de listes dans le bloc de données obtenu
purrr::map_chr/dbl/int(list, 'field')— extraire des valeurs typées de chaque élément- Des appels
map()enchaînés permettent de parcourir les niveaux d’imbrication profonds tidyr::unnest(df, cols = col)— développer les colonnes de listes contenant des blocs de donnéesjsonlite::flatten(df)— aplatir les colonnes imbriquées de blocs de données après l’analyse- Protégez toujours votre code contre
NULLavecif (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)Questions Fréquemment Posées
La leçon « Gérer des structures JSON imbriquées » est-elle gratuite ?
Oui — le texte complet de « Gérer des structures JSON imbriquées » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours R Academy, passe à CoddyKit PRO. Le cours R Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Gérer des structures JSON imbriquées » ?
Aplatissez des objets JSON profondément imbriqués en trames de données ordonnées pour l’analyse. Tu pratiques R Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer R Academy ?
Aucune expérience préalable n'est requise. R Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Gérer des structures JSON imbriquées » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon R Academy ?
Oui. Chaque leçon R Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Analyser du JSON avec jsonlite
- Effectuer des requêtes HTTP avec httr2
- Consommer des API REST dans R
- Gérer des structures JSON imbriquées