ZhvillojmĂ« kolona tĂ« ngulitura — lista me ndihmĂ«n e gjuhĂ«s R (paketa tidyr dhe funksionet e familjes unnest)

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.

ZhvillojmĂ« kolona tĂ« ngulitura — lista me ndihmĂ«n e gjuhĂ«s R (paketa tidyr dhe funksionet e familjes unnest)

Ky artikull është një vazhdim logjik i publikimit "Pako R tidyr dhe funksionet e saj të reja pivot_longer dhe pivot_wider". 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ë telegram dhe youtube Shumica e përmbajtjes së të cilave i kushtohet gjuhës R.

  1. Hyrje
  2. Përdoruesit e GitHub
  3. Repozitoret e Github
  4. Personazhet e lojës së fronit
  5. Geokodimi me Google
  6. Diskografia e Sharla Gelfand
  7. Përfundim

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() ose unnest_wider().
  • hoist() Ă«shtĂ« e ngjashme me unnest_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/masalmon

hoist() 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 
#> 6

KĂ«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 , repo

Në 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 ,
#> #   homepage

Personazhet 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 rows

Veprat 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 rows

Ose, 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]> OK

Vini 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  OK

Tani 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
 OK

Ne 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 ,
#> #   status

Dhe 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 ,
#> #   status

Pë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 ,
#> #   status

Ne 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 ,
#> #   status

Ose 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.3

Diskografia 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 rows

Në 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 , rating

Problemi ë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 , rating

Si 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 , rating

Kë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 rows

Pastaj 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

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster