Në shumicën e rasteve, kur punoni me përgjigjjen e marrë nga API, ose me çdo të dhënë tjetër që ka një strukturë të ndërlikuar, përballeni me formatet JSON dhe XML.
Këto formate kanë shumë përfitime: ato ruajnë të dhënat në mënyrë të kompaktë dhe lejojnë evitimin e dyfishimeve të panevojshme të informacionit.
Këto formate kanë një mangësi: ndërlikueshmëria e përpunimit dhe analizës. Të dhënat e pa strukturuara nuk mund të përdoren në llogaritje dhe nuk mund të krijohen vizualizime mbi to.

Ky artikull është një vazhdim logjik i publikimit . Ai do t'ju ndihmojë të sillni struktura të pa strukturuara të të dhënave në një format tabelar të njohur dhe të përshtatshëm për analizë me ndihmën e paketës tidyr, e cila është pjesë e bërthamës së bibliotekës tidyverse, dhe funksioneve të familjes së saj unnest_*().
Përmbajtja
Nëse jeni të interesuar për analizën e të dhënave, ndoshta do t'ju interesojnë kanalet e mia dhe në të cilat shumica e përmbajtjes është e kushtuar gjuhës R.
Hyrje
Rectangling (shënim i përkthyesit, nuk kam gjetur variante të përshtatshme për përkthimin e këtij termi, prandaj do ta lëmë ashtu siç është.) — është procesi i shndërrimit të të dhënave të pa strukturuara me struktura të thella në një tabelë dy-dimensionale, e cila përbëhet nga rreshta dhe kolona të njohura për ne. tidyr Ekzistojnë disa funksione që do t'ju ndihmojnë të zgjidhni kolona-lista të thella dhe të sillni të dhënat në një format tabelar:
unnest_longer()merr çdo element të listës-kolonë dhe krijon një rresht të ri.unnest_wider()merr çdo element të listës-kolonë dhe krijon një kolonë të re.unnest_auto()automatikisht përcakton se cila nga funksionet është më e përshtatshme për të përdorur
unnest_longer()oseunnest_wider().hoist()është i ngjashëm meunnest_wider()por seleksionon vetëm komponentët e specifikuar dhe lejon punimin me disa nivele të thellësisë.
Shumica e problemeve të lidhura me shndërrimin e të dhënave të pa strukturuara me disa nivele thellësie në një tabelë dy-dimensionale mund të zgjidhen duke kombinuar funksionet e përmendura me dplyr.
Për të demonstruar këto teknika, ne do të përdorim paketën repurrrsive, e cila ofron disa lista komplekse shumë-nivel, të marra nga API-të e webit.
library(tidyr)
library(dplyr)
library(repurrrsive)Përdoruesit e GitHub
Le të fillojmë me gh_users, një listë që përmban informacion rreth gjashtë përdoruesve të GitHub. Fillimisht, le të zbulojmë listën gh_users në tibble DataFrame:
users <- tibble( user = gh_users ) Kjo duket paksa e çuditshme: pse t'i shndërrojmë listën gh_users, në një strukturë më të ndërlikuar të të dhënave? Por DataFrame ka një avantazh të madh: ai bashkon disa vektora, kështu që gjithçka ndahet në një objekt.
Çdo element i objektit përdoruesit është një listë e emëruar, ku çdo element përfaqëson një kolonë.
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"Ka dy mënyra për të shndërruar komponentët e listës në kolona. unnest_wider() merr çdo komponent dhe krijon një kolonë të re:
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.…
#> # … me 23 variabla të tjera: 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 , hireableNë këtë rast, ne morëm një tabelë me 30 kolona, dhe shumica e tyre nuk do të na duhen, prandaj mund të përdorim në vend të unnest_wider() përdorimi hoist(). hoist() na lejon të nxjerrim komponentët e zgjedhur, duke përdorur të njëjtin sintaksë si purrr::pluck():
përdoruesit %>% hoist(user,
followers = "followers",
login = "login",
url = "html_url"
)
#> # Një tibble: 6 x 4
#> followers login url user
#> <int> <chr> <chr> <list>
#> 1 303 gaborcsardi https://github.com/gaborcsardi <named list [27]>
#> 2 780 jennybc https://github.com/jennybc <named list [27]>
#> 3 3958 jtleek https://github.com/jtleek <named list [27]>
#> 4 115 juliasilge https://github.com/juliasilge <named list [27]>
#> 5 213 leeper https://github.com/leeper <named list [27]>
#> 6 34 masalmon https://github.com/masalmon <named list [27]>hoist() heq komponentet e emëruara të caktuara nga lista-kolonë përdorues, kështu që mund ta mendoni hoist() si një lëvizje e komponentëve nga lista e brendshme e kuadrit të të dhënave në nivelin e tij më të lartë.
Repozita Github
Rreshtimi i listës gh_repos fillojmë ngjashëm, duke e transformuar atë në tibble:
repos <- tibble(repo = gh_repos)
repos
#> # Një tibble: 6 x 1
#> repo
#> <list>
#> 1 <list [30]>
#> 2 <list [30]>
#> 3 <list [30]>
#> 4 <list [26]>
#> 5 <list [30]>
#> 6 <list [30]>Këtë herë elementet përdorues përbëjnë një listë reposiresh, që i takojnë këtij përdoruesi. Çdo repo është një vëzhgim i veçantë, kështu që sipas konceptit të të dhënave të pastra (shën. tidy data) ata duhet të bëhen rreshta të rinj, ndaj ne e përdorim unnest_longer() në vend të unnest_wider():
repos <- repos %>% unnest_longer(repo)
repos
#> # Një tibble: 176 x 1
#> repo
#> <list>
#> 1 <named list [68]>
#> 2 <named list [68]>
#> 3 <named list [68]>
#> 4 <named list [68]>
#> 5 <named list [68]>
#> 6 <named list [68]>
#> 7 <named list [68]>
#> 8 <named list [68]>
#> 9 <named list [68]>
#> 10 <named list [68]>
#> # … me 166 rreshta të tjerëTani mund të përdorim unnest_wider() ose hoist() :
repos %>% hoist(repo,
login = c("owner", "login"),
name = "name",
homepage = "homepage",
watchers = "watchers_count"
)
#> # Një tibble: 176 x 5
#> login name homepage watchers repo
#> <chr> <chr> <chr> <int> <list>
#> 1 gaborcsardi after <NA> 5 <named list [65]>
#> 2 gaborcsardi argufy <NA> 19 <named list [65]>
#> 3 gaborcsardi ask <NA> 5 <named list [65]>
#> 4 gaborcsardi baseimports <NA> 0 <named list [65]>
#> 5 gaborcsardi citest <NA> 0 <named list [65]>
#> 6 gaborcsardi clisymbols "" 18 <named list [65]>
#> 7 gaborcsardi cmaker <NA> 0 <named list [65]>
#> 8 gaborcsardi cmark <NA> 0 <named list [65]>
#> 9 gaborcsardi conditions <NA> 0 <named list [65]>
#> 10 gaborcsardi crayon <NA> 52 <named list [65]>
#> # … me 166 rreshta të tjerëKujdesi me përdorimin e c("owner", "login"): kjo na lejon të marrim vlerën e nivelit të dytë nga lista e zhvendosur owner. Një qasje alternative është të marrim të gjithë listën owner dhe pastaj me anë të funksionit unnest_wider() të vendosim çdo element të saj në një kolonë:
repos %>%
hoist(repo, owner = "owner") %>%
unnest_wider(owner)
#> # Një tibble: 176 x 18
#> login id avatar_url gravatar_id url html_url followers_url
#> <chr> <int> <chr> <chr> <chr> <chr> <chr>
#> 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.…
#> # … me 166 rreshta të tjerë, dhe 11 variabla të tjerë: following_url <chr>,
#> # gists_url <chr>, starred_url <chr>, subscriptions_url <chr>,
#> # organizations_url <chr>, repos_url <chr>, events_url <chr>,
#> # received_events_url <chr>, type <chr>, site_admin <lgl>, repo <list>Në vend që të mendojmë për zgjedhjen e funksionit të duhur unnest_longer() ose unnest_wider() mund të përdorim unnest_auto(). Ky funksion përdor disa metoda heuristike për të vendosur funksionin më të përshtatshëm për transformimin e të dhënave dhe tregon një mesazh mbi mënyrën e zgjedhjes.
tibble(repo = gh_repos) %>%
unnest_auto(repo) %>%
unnest_auto(repo)
#> Përdorimi i `unnest_longer(repo)`; asnjë element nuk ka emra
#> Përdorimi i `unnest_wider(repo)`; elementët kanë 68 emra të zakonshëm
#> # Një 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… # … me 166 rreshta të tjerë, dhe 58 variabla të tjerë: 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 ,
#> # homepagePersonazhet elojës së fronave
got_chars ka një strukturë identike me gh_users: kjo është një shumësi listash të emëruara, ku çdo element i listës së brendshme përshkruan ndonjë atribut të karaktereve të Game of Thrones. Shndërrimi got_chars në format tabelar fillon me krijimin e një dataframe, ashtu si në shembujt e mëparshëm, e pastaj do ta konvertojmë çdo element në një kolonë të veçantë:
chars # Një tibble: 30 x 1
#> char
#>
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6
#> 7
#> 8
#> 9
#> 10
#> # … me 20 rreshta të tjerë
chars2 % unnest_wider(char)
chars2
#> # Një tibble: 30 x 18
#> url id name gender culture born died alive titles aliases father
#>
#> 1 http… 1022 Theo… Male Ironbo… Në 2… "" TRUE <chr … 2 http… 1052 Tyri… Male "" Në 2… "" TRUE <chr … 3 http… 1074 Vict… Male Ironbo… Në 2… "" TRUE <chr … 4 http… 1109 Will Male "" "" Në 2… FALSE <chr … 5 http… 1166 Areo… Male Norvos… Në 2… "" TRUE <chr … 6 http… 1267 Chett Male "" Në H… Në 2… FALSE <chr … 7 http… 1295 Cres… Male "" Në 2… Në 2… FALSE <chr … 8 http… 130 Aria… Female Dornish Në 2… "" TRUE <chr … 9 http… 1303 Daen… Female Valyri… Në 2… "" TRUE <chr … 10 http… 1319 Davo… Male Wester… Në 2… "" TRUE <chr … # … me 20 rreshta të tjerë, dhe 7 variabla të tjerë: mother , spouse ,
#> # allegiances , books , povBooks , tvSeries ,
#> # playedByStruktura got_chars pak më të ndërlikuar se gh_users, sepse disa komponente të listës char në vetvete janë lista, si rezultat ne marrim kolona – lista:
chars2 %>% select_if(is.list)
#> # Një tibble: 30 x 7
#> titles aliases allegiances books povBooks tvSeries playedBy
#>
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6
#> 7
#> 8
#> 9
#> 10
#> # … me 20 rreshta të tjerëVeprimet tuaja të ardhshme varen nga objektivat e analizës. Mund të jetë e nevojshme të vendosni informacion për çdo libër dhe serial ku shfaqet personazhi:
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 Game of Thrones
#> 2 Theon Greyjoy books A Storm of Swords
#> 3 Theon Greyjoy books A Feast for Crows
#> 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 Feast for Crows
#> # … with 170 more rowsOse, ndoshta dëshironi të krijoni një tabelë që do t'ju lejojë të lidheni personazhin me veprën:
chars2 %>%
select(name, title = titles) %>%
unnest_longer(title)
#> # A tibble: 60 x 2
#> name title
#>
#> 1 Theon Greyjoy Prince of Winterfell
#> 2 Theon Greyjoy Captain of Sea Bitch
#> 3 Theon Greyjoy Lord of the Iron Islands (by law of the green lands)
#> 4 Tyrion Lannister Acting Hand of the King (former)
#> 5 Tyrion Lannister Master of Coin (former)
#> 6 Victarion Greyjoy Lord Captain of the Iron Fleet
#> 7 Victarion Greyjoy Master of the Iron Victory
#> 8 Will ""
#> 9 Areo Hotah Captain of the Guard at Sunspear
#> 10 Chett ""
#> # … with 50 more rows(Vini re se vlerat bosh, "" në fushën title, kjo lidhet me gabimet e bëra gjatë futur të dhënave në got_chars: në të vërtetë personazhet për të cilët nuk ka tituj përkatës në fushën title duhet të kenë një vektor me gjatësi 0, jo një vektor me gjatësi 1 që përmban një varg të bardhë.)
Mund të rishtyjmë shembullin e mëposhtëm duke përdorur funksionin unnest_auto(). Ky qasje është e përshtatshme për një analizë sporadike, por nuk duhen mbështetur në unnest_auto() për përdorim të rregullt. Problemi është se nëse struktura juaj e të dhënave ndryshon unnest_auto() mund të ndrojë mekanizmin e zgjedhur të transformimit të të dhënave, nëse fillimisht ai shndërronte kolonat-liste në rreshta duke përdorur unnest_longer(), atëherë me ndryshimin e strukturës së të dhënave hyrëse logjika mund të ndryshojë në dobi të unnest_wider(), dhe përdorimi i një qasje të tillë në baza të vazhdueshme mund të çojë në gabime të papritura.
tibble(char = got_chars) %>%
unnest_auto(char) %>%
select(name, title = titles) %>%
unnest_auto(title)
#> Using `unnest_wider(char)`; elements have 18 names in common
#> Using `unnest_longer(title)`; no element has names
#> # A tibble: 60 x 2
#> name title
#>
#> 1 Theon Greyjoy Prince of Winterfell
#> 2 Theon Greyjoy Captain of Sea Bitch
#> 3 Theon Greyjoy Lord of the Iron Islands (by law of the green lands)
#> 4 Tyrion Lannister Acting Hand of the King (former)
#> 5 Tyrion Lannister Master of Coin (former)
#> 6 Victarion Greyjoy Lord Captain of the Iron Fleet
#> 7 Victarion Greyjoy Master of the Iron Victory
#> 8 Will ""
#> 9 Areo Hotah Captain of the Guard at Sunspear
#> 10 Chett ""
#> # … with 50 more rowsGjeokodimi me ndihmën e Google
Më pas, ne do të shqyrtojmë një strukturë më të komplikuar të të dhënave që vijnë nga shërbimi i gjeokodimit të Google. Ruajtja e akreditimeve është në kundërshtim me kushtet e përdorimit të API të Google Maps, prandaj fillimisht do të shkruaj një mbështetje të thjeshtë për API-në. E cila bazohet në ruajtjen e çelësit API të Google Maps në një variabël mjedisor; nëse në variablat mjedisorë nuk keni ruajtur një çelës për përdorim me API-në e Google Maps, fragmentet e kodit të paraqitura në këtë seksion nuk do të ekzekutohen.
has_key <- !identical(Sys.getenv("GOOGLE_MAPS_API_KEY"), "")
if (!has_key) {
message("No Google Maps API key found; code chunks will not be run")
}
# 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)
}Lista që kthehet nga kjo funksion është mjaft komplekse:
houston <- geocode("Houston TX")
str(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 "United States"
#> .. .. .. ..$ 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"К счастью, мы можем пошагово решить проблему преобразования этих данных в табличный вид с помощью функций tidyr. Чтобы сделать задачу немного сложнее и реалистичнее, я начну с геокодирования нескольких городов:
city <- c ( "Houston" , "LA" , "New York" , "Chicago" , "Springfield" ) city_geo <- purrr::map (city, geocode) Полученный результат я преобразую в tibble, для удобства добавлю столбец с соответствующим названием города.
loc <- tibble(city = city, json = city_geo)
loc
#> # A tibble: 5 x 2
#> city json
#> <chr> <list>
#> 1 Houston <named list [2]>
#> 2 LA <named list [2]>
#> 3 New York <named list [2]>
#> 4 Chicago <named list [2]>
#> 5 Springfield <named list [2]>Первый уровень содержит компоненты status dhe result, который мы можем развернуть с помощью unnest_wider() :
loc %>%
unnest_wider(json)
#> # A tibble: 5 x 3
#> city results status
#> <chr> <list> <chr>
#> 1 Houston <list [1]> OK
#> 2 LA <list [1]> OK
#> 3 New York <list [1]> OK
#> 4 Chicago <list [1]> OK
#> 5 Springfield <list [1]> OKMerrni parasysh se results является многоуровневым списком. У большинства городов есть 1 элемент (представляющий уникальное значение, соответствующее API геокодирования), но у Спрингфилда их два. Мы можем вытащить их в отдельные строки с помощью unnest_longer() :
loc %>%
unnest_wider(json) %>%
unnest_longer(results)
#> # A tibble: 5 x 3
#> city results status
#> <chr> <list> <chr>
#> 1 Houston <named list [5]> OK
#> 2 LA <named list [5]> OK
#> 3 New York <named list [5]> OK
#> 4 Chicago <named list [5]> OK
#> 5 Springfield <named list [5]> OKТеперь все они имеют одинаковые компоненты, в чём можно убедиться с помощью 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
#> <chr> <list> <chr> <list> <chr> <lis> <chr>
#> 1 Houst… <list [4]> Houston, TX, USA <named … ChIJAYWN… <lis… OK
#> 2 LA <list [4]> Los Angeles, CA… <named … ChIJE9on… <lis… OK
#> 3 New Y… <list [3]> New York, NY, U… <named … ChIJOwg_… <lis… OK
#> 4 Chica… <list [4]> Chicago, IL, USA <named … ChIJ7cv0… <lis… OK
#> 5 Sprin… <list [5]> Springfield, MO… <named … ChIJP5jI… <lis… OKМы можем найти координаты широты и долготы каждого города развернув список 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
#> <chr> <list> <chr> <list> <list> <chr>
#> 1 Hous… <list [4]> Houston, TX, USA <name… <named … APPROXIMATE
#> 2 LA <list [4]> Los Angeles, CA… <name… <named … APPROXIMATE
#> 3 New … <list [3]> New York, NY, U… <name… <named … APPROXIMATE
#> 4 Chic… <list [4]> Chicago, IL, USA <name… <named … APPROXIMATE
#> 5 Spri… <list [5]> Springfield, MO… <name… <named … APPROXIMATE
#> # … with 4 more variables: viewport <list>, place_id <chr>, types <list>,
#> # status <chr>А затем местоположение, для чего требуется развернуть lokacionin:
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
#> <chr> <list> <chr> <list> <dbl> <dbl> <chr>
#> 1 Hous… <list [4]> Houston, TX, USA <name… 29.8 -95.4 APPROXIMATE
#> 2 LA <list [4]> Los Angeles, CA… <name… 34.1 -118. APPROXIMATE
#> 3 New … <list [3]> New York, NY, U… <name… 40.7 -74.0 APPROXIMATE
#> 4 Chic… <list [4]> Chicago, IL, USA <name… 41.9 -87.6 APPROXIMATE
#> 5 Spri… <list [5]> Springfield, MO… <name… 37.2 -93.3 APPROXIMATE
#> # … with 4 more variables: viewport <list>, place_id <chr>, types <list>,
#> # status <chr>Опять же, unnest_auto() shinjon i përshkruar me disa rreziqe që mund të shkaktohen nga ndryshimi i strukturës së të dhënave të hyra;
loc %>%
unnest_auto(json) %>%
unnest_auto(results) %>%
unnest_auto(results) %>%
unnest_auto(geometry) %>%
unnest_auto(location)
#> Duke përdorur `unnest_wider(json)`; elementët kanë 2 emra të zakonshëm
#> Duke përdorur `unnest_longer(results)`; asnjë element nuk ka emra
#> Duke përdorur `unnest_wider(results)`; elementët kanë 5 emra të zakonshëm
#> Duke përdorur `unnest_wider(geometry)`; elementët kanë 4 emra të zakonshëm
#> Duke përdorur `unnest_wider(location)`; elementët kanë 2 emra të zakonshëm
#> # Një tibble: 5 x 11
#> qytet komponente_adrese… adresa_e_formatuar… kufijtë lat lng lloji_i_lokacionit
#>
#> 1 Hous… Houston, TX, SHBA 2 LA Los Angeles, CA… 3 New … New York, NY, U… 4 Chic… Chicago, IL, SHBA 5 Spri… Springfield, MO… # … me 4 variabla të tjerë: pamja e hartës , id_e_vendit , llojet ,
#> # statusiNe gjithashtu mund të shohim thjesht adresën e parë për secilin qytet:
loc %>%
unnest_wider(json) %>%
hoist(results, first_result = 1) %>%
unnest_wider(first_result) %>%
unnest_wider(geometry) %>%
unnest_wider(location)
#> # Një tibble: 5 x 11
#> qytet komponente_adrese… adresa_e_formatuar… kufijtë lat lng lloji_i_lokacionit
#>
#> 1 Hous… Houston, TX, SHBA 2 LA Los Angeles, CA… 3 New … New York, NY, U… 4 Chic… Chicago, IL, SHBA 5 Spri… Springfield, MO… # … me 4 variabla të tjerë: pamja e hartës , id_e_vendit , llojet ,
#> # statusiOse të përdorim hoist() për një zhytje me shumë nivele, për të kaluar direkt në lat dhe lng.
loc %>%
hoist(json,
lat = list("results", 1, "geometry", "location", "lat"),
lng = list("results", 1, "geometry", "location", "lng")
)
#> # Një tibble: 5 x 4
#> qytet 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.3Diskografia e Sharlës Gelfand
Në përfundim, ne do të shqyrtojmë konstrukcionin më të komplikuar - diskografia e Sharlës Gelfand. Siç kemi bërë në shembujt e mësipërm, fillojmë me konvertimin e listës në një data frame me një kolonë, dhe pastaj do ta zgjerim atë, në mënyrë që secili komponent të jetë një kolonë e veçantë. Gjithashtu, unë do ta transformoj kolonën date_added në formatin përkatës të datës dhe orës në R.
discs %
unnest_wider(disc) %>%
mutate(date_added = as.POSIXct(strptime(date_added, "%Y-%m-%dT%H:%M:%S")))
discs
#> # Një tibble: 155 x 5
#> instance_id date_added informacioni_bazik 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
#> # … me 145 rreshta të tjerëNë këtë nivel, ne kemi marrë informacionin se kur çdo disk u shtua në diskografinë e Sharlës, por nuk shohim asnjë të dhënën mbi këta disqe. Për këtë, na nevojitet të zgjeromë kolonën informacioni_bazik:
discs %>% unnest_wider(informacioni_bazik)
#> Emri i kolonës `id` nuk duhet të jetë i dyfishuar.
#> Përdoreni .name_repair për të specifikuar riparimin.Fatkeqësisht do të marrim një gabim, sepse brenda listës informacioni_bazik ka një kolonë me të njëjtin emër informacioni_bazik. Kur ndodh një gabim i tillë, për të përcaktuar shpejt shkakun e tij mund të përdorim names_repair = "unique":
discs %>% unnest_wider(informacioni_bazik, names_repair = "unique")
#> Emrat e rinj:
#> * id -> id...6
#> * id -> id...14
#> # Një tibble: 155 x 15
#> instance_id date_added etiketat viti artistët id...6 thumb titulli
#>
#> 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 # … me 145 rreshta të tjerë, dhe 7 variabla të tjerë: formatet ,
#> # imazhi_i_kopertinës , url_i_burimit , id_master ,
#> # url_master , id...14 , vlerësimiProblemi është se informacioni_bazik ripërton kolonën id e cila gjithashtu ruhet në nivelin e sipërm, prandaj ne mund ta fshijmë atë:
discs %>%
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 # … with 145 more rows, and 6 more variables: formats ,
#> # cover_image , resource_url , master_id ,
#> # master_url , ratingSi alternativë, mund të përdornim hoist():
discs %>%
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…
#> # … with 145 more rows, and 3 more variables: basic_information ,
#> # id , ratingKëtu shpejt nxjerr emrin e label-it dhe artistit të parë sipas indeksit, duke u zhytur në listën e thellë.
Një qasje më sistematike është të krijoni tabela të veçanta për artistët dhe label-at:
discs %>%
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
#> # … with 157 more rows
discs %>%
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 Numbered Black Cassette 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
#> # … with 270 more rowsMë pas mund t'i bashkoni përsëri ato me setin origjinal të të dhënave sipas nevojës.
Përfundimi
Në bërthamën e bibliotekës tidyverse janë shumë paketa të dobishme të bashkuara nga një filozofi e përbashkët për trajtimin e të dhënave.
Në këtë artikull ne shqyrtuam familjen e funksioneve unnest_*(), të cilët janë të orientuar për të punuar me nxjerrjen e elementeve nga listat e thelluara. Ky paketë përmban shumë funksione të tjera të dobishme që thjeshtojnë transformimin e të dhënave sipas konceptit të Tidy Data.
Burimi: habr.com
