A legtöbb esetben, amikor az API-tól kapott válasszal, vagy bármilyen más, bonyolult fa struktúrával rendelkező adattal dolgozik, a JSON és XML formátumokkal találkozik.
Ezek a formátumok számos előnnyel rendelkeznek: a data kompakt módon tárolja az információt, és elkerüli a felesleges adatduplikációt.
E formátumok hátránya a feldolgozásuk és elemzésük nehézsége. A strukturálatlan adatok nem használhatóak számításokban, és nem lehet rájuk alapozva vizualizációt készíteni.

Ez a cikk logikai folytatása a közzétett . Segíteni fog abban, hogy a strukturálatlan adatstruktúrákat egy ismerős, analízisre alkalmas táblázatos formába hozza a tidyr, a könyvtár magjának részeként tidyverse, és annak unnest_*().
Tartalom
Ha érdeklik az adatelemzés, talán érdekesek lesznek a és csatornák. A tartalom nagyobb része R nyelvvel foglalkozik.
Bevezetés
Rectangling (a fordító megjegyzése, nem találtam megfelelő fordítást erre a kifejezésre, ezért úgy hagyjuk, ahogy van.) — a folyamat, amely a strukturálatlan, beágyazott tömbökkel rendelkező adatokat két dimenziós táblázatokká alakítja, amely ismert sorokból és oszlopokból áll. A tidyr használ több olyan funkciót, amelyek segítenek kibővíteni a beágyazott oszlop-listákat, és az adatokat téglalap alakú, táblázatos formára hozni:
unnest_longer()minden lista-oszlop elemét véve új sort hoz létre.unnest_wider()minden lista-oszlop elemét véve új oszlopot hoz létre.unnest_auto()automatikusan meghatározza, hogy melyik funkciót érdemes használni
unnest_longer()vagyunnest_wider().hoist()hasonlít aunnest_wider()de csak a megadott komponenseket választja ki, és lehetővé teszi a több szintű beágyazással való munkát.
A strukturálatlan adatok két dimenziós táblázattá alakításával kapcsolatos problémák többsége megoldható az említett funkciók és a dplyr kombinálásával.
Ezeknek a technikáknak a bemutatására a repurrrsive, amely több bonyolult, többszintű listát biztosít, amelyet web-API-ból kaptunk.
library(tidyr)
library(dplyr)
library(repurrrsive)GitHub felhasználók
Kezdjük a gh_users, egy listával, amely hat GitHub felhasználó információit tartalmazza. Először is alakítsuk át a listát gh_users be. tibble keretbe:
users <- tibble( user = gh_users ) Ez egy kicsit illogikusnak tűnik: miért készítenénk listát gh_users, egy bonyolultabb adatszerkezetről? De a data frame-nek van egy nagy előnye: több vektort egyesít, így minden egy objektumban nyomon követhető.
Minden objektumelemet Miután megállapítottuk, hogy ki küldte a kérést, meg kell határoznunk, hogy az adott alanynak mit engedélyeztek. Egyes szolgáltatásrácsok lehetővé teszik alapvető irányelvek (arról, hogy ki mit tehet) megadását YAML-fájlok formájában vagy parancssoron, míg mások integrációt kínálnak olyan keretrendszerekkel, mint az egy névvel ellátott lista képvisel, amelyben minden elem egy oszlopot képvisel.
names(users$user[[1]])
#> [1] "login" "id" "avatar_url"
#> [4] "gravatar_id" "url" "html_url"
#> [7] "followers_url" "following_url" "gists_url"
#> [10] "starred_url" "subscriptions_url" "organizations_url"
#> [13] "repos_url" "events_url" "received_events_url"
#> [16] "type" "site_admin" "name"
#> [19] "company" "blog" "location"
#> [22] "email" "hireable" "bio"
#> [25] "public_repos" "public_gists" "followers"
#> [28] "following" "created_at" "updated_at"Két mód van arra, hogy a listaelemeket oszlopokká alakítsuk. unnest_wider() azt veszi, hogy minden komponenst külön oszlopba helyez:
users %>% unnest_wider(user)
#> # A tibble: 6 x 30
#> login id avatar_url gravatar_id url html_url followers_url
#>
#> 1 gabo… 6.60e5 https://a… "" http… https:… https://api.…
#> 2 jenn… 5.99e5 https://a… "" http… https:… https://api.…
#> 3 jtle… 1.57e6 https://a… "" http… https:… https://api.…
#> 4 juli… 1.25e7 https://a… "" http… https:… https://api.…
#> 5 leep… 3.51e6 https://a… "" http… https:… https://api.…
#> 6 masa… 8.36e6 https://a… "" http… https:… https://api.…
#> # … 23 további változóval: following_url , gists_url ,
#> # starred_url , subscriptions_url , organizations_url ,
#> # repos_url , events_url , received_events_url ,
#> # type , site_admin , name , company , blog ,
#> # location , email , public_repos , public_gists ,
#> # followers , following , created_at , updated_at ,
#> # bio , hireableEbben az esetben egy 30 oszlopból álló táblázatot kaptunk, és a többségére nincs szükségünk, ezért helyette unnest_wider() használni hoist(). hoist() lehetővé teszi számunkra, hogy a kiválasztott komponenseket azonos szintaxissal nyerjük ki, mint purrr::pluck():
felhasználók %>% hoist(user,
követők = "followers",
bejelentkezés = "login",
url = "html_url"
)
#> # A tibble: 6 x 4
#> követők bejelentkezés url felhasználó
#>
#> 1 303 gaborcsardi https://github.com/gaborcsardi
#> 2 780 jennybc https://github.com/jennybc
#> 3 3958 jtleek https://github.com/jtleek
#> 4 115 juliasilge https://github.com/juliasilge
#> 5 213 leeper https://github.com/leeper
#> 6 34 masalmon https://github.com/masalmonhoist() eltávolítja a megadott névvel ellátott összetevőket a lista-oszlopból user, ezért úgy tekintheti hoist() a belső lista komponenseinek áthelyezéseként a dátakeret felső szintjére.
GitHub repozitóriumok
Lista kiegyenlítése gh_repos hasonlóan kezdünk, átalakítva tibble:
repos # A tibble: 6 x 1
#> repo
#>
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6Ezúttal az elemek user azokat a repozitóriumokat képviselik, amelyek ennek a felhasználónak a tulajdonában vannak. Minden repozitórium külön megfigyelés, így a tiszta adatok koncepciója szerint (tiszta adatok az megjegyzés) új sorokká kell válniuk, ezért használjuk unnest_longer() nem pedig unnest_wider():
repos % unnest_longer(repo)
repos
#> # A tibble: 176 x 1
#> repo
#>
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6
#> 7
#> 8
#> 9
#> 10
#> # … 166 további sorralMost már használhatjuk unnest_wider() vagy hoist() :
repos %>% hoist(repo,
bejelentkezés = c("owner", "login"),
név = "name",
honlap = "homepage",
nézők = "watchers_count"
)
#> # A tibble: 176 x 5
#> bejelentkezés név honlap nézők repo
#>
#> 1 gaborcsardi után 5
#> 2 gaborcsardi argufy 19
#> 3 gaborcsardi ask 5
#> 4 gaborcsardi baseimports 0
#> 5 gaborcsardi citest 0
#> 6 gaborcsardi clisymbols "" 18
#> 7 gaborcsardi cmaker 0
#> 8 gaborcsardi cmark 0
#> 9 gaborcsardi conditions 0
#> 10 gaborcsardi crayon 52
#> # … 166 további sorralFigyeljünk a használatra c("owner", "login"): ez lehetővé teszi számunkra, hogy elérjük a második szintű értéket a beágyazott listából tulajdonosAz alternatív megközelítés az, hogy megszerezzük az összes listát tulajdonos majd egy funkció segítségével unnest_wider() minden elemét egy oszlopba helyezzük:
repos %>%
hoist(repo, owner = "owner") %>%
unnest_wider(owner)
#> # A tibble: 176 x 18
#> login id avatar_url gravatar_id url html_url followers_url
#>
#> 1 gabo… 660288 https://a… "" http… https:… https://api.…
#> 2 gabo… 660288 https://a… "" http… https:… https://api.…
#> 3 gabo… 660288 https://a… "" http… https:… https://api.…
#> 4 gabo… 660288 https://a… "" http… https:… https://api.…
#> 5 gabo… 660288 https://a… "" http… https:… https://api.…
#> 6 gabo… 660288 https://a… "" http… https:… https://api.…
#> 7 gabo… 660288 https://a… "" http… https:… https://api.…
#> 8 gabo… 660288 https://a… "" http… https:… https://api.…
#> 9 gabo… 660288 https://a… "" http… https:… https://api.…
#> 10 gabo… 660288 https://a… "" http… https:… https://api.…
#> # … 166 további sorral, és 11 további változóval: following_url ,
#> # gists_url , starred_url , subscriptions_url ,
#> # organizations_url , repos_url , events_url ,
#> # received_events_url , type , site_admin , repoAhelyett, hogy a megfelelő funkció kiválasztásán tűnődne unnest_longer() vagy unnest_wider() használhatja unnest_auto(). Ez a funkció több heurisztikus módszert alkalmaz az adatok átalakításához legjobban megfelelő funkció kiválasztására, és üzenetet ad az alkalmazott módszerről.
tibble(repo = gh_repos) %>%
unnest_auto(repo) %>%
unnest_auto(repo)
#> Using `unnest_longer(repo)`; no element has names
#> Using `unnest_wider(repo)`; elements have 68 names in common
#> # A tibble: 176 x 67
#> id name full_name owner private html_url description fork url
#>
#> 1 6.12e7 after gaborcsa… 2 4.05e7 argu… gaborcsa… 3 3.64e7 ask gaborcsa… 4 3.49e7 base… gaborcsa… 5 6.16e7 cite… gaborcsa… 6 3.39e7 clis… gaborcsa… 7 3.72e7 cmak… gaborcsa… 8 6.80e7 cmark gaborcsa… 9 6.32e7 cond… gaborcsa… <nam… FALSE https:/… TRUE http…
#> 10 2.43e7 cray… gaborcsa… # … with 166 more rows, and 58 more variables: forks_url ,
#> # keys_url , collaborators_url , teams_url ,
#> # hooks_url , issue_events_url , events_url ,'
#> # assignees_url , branches_url , tags_url ,
#> # blobs_url , git_tags_url , git_refs_url ,
#> # trees_url , statuses_url , languages_url ,
#> # stargazers_url , contributors_url , subscribers_url ,
#> # subscription_url , commits_url , git_commits_url ,
#> # comments_url , issue_comment_url , contents_url ,
#> # compare_url , merges_url , archive_url ,
#> # downloads_url , issues_url , pulls_url ,
#> # milestones_url , notifications_url , labels_url ,
#> # releases_url , deployments_url , created_at ,
#> # updated_at , pushed_at , git_url , ssh_url ,
#> # clone_url , svn_url , size , stargazers_count ,
#> # watchers_count , language , has_issues ,
#> # has_downloads , has_wiki , has_pages ,
#> # forks_count , open_issues_count , forks ,
#> # open_issues , watchers , default_branch ,
#> # homepageTrónok harca karakterek
got_chars azonos struktúrával rendelkezik gh_users: egy nevekkel ellátott listák halmaza, ahol minden belső lista egy karakter attribútumát írja le a Trónok harcában. A táblázatos formázáshoz got_chars adatkeretet hozunk létre, akárcsak az előző példákban, majd minden elemet külön oszlopba alakítunk át:
chars # A tibble: 30 x 1
#> char
#>
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6
#> 7
#> 8
#> 9
#> 10
#> # … with 20 more rows
chars2 % unnest_wider(char)
chars2
#> # A tibble: 30 x 18
#> url id name gender culture born died alive titles aliases father
#> &
#> 1 http… 1022 Theo… Male Ironbo… In 2… "" TRUE <chr … 2 http… 1052 Tyri… Male "" In 2… "" TRUE <chr … 3 http… 1074 Vict… Male Ironbo… In 2… "" TRUE <chr … 4 http… 1109 Will Male "" "" In 2… FALSE <chr … 5 http… 1166 Areo… Male Norvos… In 2… "" TRUE <chr … 6 http… 1267 Chett Male "" At H… In 2… FALSE <chr … 7 http… 1295 Cres… Male "" In 2… In 2… FALSE <chr … 8 http… 130 Aria… Female Dornish In 2… "" TRUE <chr … 9 http… 1303 Daen… Female Valyri… In 2… "" TRUE <chr … 10 http… 1319 Davo… Male Wester… In 2… "" TRUE <chr … # … with 20 more rows, and 7 more variables: mother , spouse ,
#> # allegiances , books , povBooks , tvSeries ,
#> # playedByStruktúra got_chars kicsit bonyolultabb, mint gh_users, mivel egyes elemek a listában char önállóan listákat alkotnak, így oszlopokat kapunk — tartalmaznak listákat:
chars2 %>% select_if(is.list)
#> # A tibble: 30 x 7
#> titles aliases allegiances books povBooks tvSeries playedBy
#>
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6
#> 7
#> 8
#> 9
#> 10
#> # … with 20 more rowsA további lépései a feltárás céljaitól függenek. Lehet, hogy szüksége van arra, hogy soronként feltüntesse az információkat minden könyvről és sorozatról, amelyben a karakter szerepel:
chars2 %>%
select(name, books, tvSeries) %>%
pivot_longer(c(books, tvSeries), names_to = "media", values_to = "value") %>%
unnest_longer(value)
#> # A tibble: 180 x 3
#> name media value
#>
#> 1 Theon Greyjoy books A Trónok harca
#> 2 Theon Greyjoy books A Kardok vihara
#> 3 Theon Greyjoy books A Hollók lakomája
#> 4 Theon Greyjoy tvSeries Season 1
#> 5 Theon Greyjoy tvSeries Season 2
#> 6 Theon Greyjoy tvSeries Season 3
#> 7 Theon Greyjoy tvSeries Season 4
#> 8 Theon Greyjoy tvSeries Season 5
#> 9 Theon Greyjoy tvSeries Season 6
#> 10 Tyrion Lannister books A Hollók lakomája
#> # … 170 további sorralVagy lehet, hogy szeretne létrehozni egy táblázatot, amely lehetővé teszi a karakter és a mű párosítását:
chars2 %>%
select(name, title = titles) %>%
unnest_longer(title)
#> # A tibble: 60 x 2
#> name title
#>
#> 1 Theon Greyjoy Winterfell hercege
#> 2 Theon Greyjoy A Tenger Banya kapitánya
#> 3 Theon Greyjoy A Vasmadarak ura (a zöld földek törvénye szerint)
#> 4 Tyrion Lannister A király megbízott keze (volt)
#> 5 Tyrion Lannister A Pénzura (volt)
#> 6 Victarion Greyjoy A Vasmadarak flotta főkapitánya
#> 7 Victarion Greyjoy A Vasmadarak győzelme mestere
#> 8 Will ""
#> 9 Areo Hotah A Vigyázó kapitánya a Napgyümölcsben
#> 10 Chett ""
#> # … 50 további sorral(Vegye figyelembe, hogy a null értékek "" a mezőben title, ez a bemeneti adatok bevitele során elkövetett hibák miatt van got_chars: valójában azoknak a karaktereknek, akiknek nincs megfelelő könyv- és sorozatcímük a mezőben title nulla hosszúságú vektornak kellene lenniük, és nem egy hosszúságú 1-es vektornak, amely üres stringet tartalmaz.)
A fenti példát átkonvertálhatjuk a(z) használatával unnest_auto(). Ez a módszer kényelmes egyszeri elemzéshez, de nem érdemes rendszeresen támaszkodni rá. unnest_auto() Az a helyzet, hogy ha az adatszerkezete megváltozik, unnest_auto() meg akarja változtatni a kiválasztott adatformátum-átalakító mechanizmust; ha az eredetileg oszlop-listákat alakított át sorokká a(z) révén, unnest_longer()akkor az adatbeviteli struktúra módosítása esetén a logikát módosítani lehet a a(z)-ért, és az ilyen megközelítés tartós használata váratlan hibákhoz vezethet. unnest_wider(), és ennek a megközelítésnek a folyamatos alkalmazása váratlan hibákhoz vezethet.
tibble(char = got_chars) %>%
unnest_auto(char) %>%
select(name, title = titles) %>%
unnest_auto(title)
#> Az `unnest_wider(char)` használatával; az elemeknek 18 közös neve van
#> Az `unnest_longer(title)` használatával; egyetlen elemnek sincs neve
#> # A tibble: 60 x 2
#> name title
#>
#> 1 Theon Greyjoy Winterfell hercege
#> 2 Theon Greyjoy Sea Bitch kapitánya
#> 3 Theon Greyjoy A Vas-szigetek ura (a zöld földek törvénye szerint)
#> 4 Tyrion Lannister A király megbízott keze (korábban)
#> 5 Tyrion Lannister Pénzügyminiszter (korábban)
#> 6 Victarion Greyjoy A Vaskoszorú lordkapitánya
#> 7 Victarion Greyjoy A Vas-győzelem mestere
#> 8 Will ""
#> 9 Areo Hotah A napsugár őrség kapitánya
#> 10 Chett ""
#> # … 50 további sorralGeokódolás a Google segítségével
Most egy bonyolultabb adatstruktúrát fogunk megvizsgálni, amelyet a Google geokódoló szolgáltatásától kapunk. Az API Google térképekkel való használatának feltételeivel ellentétes az adatok gyorsítótárazása, ezért először írok egy egyszerű API-környezetet. Amely az API Google térképekkel való használatához szükséges kulcs környezeti változóban való tárolásán alapul; ha a környezeti változók között nincs mentett kulcs az API Google térképekhez, akkor az ebben a szakaszban bemutatott kódok nem fognak működni.
has_key <- !identical(Sys.getenv("GOOGLE_MAPS_API_KEY"), "")
if (!has_key) {
message("Nincs Google Maps API kulcs; a kódrészletek nem fognak lefutni")
}
# https://developers.google.com/maps/documentation/geocoding
geocode <- function(address, api_key = Sys.getenv("GOOGLE_MAPS_API_KEY")) {
url <- "https://maps.googleapis.com/maps/api/geocode/json"
url <- paste0(url, "?address=", URLencode(address), "&key=", api_key)
jsonlite::read_json(url)
}Ez a funkció egy meglehetősen bonyolult listát ad vissza:
houston List of 2
#> $ results:List of 1
#> ..$ :List of 5
#> .. ..$ address_components:List of 4
#> .. .. ..$ :List of 3
#> .. .. .. ..$ long_name : chr "Houston"
#> .. .. .. ..$ short_name: chr "Houston"
#> .. .. .. ..$ types :List of 2
#> .. .. .. .. ..$ : chr "locality"
#> .. .. .. .. ..$ : chr "political"
#> .. .. ..$ :List of 3
#> .. .. .. ..$ long_name : chr "Harris County"
#> .. .. .. ..$ short_name: chr "Harris County"
#> .. .. .. ..$ types :List of 2
#> .. .. .. .. ..$ : chr "administrative_area_level_2"
#> .. .. .. .. ..$ : chr "political"
#> .. .. ..$ :List of 3
#> .. .. .. ..$ long_name : chr "Texas"
#> .. .. .. ..$ short_name: chr "TX"
#> .. .. .. ..$ types :List of 2
#> .. .. .. .. ..$ : chr "administrative_area_level_1"
#> .. .. .. .. ..$ : chr "political"
#> .. .. ..$ :List of 3
#> .. .. .. ..$ long_name : chr "Egyesült Államok"
#> .. .. .. ..$ short_name: chr "US"
#> .. .. .. ..$ types :List of 2
#> .. .. .. .. ..$ : chr "country"
#> .. .. .. .. ..$ : chr "political"
#> .. ..$ formatted_address : chr "Houston, TX, USA"
#> .. ..$ geometry :List of 4
#> .. .. ..$ bounds :List of 2
#> .. .. .. ..$ northeast:List of 2
#> .. .. .. .. ..$ lat: num 30.1
#> .. .. .. .. ..$ lng: num -95
#> .. .. .. ..$ southwest:List of 2
#> .. .. .. .. ..$ lat: num 29.5
#> .. .. .. .. ..$ lng: num -95.8
#> .. .. ..$ location :List of 2
#> .. .. .. ..$ lat: num 29.8
#> .. .. .. ..$ lng: num -95.4
#> .. .. ..$ location_type: chr "APPROXIMATE"
#> .. .. ..$ viewport :List of 2
#> .. .. .. ..$ northeast:List of 2
#> .. .. .. .. ..$ lat: num 30.1
#> .. .. .. .. ..$ lng: num -95
#> .. .. .. ..$ southwest:List of 2
#> .. .. .. .. ..$ lat: num 29.5
#> .. .. .. .. ..$ lng: num -95.8
#> .. ..$ place_id : chr "ChIJAYWNSLS4QIYROwVl894CDco"
#> .. ..$ types :List of 2
#> .. .. ..$ : chr "locality"
#> .. .. ..$ : chr "political"
#> $ status : chr "OK"Szerencsére lépésről lépésre meg tudjuk oldani az adatok táblázatos formátumba történő átalakításának problémáját a funkciók segítségével. tidyr. Hogy a feladat egy kicsit nehezebb és valósághűbb legyen, elkezdem néhány város geokódolásával:
city <- c ( "Houston" , "LA" , "New York" , "Chicago" , "Springfield" ) city_geo <- purrr::map (city, geocode) Az eredményeket átalakítom tibble, a kényelem kedvéért hozzáadok egy városnevének megfelelő oszlopot.
loc # A tibble: 5 x 2
#> city json
#>
#> 1 Houston
#> 2 LA
#> 3 New York
#> 4 Chicago
#> 5 SpringfieldAz első szint tartalmazza az összetevőket status és eredmény, amelyeket a következő módon bontogathatunk ki unnest_wider() :
loc %>%
unnest_wider(json)
#> # A tibble: 5 x 3
#> city results status
#>
#> 1 Houston OK
#> 2 LA OK
#> 3 New York OK
#> 4 Chicago OK
#> 5 Springfield OKp(x) – results többszintű lista. A legtöbb városnak 1 eleme van (ami egyedi értéket képvisel, amely a geokódoló API-hoz tartozik), de Springfieldnek kettő van. Ezeket külön sorokba tudjuk húzni a unnest_longer() :
loc %>%
unnest_wider(json) %>%
unnest_longer(results)
#> # A tibble: 5 x 3
#> city results status
#>
#> 1 Houston OK
#> 2 LA OK
#> 3 New York OK
#> 4 Chicago OK
#> 5 Springfield OKMost már mindegyiknek azonos összetevői vannak, amit akár a következővel is ellenőrizhetünk unnest_wider():
loc %>%
unnest_wider(json) %>%
unnest_longer(results) %>%
unnest_wider(results)
#> # A tibble: 5 x 7
#> city address_componen… formatted_addre… geometry place_id types status
#>
#> 1 Houst… Houston, TX, USA <named … ChIJAYWN… OK
#> 2 LA Los Angeles, CA… <named … ChIJE9on… OK
#> 3 New Y… New York, NY, U… <named … ChIJOwg_… OK
#> 4 Chica… Chicago, IL, USA <named … ChIJ7cv0… OK
#> 5 Sprin… Springfield, MO… <named … ChIJP5jI… OKMeg tudjuk találni minden város szélességi és hosszúsági koordinátáit a lista kibővítésével geometry:
loc %>%
unnest_wider(json) %>%
unnest_longer(results) %>%
unnest_wider(results) %>%
unnest_wider(geometry)
#> # A tibble: 5 x 10
#> city address_compone… formatted_addre… bounds location location_type
#>
#> 1 Hous… Houston, TX, USA <name… 2 LA Los Angeles, CA… <name… 3 New … New York, NY, U… <name… 4 Chic… Chicago, IL, USA <name… 5 Spri… Springfield, MO… <name… # … 4 további változóval: viewport , place_id , types ,
#> # statusAztán a helymeghatározás, amihez szét kell bontani location:
loc %>%
unnest_wider(json) %>%
unnest_longer(results) %>%
unnest_wider(results) %>%
unnest_wider(geometry) %>%
unnest_wider(location)
#> # A tibble: 5 x 11
#> city address_compone… formatted_addre… bounds lat lng location_type
#>
#> 1 Hous… Houston, TX, USA 2 LA Los Angeles, CA… 3 New … New York, NY, U… 4 Chic… Chicago, IL, USA 5 Spri… Springfield, MO… # … with 4 more variables: viewport , place_id , types ,
#> # statusIsmét, unnest_auto() egyszerűsíti a leírt műveletet bizonyos kockázatokkal, amelyeket a bejövő adatok struktúrájának megváltozása okozhat:
loc %>%
unnest_auto(json) %>%
unnest_auto(results) %>%
unnest_auto(results) %>%
unnest_auto(geometry) %>%
unnest_auto(location)
#> Using `unnest_wider(json)`; elements have 2 names in common
#> Using `unnest_longer(results)`; no element has names
#> Using `unnest_wider(results)`; elements have 5 names in common
#> Using `unnest_wider(geometry)`; elements have 4 names in common
#> Using `unnest_wider(location)`; elements have 2 names in common
#> # A tibble: 5 x 11
#> city address_compone… formatted_addre… bounds lat lng location_type
#>
#> 1 Hous… Houston, TX, USA 2 LA Los Angeles, CA… 3 New … New York, NY, U… 4 Chic… Chicago, IL, USA 5 Spri… Springfield, MO… # … with 4 more variables: viewport , place_id , types ,
#> # statusEsetleg egyszerűen nézhetjük meg az első címet minden városra:
loc %>%
unnest_wider(json) %>%
hoist(results, first_result = 1) %>%
unnest_wider(first_result) %>%
unnest_wider(geometry) %>%
unnest_wider(location)
#> # A tibble: 5 x 11
#> city address_compone… formatted_addre… bounds lat lng location_type
#>
#> 1 Hous… Houston, TX, USA 2 LA Los Angeles, CA… 3 New … New York, NY, U… 4 Chic… Chicago, IL, USA 5 Spri… Springfield, MO… # … with 4 more variables: viewport , place_id , types ,
#> # statusVagy használható hoist() többszintű megközelítésként, hogy közvetlenül a következőhöz jussunk lat és lng.
loc %>%
hoist(json,
lat = list("results", 1, "geometry", "location", "lat"),
lng = list("results", 1, "geometry", "location", "lng")
)
#> # A tibble: 5 x 4
#> city lat lng json
#>
#> 1 Houston 29.8 -95.4
#> 2 LA 34.1 -118.
#> 3 New York 40.7 -74.0
#> 4 Chicago 41.9 -87.6
#> 5 Springfield 37.2 -93.3Scharla Gelfand diszkográfiája
A végén a legbonyolultabb struktúrát fogjuk megvizsgálni — Sharla Gelfand diszkográfiáját. Ahogy a korábban említett példákban, a lista egy oszlopos adatkeretbe való konvertálásával kezdjük, majd bővítjük azt, hogy minden komponens külön oszlop legyen. Azt is átalakítom, hogy az oszlop date_added a megfelelő dátum- és időformátumra kerüljön R-ben.
discs %
unnest_wider(disc) %>%
mutate(date_added = as.POSIXct(strptime(date_added, "%Y-%m-%dT%H:%M:%S")))
discs
#> # A tibble: 155 x 5
#> instance_id date_added basic_information id rating
#>
#> 1 354823933 2019-02-16 17:48:59 7496378 0
#> 2 354092601 2019-02-13 14:13:11 4490852 0
#> 3 354091476 2019-02-13 14:07:23 9827276 0
#> 4 351244906 2019-02-02 11:39:58 9769203 0
#> 5 351244801 2019-02-02 11:39:37 7237138 0
#> 6 351052065 2019-02-01 20:40:53 13117042 0
#> 7 350315345 2019-01-29 15:48:37 7113575 0
#> 8 350315103 2019-01-29 15:47:22 10540713 0
#> 9 350314507 2019-01-29 15:44:08 11260950 0
#> 10 350314047 2019-01-29 15:41:35 11726853 0
#> # … with 145 more rowsEzen a szinten megtudtuk, mikor adták hozzá az egyes lemezeket Sharla diszkográfiájához, de az egyes lemezek adatai nem láthatók. Ehhez ki kell bővítenünk az oszlopot basic_information:
discs %>% unnest_wider(basic_information)
#> A `id` oszlop nevét nem lehet megismételni.
#> Használja a .name_repair-t a javításhoz.Sajnos hibát fogunk kapni, mivel a listában basic_information van egy azonos nevű oszlop basic_information. Ilyen hiba esetén a probléma gyors meghatározásához használhatja names_repair = "unique":
lemezek %>% unnest_wider(basic_information, names_repair = "unique")
#> Új nevek:
#> * id -> id...6
#> * id -> id...14
#> # A tibble: 155 x 15
#> instance_id date_added labels year artists id...6 thumb title
#>
#> 1 354823933 2019-02-16 17:48:59 <list… 2015 2 354092601 2019-02-13 14:13:11 <list… 2013 3 354091476 2019-02-13 14:07:23 <list… 2017 4 351244906 2019-02-02 11:39:58 <list… 2017 5 351244801 2019-02-02 11:39:37 <list… 2015 6 351052065 2019-02-01 20:40:53 <list… 2019 7 350315345 2019-01-29 15:48:37 <list… 2014 8 350315103 2019-01-29 15:47:22 <list… 2015 9 350314507 2019-01-29 15:44:08 <list… 2017 10 350314047 2019-01-29 15:41:35 <list… 2017 # … összesen 145 egyéb sor, és 7 további változó: formats ,
#> # cover_image , resource_url , master_id ,
#> # master_url , id...14 , ratingA probléma az, hogy basic_information ismétli az id oszlopot, amely szintén a legfelső szinten tárolódik, ezért egyszerűen eltávolíthatjuk:
lemezek %>%
select(-id) %>%
unnest_wider(basic_information)
#> # A tibble: 155 x 14
#> instance_id date_added labels year artists id thumb title
#>
#> 1 354823933 2019-02-16 17:48:59 <list… 2015 2 354092601 2019-02-13 14:13:11 <list… 2013 3 354091476 2019-02-13 14:07:23 <list… 2017 4 351244906 2019-02-02 11:39:58 <list… 2017 5 351244801 2019-02-02 11:39:37 <list… 2015 6 351052065 2019-02-01 20:40:53 <list… 2019 7 350315345 2019-01-29 15:48:37 <list… 2014 8 350315103 2019-01-29 15:47:22 <list… 2015 9 350314507 2019-01-29 15:44:08 <list… 2017 10 350314047 2019-01-29 15:41:35 <list… 2017 # … összesen 145 egyéb sor, és 6 további változó: formats ,
#> # cover_image , resource_url , master_id ,
#> # master_url , ratingAlternatív megoldásként használhatnánk hoist():
deszkák %>%
hoist(basic_information,
title = "title",
year = "year",
label = list("labels", 1, "name"),
artist = list("artists", 1, "name")
)
#># A tibble: 155 x 9
#># instance_id date_added title year label artist
#>
#> 1 354823933 2019-02-16 17:48:59 Demo 2015 Tobi… Mollot
#> 2 354092601 2019-02-13 14:13:11 Obse… 2013 La V… Una B…
#> 3 354091476 2019-02-13 14:07:23 I 2017 La V… S.H.I…
#> 4 351244906 2019-02-02 11:39:58 Oído… 2017 La V… Rata …
#> 5 351244801 2019-02-02 11:39:37 A Ca… 2015 Kato… Ivy (…
#> 6 351052065 2019-02-01 20:40:53 Tash… 2019 High… Tashme
#> 7 350315345 2019-01-29 15:48:37 Demo 2014 Mind… Desgr…
#> 8 350315103 2019-01-29 15:47:22 Let … 2015 Not … Phant…
#> 9 350314507 2019-01-29 15:44:08 Sub … 2017 Not … Sub S…
#> 10 350314047 2019-01-29 15:41:35 Demo 2017 Pres… Small…
#> # … 145 további sorral és 3 további változóval: basic_information ,
#> # id , értékelésItt gyorsan kiemelem az első címke és művész nevét az index alapján, belemerülve a beágyazott listába.
A célravezetőbb megközelítés az, ha külön táblázatokat hozunk létre a művészek és a címkék számára:
deszkák %>%
hoist(basic_information, artist = "artists") %>%
select(disc_id = id, artist) %>%
unnest_longer(artist) %>%
unnest_wider(artist)
#># A tibble: 167 x 8
#> disc_id join name anv tracks role resource_url id
#>
#> 1 7496378 "" Mollot "" "" "" https://api.discog… 4.62e6
#> 2 4490852 "" Una Bèstia… "" "" "" https://api.discog… 3.19e6
#> 3 9827276 "" S.H.I.T. (… "" "" "" https://api.discog… 2.77e6
#> 4 9769203 "" Rata Negra "" "" "" https://api.discog… 4.28e6
#> 5 7237138 "" Ivy (18) "" "" "" https://api.discog… 3.60e6
#> 6 13117042 "" Tashme "" "" "" https://api.discog… 5.21e6
#> 7 7113575 "" Desgraciad… "" "" "" https://api.discog… 4.45e6
#> 8 10540713 "" Phantom He… "" "" "" https://api.discog… 4.27e6
#> 9 11260950 "" Sub Space … "" "" "" https://api.discog… 5.69e6
#> 10 11726853 "" Small Man … "" "" "" https://api.discog… 6.37e6
#> # … 157 további sorral
deszkák %>%
hoist(basic_information, format = "formats") %>%
select(disc_id = id, format) %>%
unnest_longer(format) %>%
unnest_wider(format) %>%
unnest_longer(descriptions)
#># A tibble: 280 x 5
#> disc_id descriptions text name qty
#>
#> 1 7496378 Számozott Fekete kazetta 1
#> 2 4490852 LP Vinyl 1
#> 3 9827276 "7"" Vinyl 1
#> 4 9827276 45 RPM Vinyl 1
#> 5 9827276 EP Vinyl 1
#> 6 9769203 LP Vinyl 1
#> 7 9769203 Album Vinyl 1
#> 8 7237138 "7"" Vinyl 1
#> 9 7237138 45 RPM Vinyl 1
#> 10 13117042 "7"" Vinyl 1
#> # … 270 további sorralEzután szükség szerint visszaillesztheti őket az eredeti adatgyűjteménybe.
Zárás
A könyvtár magjában tidyverse számos hasznos csomag található, amelyek közös adatfeldolgozási filozófiával rendelkeznek.
Ebben a cikkben a funkciók családját vizsgáltuk meg unnest_*(), amelyek a beágyazott listákból történő elemek kinyerésére összpontosítanak. Ez a csomag számos más hasznos funkciót tartalmaz, amelyek megkönnyítik az adatok átalakítását a Tiszta Adatok.
Forrás: habr.com
