Në shumicën e rasteve, kur punoni me përgjigjen e marrë nga API, ose me çdo të dhënë tjetër që ka një strukturë komplekse hierarkike, do të përballeni me formatet JSON dhe XML.
Këto formate kanë shumë avantazhe: ato ruajnë të dhënat në një formë të kompaktë dhe lejojnë shmangien e tepërtesës së informacionit.
Disavantazhi i këtyre formateve është vështirësia në përpunimin dhe analizimin e tyre. Të dhënat e pa strukturuara nuk mund të përdoren në llogaritje dhe nuk është e mundur të ndërtohet një vizualizim mbi bazën e tyre.

Ky artikull është një vazhdim logjik i publikimit . Ai do t'ju ndihmojë të shndërroni strukturat e dhënash të pa strukturuara në një format tabelar të zakonshëm dhe të përdorshëm për analizë përmes paketës tidyr, e cila është pjesë e bërthamës së bibliotekës tidyverse, dhe funksioneve të familjes unnest_*().
Përmbajtja
Nëse jeni të interesuar për analizën e të dhënave, ndoshta do t'ju interesojnë kanalet e mia në dhe Shumica e përmbajtjes së të cilave i kushtohet gjuhës R.
Hyrje
Rectangling (shĂ«n. e pĂ«rkthyesit, nuk gjeta variante adekuate pĂ«r pĂ«rkthimin e kĂ«tij termi, kĂ«shtu qĂ« do ta lĂ«mĂ« siç Ă«shtĂ«.) â Ă«shtĂ« procesi i shndĂ«rrimit tĂ« tĂ« dhĂ«nave tĂ« pa strukturuara me array tĂ« ngjitur nĂ« njĂ« tabelĂ« dy-dimensionale, e cila pĂ«rbĂ«het nga rreshta dhe kolona tĂ« njohura pĂ«r ne. NĂ« tidyr janĂ« disa funksione qĂ« do t'ju ndihmojnĂ« tĂ« zgjerojnĂ« kolumat e listave dhe tĂ« shndĂ«rrojnĂ« tĂ« dhĂ«nat nĂ« njĂ« formĂ« tĂ« drejtkĂ«ndĂ«she, tabelare:
unnest_longer()merr çdo element të kolumnit-listë dhe krijon një rresht të ri.unnest_wider()merr çdo element të kolumnit-listë dhe krijon një kolonnë të re.unnest_auto()përkufizon automatikisht se cila nga funksionet është më e përshtatshme për t'u përdorur
unnest_longer()oseunnest_wider().hoist()është e ngjashme meunnest_wider()por zgjidh vetëm komponentët e specifikuar dhe lejon punën 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 të ndërlikuara, shumë-nivele, të marra nga API-të e webit.
library(tidyr)
library(dplyr)
library(repurrrsive)Përdoruesit e GitHub
Të fillojmë me gh_users, një listë që përmban informacion mbi gjashtë përdoruesit e GitHub. Fillimisht, le të shndërrojmë listën gh_users në tibble të dhënave.:
users <- tibble( user = gh_users ) Kjo duket paksa jolojjike: pse të sjellësh një listë gh_users, në një strukturë më të komplikuar të të dhënave? Por data frame ka një avantazh të madh: ai bashkon disa vektorë, kështu që gjithçka ndiqet në një objekt.
Ădo element i objektit users pĂ«rfaqĂ«son njĂ« listĂ« tĂ« 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ë kthyer komponentët e listës në kolona. unnest_wider() merr çdo komponent dhe krijon një kolonë të re:
users %>% unnest_wider(user)
#> # Një tibble: 6 x 30
#> login id avatar_url gravatar_id url html_url followers_url
#> <chr> <int> <chr> <chr> <chr> <chr> <chr>
#> 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 <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>, name <chr>, company <chr>, blog <chr>,
#> # location <chr>, email <chr>, public_repos <int>, public_gists <int>,
#> # followers <int>, following <int>, created_at <chr>, updated_at <chr>,
#> # bio <chr>, hireable <lgl>Në këtë rast kemi marrë një tabelë që përmban 30 kolona, dhe shumica prej tyre nuk do të na nevojiten, prandaj mund të përdorim në vend unnest_wider() të përdorë 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
#>
#> 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() fshin komponentet e emëruar të specifikuar nga lista e kolonave user, prandaj ju mund ta konsideroni hoist() si një zhvendosje të komponentëve nga lista e brendshme e kuadrit të të dhënave në nivelin e tij më të lartë.
Repozitoret e Github
Rrafshimi i listës gh_repos ne fillojmë ngjashëm, duke e shndërruar atë në tibble:
repos # Një tibble: 6 x 1
#> repo
#>
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6KĂ«tĂ« herĂ« elementĂ«t user pĂ«rbĂ«jnĂ« njĂ« listĂ« tĂ« repo-ve qĂ« i pĂ«rkasin kĂ«tij pĂ«rdoruesi. Ădo repo Ă«shtĂ« njĂ« vĂ«zhgim i veçantĂ«, kĂ«shtu qĂ« sipas konceptit tĂ« tĂ« dhĂ«nave tĂ« rregullta (shĂ«n. tĂ« dhĂ«na tĂ« rregullta) ato duhet tĂ« bĂ«hen rreshta tĂ« rinj, prandaj ne pĂ«rdorim unnest_longer() ndĂ«rsa jo unnest_wider():
repos % unnest_longer(repo)
repos
#> # Një tibble: 176 x 1
#> repo
#>
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6
#> 7
#> 8
#> 9
#> 10
#> # ... me 166 rreshta të tjerëTani ne 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
#>
#> 1 gaborcsardi after 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
#> # ... me 166 rreshta të tjerëKujdesi në përdorimin e c("owner", "login"): kjo na lejon të marrim vlerën e nivelit të dytë nga lista e brendshme owner. Qasja alternative është të merrni listën e plotë owner dhe pastaj me anë të funksionit unnest_wider() ta vendosni ç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
#>
#> 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ë tjera, dhe 11 ndryshore të tjera: following_url ,
#> # gists_url , starred_url , subscriptions_url ,
#> # organizations_url , repos_url , events_url ,
#> # received_events_url , type , site_admin , repoNë vend që të mendoni për zgjedhjen e funksionit të duhur unnest_longer() ose unnest_wider() ju mund të përdorni unnest_auto(). Ky funksion përdor disa metoda heuristike për të përcaktuar funksionin më të përshtatshëm për transformimin e të dhënave dhe tregon një mesazh në lidhje me metodën e zgjedhur.
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 emri emri_i_plote pronari privat html_url përshkrimi fork url
#>
#> 1 6.12e7 pas gaborcsa⊠2 4.05e7 argu⊠gaborcsa⊠3 3.64e7 pyet gaborcsa⊠4 3.49e7 bazë⊠gaborcsa⊠5 6.16e7 cito⊠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 më shumë, dhe 58 variabla më shumë: 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 , ka_probleme ,
#> # ka_shkarkime , ka_wiki , ka_faqe ,
#> # forks_count , open_issues_count , forkë ,
#> # open_issues , shikues , default_branch ,
#> # homepagePersonazhet e lojës së fronit
got_chars ka një strukturë identike me gh_users: ky është një set listash të emëruara, ku çdo element i listës së brendshme përshkruan një atribut të karakterit të Dragoçevës. Kalimi got_chars në formë tabelare fillojmë duke krijuar një dataframe, ashtu si në shembujt e mëparshëm, dhe më pas do të transferojmë çdo element në një kolonë të veçantë:
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
#> <int> <chr> <chr> <chr> <chr> <chr> <lgl> <list> <list> <chr>
#> 1 http⊠1022 Theo⊠Male Ironbo⊠In 2⊠"" TRUE <chr ⊠<chr [⊠""
#> 2 http⊠1052 Tyri⊠Male "" In 2⊠"" TRUE <chr ⊠<chr [⊠""
#> 3 http⊠1074 Vict⊠Male Ironbo⊠In 2⊠"" TRUE <chr ⊠<chr [⊠""
#> 4 http⊠1109 Will Male "" "" In 2⊠FALSE <chr ⊠<chr [⊠""
#> 5 http⊠1166 Areo⊠Male Norvos⊠In 2⊠"" TRUE <chr ⊠<chr [⊠""
#> 6 http⊠1267 Chett Male "" At H⊠In 2⊠FALSE <chr ⊠<chr [⊠""
#> 7 http⊠1295 Cres⊠Male "" In 2⊠In 2⊠FALSE <chr ⊠<chr [⊠""
#> 8 http⊠130 Aria⊠Female Dornish In 2⊠"" TRUE <chr ⊠<chr [⊠""
#> 9 http⊠1303 Daen⊠Female Valyri⊠In 2⊠"" TRUE <chr ⊠<chr [⊠""
#> 10 http⊠1319 Davo⊠Male Wester⊠In 2⊠"" TRUE <chr ⊠<chr [⊠""
#> # ⊠with 20 more rows, and 7 more variables: mother <chr>, spouse <chr>,
#> # allegiances <list>, books <list>, povBooks <list>, tvSeries <list>,
#> # playedBy <list>Struktura got_chars pak mĂ« i komplikuar se gh_users, sepse disa komponentĂ« tĂ« listĂ«s char vetĂ« janĂ« lista, si rezultat ne marrim kolona â lista:
chars2 %>% select_if(is.list)
#> # A tibble: 30 x 7
#> titles aliases allegiances books povBooks tvSeries playedBy
#> <list> <list> <list> <list> <list> <list> <list>
#> 1 <chr [3]> <chr [4]> <chr [1]> <chr [3]> <chr [2]> <chr [6]> <chr [1]>
#> 2 <chr [2]> <chr [11]> <chr [1]> <chr [2]> <chr [4]> <chr [6]> <chr [1]>
#> 3 <chr [2]> <chr [1]> <chr [1]> <chr [3]> <chr [2]> <chr [1]> <chr [1]>
#> 4 <chr [1]> <chr [1]> <???> <chr [1]> <chr [1]> <chr [1]> <chr [1]>
#> 5 <chr [1]> <chr [1]> <chr [1]> <chr [3]> <chr [2]> <chr [2]> <chr [1]>
#> 6 <chr [1]> <chr [1]> <???> <chr [2]> <chr [1]> <chr [1]> <chr [1]>
#> 7 <chr [1]> <chr [1]> <???> <chr [2]> <chr [1]> <chr [1]> <chr [1]>
#> 8 <chr [1]> <chr [1]> <chr [1]> <chr [4]> <chr [1]> <chr [1]> <chr [1]>
#> 9 <chr [5]> <chr [11]> <chr [1]> <chr [1]> <chr [4]> <chr [6]> <chr [1]>
#> 10 <chr [4]> <chr [5]> <chr [2]> <chr [1]> <chr [3]> <chr [5]> <chr [1]>
#> # ⊠with 20 more rowsVeprat tuaja të mëtejshme varen nga qëllimet e analizës. Ndoshta ju nevojitet të vendosni në rreshta informacionin 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ë përputhni 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, për vlerat bosh "" në fushën titullin, kjo është për shkak të gabimeve të bërë gjatë hyrjes së të dhënave në got_chars: në të vërtetë, personazhet për të cilët nuk ka tituj përkatës librash dhe serialesh në fushën titullin duheshin të kishin një vektor të gjatësi 0, dhe jo një vektor të gjatësi 1 që përmban një varg bosh.)
Ne mund ta risistemi shembullin e mësipërm duke përdorur funksionin unnest_auto(). Ky qasje është e përshtatshme për një analizë të vetme, por nuk është e përshtatshme të mbështeteni në unnest_auto() për përdorim në një bazë të rregullt. E vetmja gjë është që nëse struktura juaj e të dhënave ndryshon unnest_auto() mund të ndryshojë mekanizmin e zgjedhjes për transformimin e të dhënave, nëse fillimisht ai shtrinte kolonat-lista në rreshta duke përdorur unnest_longer(), atëherë me ndryshimin e strukturës së të dhënave hyrëse logjika mund të ndryshohet në favor të unnest_wider(), dhe përdorimi i këtij qasjes në mënyrë të vazhdueshme mund të çojë në gabime të papritura.
tibble(char = got_chars) %>%
unnest_auto(char) %>%
select(name, title = titles) %>%
unnest_auto(title)
#> Përdorimi i `unnest_wider(char)`; elementët kanë 18 emra të përbashkët
#> Përdorimi i `unnest_longer(title)`; asnjë element nuk ka emra
#> # Një tibble: 60 x 2
#> name title
#>
#> 1 Theon Greyjoy Princi i Winterfell
#> 2 Theon Greyjoy Kapiteni i Sea Bitch
#> 3 Theon Greyjoy Lordi i Ishujve të Hekurit (sipër ligjit të tokave të gjelbra)
#> 4 Tyrion Lannister Dorehandi veprues i Mbretit (ish)
#> 5 Tyrion Lannister Master i Parave (ish)
#> 6 Victarion Greyjoy Kapiteni i Flotës së Hekurit
#> 7 Victarion Greyjoy Master i Fitores së Hekurit
#> 8 Will ""
#> 9 Areo Hotah Kapiteni i Gardës në Sunspear
#> 10 Chett ""
#> # ⊠me 50 rreshta të tjerëGeokodimi me Google
Më pas do të shqyrtojmë një strukturë më të komplikuar të të dhënave që merrni nga shërbimi i gjeokodimit të Google. Ruajtja e akreditivave është në kundërshtim me kushte të punës me API-të Google maps, kështu që unë fillimisht do të shkruaj një mbështjellës të thjeshtë për API-në. I cili bazohet në ruajtjen e çelësit të API-t të Google Maps në një variabël mjedisi; nëse në variablat e mjedisit nuk keni ruajtur çelësin për të punuar 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("Nuk u gjet çelësi i API-së së Google Maps; fragmentet e kodit nuk do të ekzekutohen")
}
# 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ë kthen kjo funksion është mjaft e komplikuar:
houston Lista 2
#> $ results: Lista 1
#> ..$ : Lista 5
#> .. ..$ address_components: Lista 4
#> .. .. ..$ : Lista 3
#> .. .. .. ..$ long_name : chr "Houston"
#> .. .. .. ..$ short_name: chr "Houston"
#> .. .. .. ..$ types : Lista 2
#> .. .. .. .. ..$ : chr "locality"
#> .. .. .. .. ..$ : chr "political"
#> .. .. ..$ : Lista 3
#> .. .. .. ..$ long_name : chr "Harris County"
#> .. .. .. ..$ short_name: chr "Harris County"
#> .. .. .. ..$ types : Lista 2
#> .. .. .. .. ..$ : chr "administrative_area_level_2"
#> .. .. .. .. ..$ : chr "political"
#> .. .. ..$ : Lista 3
#> .. .. .. ..$ long_name : chr "Texas"
#> .. .. .. ..$ short_name: chr "TX"
#> .. .. .. ..$ types : Lista 2
#> .. .. .. .. ..$ : chr "administrative_area_level_1"
#> .. .. .. .. ..$ : chr "political"
#> .. .. ..$ : Lista 3
#> .. .. .. ..$ long_name : chr "United States"
#> .. .. .. ..$ short_name: chr "US"
#> .. .. .. ..$ types : Lista 2
#> .. .. .. .. ..$ : chr "country"
#> .. .. .. .. ..$ : chr "political"
#> .. ..$ formatted_address : chr "Houston, TX, USA"
#> .. ..$ geometry : Lista 4
#> .. .. ..$ bounds : Lista 2
#> .. .. .. ..$ northeast: Lista 2
#> .. .. .. .. ..$ lat: num 30.1
#> .. .. .. .. ..$ lng: num -95
#> .. .. .. ..$ southwest: Lista 2
#> .. .. .. .. ..$ lat: num 29.5
#> .. .. .. .. ..$ lng: num -95.8
#> .. .. ..$ location : Lista 2
#> .. .. .. ..$ lat: num 29.8
#> .. .. .. ..$ lng: num -95.4
#> .. .. ..$ location_type: chr "APPROXIMATE"
#> .. .. ..$ viewport : Lista 2
#> .. .. .. ..$ northeast: Lista 2
#> .. .. .. .. ..$ lat: num 30.1
#> .. .. .. .. ..$ lng: num -95
#> .. .. .. ..$ southwest: Lista 2
#> .. .. .. .. ..$ lat: num 29.5
#> .. .. .. .. ..$ lng: num -95.8
#> .. ..$ place_id : chr "ChIJAYWNSLS4QIYROwVl894CDco"
#> .. ..$ types : Lista 2
#> .. .. ..$ : chr "locality"
#> .. .. ..$ : chr "political"
#> $ status : chr "OK"Fatkeqësisht, ne mund të zgjidhim hap pas hapi problemin e konvertimit të këtyre të dhënave në një format tabelar duke përdorur funksionet tidyr. Për ta bërë detyrën pak më sfiduese dhe realiste, do të filloj me gjeokodimin e disa qyteteve:
city <- c ( "Houston" , "LA" , "New York" , "Chicago" , "Springfield" ) city_geo <- purrr::map (city, geocode) Rezultati i marrë do ta konvertoj në tibble, për lehtësi do të shtoj një kolonnë me emrin përkatës të qytetit.
loc # Një 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]>Niveli i parë përmban komponentët status dhe rezultati, të cilin mund ta zhvillojmë duke përdorur unnest_wider() :
loc %>%
unnest_wider(json)
#> # Një 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]> OKVini re se results është një listë shumënivelesh. shumica e qyteteve kanë 1 element (që përfaqëson një vlerë unike, në përputhje me API-në e gjeokodimit), por Springfield ka dy. Ne mund t'i nxjerrim ato në rreshta të veçantë me anë të 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 OKTani të gjithë kanë komponente të njëjta, çka mund të provohet me anë të 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⊠2 LA Los Angeles, CA⊠<named ⊠ChIJE9on⊠3 New Y⊠New York, NY, U⊠<named ⊠ChIJOwg_⊠4 Chica⊠Chicago, IL, USA <named ⊠ChIJ7cv0⊠5 Sprin⊠Springfield, MO⊠<named ⊠ChIJP5jI⊠<lis⊠OKNe mund të gjejmë koordinatat e gjerësi dhe gjatësi për secilin qytet duke i zhvilluar listat 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⊠# ⊠with 4 more variables: viewport , place_id , types ,
#> # statusDhe më pas vendndodhja, për të cilën është e nevojshme të zhvillohet 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 ,
#> # statusPërsëri, unnest_auto() e thjeshton operacionin e përshkruar me disa rreziqe, të cilat mund të shkaktohen nga ndryshimi i strukturës së të dhënave hyrëse:
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ë përbashkët
#> Duke përdorur `unnest_longer(results)`; asnjë element nuk ka emra
#> Duke përdorur `unnest_wider(results)`; elementët kanë 5 emra të përbashkët
#> Duke përdorur `unnest_wider(geometry)`; elementët kanë 4 emra të përbashkët
#> Duke përdorur `unnest_wider(location)`; elementët kanë 2 emra të përbashkët
#> # 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⊠# ⊠me 4 variabla të tjera: viewport , place_id , types ,
#> # statusNe gjithashtu mund të shikojmë 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)
#> # 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⊠# ⊠me 4 variabla të tjera: viewport , place_id , types ,
#> # statusOse të përdorim hoist() për një zhytje shumëniveleshe, për të kaluar drejtpërsëdrejti në lat dhe 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.3Diskografia e Sharla Gelfand
NĂ« pĂ«rfundim do tĂ« shqyrtojmĂ« ndĂ«rtimin mĂ« tĂ« komplikuar â diskografinĂ« e SharlĂ«s Gelfand. Ashtu si nĂ« shembujt e shĂ«nuar mĂ« lart, ne fillojmĂ« me konvertimin e listĂ«s nĂ« njĂ« data frame me njĂ« kolonĂ«, dhe pastaj do ta zgjerojmĂ« qĂ« çdo komponent tĂ« jetĂ« njĂ« kolonĂ« e veçantĂ«. Gjithashtu, do ta bĂ«j 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
#> # 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 rowsNë këtë nivel kemi marrë informacion në lidhje me kur çdo disk është shtuar në diskografinë e Sharlës, por nuk shohim asnjë të dhënë në lidhje me këta disqe. Për këtë, na duhet të zgjerojmë kolonën basic_information:
discs %>% unnest_wider(basic_information)
#> Emri i kolonës `id` nuk duhet të jetë i dyfishuar.
#> Përdorni .name_repair për të specifikuar riparimin.Për fat të keq do të marrim një gabim, pasi brenda listës basic_information ka një kolonë me emër të njëjtë basic_information. 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(basic_information, names_repair = "unique")
#> Emri të rinj:
#> * id -> id...6
#> * id -> id...14
#> # Një 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 # ⊠me 145 rreshta më shumë, dhe 7 ndryshime të tjera: formats ,
#> # cover_image , resource_url , master_id ,
#> # master_url , id...14 , ratingProblemi është se basic_information replicon id kolona e cila gjithashtu ruhet në nivelin e lartë, kështu që thjesht mund ta fshijmë:
discs %>%
select(-id) %>%
unnest_wider(basic_information)
#> # Një 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 # ⊠me 145 rreshta më shumë, dhe 6 ndryshime të tjera: formats ,
#> # cover_image , resource_url , master_id ,
#> # master_url , ratingSi një alternativë, ne mund të përdorim 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 unë shpejt nxjerr emrin e parë të label-it dhe artistit sipas indeksit, duke u zhytur në një listë të thelluar.
Një qasje më sistematike është krijimi i tabelave të veçanta për artistin dhe label-in:
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 rowsPastaj mund t'i bashkoni përsëri ato në setin origjinal të të dhënave sipas nevojës.
Përfundim
Në thelb të bibliotekës tidyverse janë të përfshirë shumë paketa të dobishme të bashkuara nga një filozofi e përbashkët e përpunimit të të dhënave.
Në këtë artikull, ne shqyrtuam familjen e funksioneve unnest_*(), të cilat janë të orientuara drejt punës me ekskursionin e elementeve nga lista të inkuadruara. 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
