Help us understand the problem. What is going on with this article?

{purrr}で覗くStarWarsの世界

はじめに

Rのパッケージpurrrmap()の基本的な使い方を、StarWarsのデータを使いながら学ぶという初心者向けの記事です。すでに良記事がたくさんありますので、先に参照してください…笑。すごく勉強になります。

ここでは、あえてmap()を多用する場面があります。たしかに、はやいことデータフレームに変換すれば、もっと楽に処理できるかもしれません…が、あえてmap()を使う場面が多くありますので、「もっと楽に処理できるのに…。それ、データフレームにしたらいいんじゃない?」とか思わないでください…笑。また、意図的にmap()を使っている場合でも、それが最適なコードというわけではない点、ご了承ください。

※注意:私はStarWarsを1度も見たことがないので、StarWarsドメイン知識は0です。ダースベータは黒くて、赤いライトイセイバーを持っていることくらいはかろうじて知っていますが…。支離滅裂なことを書いている可能性は否定できません。

この記事は下記のビデオを参考にしています。

データセットの紹介

repurrrsiveパッケージのデータを使います。このパッケージには、purrrのための様々なデータが格納されています。StarWars関連だと、sw_peoplesw_filmssw_speciessw_planetssw_starshipssw_vehiclesが格納されています。

例えば、sw_peopleはデータ型がリストで、長さ87。87キャラクターの情報がリストのリストで保存されています。

R
library(repurrrsive)

typeof(sw_people)
[1] "list"

length(sw_people)
[1] 87

names(sw_people[[1]])
 [1] "name"       "height"     "mass"       "hair_color" "skin_color" "eye_color"  "birth_year" "gender"    
 [9] "homeworld"  "films"      "species"    "vehicles"   "starships"  "created"    "edited"     "url"      

もう少し細かく見ると、1つ目は"Luke Skywalker"のデータのようです。各キャラクターは下記のような情報を持っており、例えば$filmsには長さ5の文字型ベクトルがあったり、$heightには整数が文字型ベクトルで格納されていたり、少し面倒なデータセットのようです。

R
str(sw_people[[1]])
List of 16
 $ name      : chr "Luke Skywalker"
 $ height    : chr "172"
 $ mass      : chr "77"
 $ hair_color: chr "blond"
 $ skin_color: chr "fair"
 $ eye_color : chr "blue"
 $ birth_year: chr "19BBY"
 $ gender    : chr "male"
 $ homeworld : chr "http://swapi.co/api/planets/1/"
 $ films     : chr [1:5] "http://swapi.co/api/films/6/" "http://swapi.co/api/films/3/" "http://swapi.co/api/films/2/" "http://swapi.co/api/films/1/" ...
 $ species   : chr "http://swapi.co/api/species/1/"
 $ vehicles  : chr [1:2] "http://swapi.co/api/vehicles/14/" "http://swapi.co/api/vehicles/30/"
 $ starships : chr [1:2] "http://swapi.co/api/starships/12/" "http://swapi.co/api/starships/22/"
 $ created   : chr "2014-12-09T13:50:51.644000Z"
 $ edited    : chr "2014-12-20T21:17:56.891000Z"
 $ url       : chr "http://swapi.co/api/people/1/"

map()のおさらい

forループなど繰り返し作業を、簡潔で読みやすいコードで置き換えることができる関数、それがmap()です。基本的な文法は下記のとおりです。つまり、ベクトル、リスト、データフレームのカラムなどそれぞれに対して、関数を適用してくれる関数です。

R
map(.x, .f, ...) # for each element of .x do .f

.x : vector / list / dataframe(for each column)
.f = do something

map_**()**の部分にデータ型を指定することで、アウトプットのデータ型を指定し、ベクトルで出力できます。map_int()map_dbl()map_chr()map_lgl()map_int()map_dfc()map_dfr()があります。

キャラクターの項目数は同じ?

sw_peopleには各キャラクターの情報が格納されているようですが、キャラクターすべてが同じ情報(項目)を持っているのでしょうか。基本的に、現実のデータ分析で扱うデータは、すべて綺麗に揃っているわけないので、確認を含めて調べましょう。

案の定、最大で16、最小で13の通りばらついているようです。なので、各キャラクターは同じ量の情報量を持っているわけではないようです。そして、大体が14個か15個の情報をもっているようです。

R
sw_people %>% 
  map(., names) %>% 
  map_int(., length) %>% 
  unique()

[1] 16 14 15 13

sw_people %>% 
  map(., names) %>% 
  map_chr(., length) %>% 
  table(.)

.
13 14 15 16 
 4 60 16  7 

リスト内の情報を一括で確認

先ほどは同じ項目数があるのかどうかを調べましたが、今度はunknownという言葉が含まれている数も調べておきます。このような場合、少し混乱しますが、map(.x , ~ map(.x = ., ~ f))という形でmap()をラップして使うことになります。"Captain Phasma"はunknownという言葉が6個も含まれているようですね。

R
sw_people %>% 
  map_int(.x = ., ~ map_lgl(.x = ., ~ "unknown" %in% .x) %>% sum()) %>%
  set_names(sw_people %>% map_chr(., "name")) %>% 
  sort(decreasing = TRUE) %>% 
  head(10)

Captain Phasma   Arvel Crynyd           Finn            Rey    Poe Dameron            BB8     Rugor Nass 
             6              3              3              3              3              3              2 
     Ric Olié          Watto    Bib Fortuna 
             2              2              2 

リストのキャラクター名を確認

リストのキャラクター名を確認します。確認したところで誰が誰なのかわかりませんが、ダースベータも含まれるんでしょうか。map_chr()にリストを渡して、nameというリストの部分を抽出するようにお願いし、tibbleに変換し、判定するという流れをここではとってみます。ダースベータもリストに含まれているようです。

R
sw_people %>% 
  map_chr(., "name") %>% 
  tibble(name = .) %>% 
  mutate(flg = if_else(name == "Darth Vader", TRUE, FALSE)) %>% 
  filter(flg == TRUE)

# A tibble: 1 x 2
  name        flg  
  <chr>       <lgl>
1 Darth Vader TRUE 

キャラクターの身長は、日本人と同じくらいか?

StarWarsを見たことないので、キャラクターの身長は、日本人の平均身長と同じくらいのでしょうか。日本人男性の身長は、170.7cmくらいなので、それと同じくらいでしょうか。調べてみましょう。

R
sw_people %>% 
+   map_int(., "height")
 エラー: Can't coerce element 1 from a character to a integer

????。なんでやねん。身長は数字で入っとるやろ。ほれみてみ、"172"って数字やないの。

R
sw_people[[1]]["height"]
$height
[1] "172"

関西のおばちゃんのようなクレームはいけません。エラー文"Can't coerce element 1 from a character to a integer"をみれば明らかですが、これは文字型ですね。落ち着いて中身を確認しましょう。

R
sw_people %>% 
  map_chr(., "height")

 [1] "172"     "167"     "96"      "202"     "150"     "178"     "165"     "97"      "183"     "182"     "188"    
[]
[78] "234"     "188"     "178"     "206"     "unknown" "unknown" "unknown" "unknown" "unknown" "165"    

見事なまでにすべて文字型ですね。一部省略してますが、再現して確認してみてください。

sw_people %>% 
  map(., "height") %>% 
  map_chr(., typeof)

 [1] "character" "character" "character" "character" "character" "character" "character" "character" "character"
[略]
[82] "character" "character" "character" "character" "character" "character"

こんな時は素直に文字型で抽出して、データ型を整数型に変えてしまいます。

R
sw_people %>% 
  map_chr(., "height") %>% 
  readr::parse_number(na = "unknown")

 [1] 172 167  96 202 150 178 165  97 183 182 188 180 228 180 173 175 170 180  66 170 183 200 190 177 175 180 150  NA
[29]  88 160 193 191 170 196 224 206 183 137 112 183 163 175 180 178  94 122 163 188 198 196 171 184 188 264 188 196
[57] 185 157 183 183 170 166 165 193 191 183 168 198 229 213 167  79  96 193 191 178 216 234 188 178 206  NA  NA  NA
[85]  NA  NA 165

あとはこれの平均をとれば、日本人男性の平均身長と同じかどうか確認できます。

結果として、StarWarsのキャラクターの平均身長は174.4cmくらいなので、日本人の身長よりも平均は大きいようです。どちらかというと、アメリカ人男性の平均身長174cmなので、StarWarsはアメリカに近い世界のようです。そりゃそうかもしれませんが。

R
sw_people %>% 
  map_chr(., "height") %>% 
  readr::parse_number(., na = "unknown") %>% 
  mean(., na.rm = TRUE)

[1] 174.358

ダースベータの身長は?

ダースベータの身長はどのくらいなんでしょうか。気になりますね。たまにCMでお見かけすると、きっと他のキャラクターと同じくらいなので、174cmくらいなんでしょう。ダースベータが格納されているリスト番号を使って、身長を確認しましょう。

R
Vader_index <- sw_people %>% 
  map_lgl(., ~ .x[["name"]] == "Darth Vader") %>% 
  which(TRUE)

sw_people[[Vader_index]]["name"]
$name
[1] "Darth Vader"

sw_people[[Vader_index]]["height"]
$height
[1] "202"

うん??202cmですか。えっと…デカすぎませんかね。NBA選手の平均身長が200㎝とかとかなので、NBA選手くらい身長が高いようです。

Googleで調べると、190cmです。190cmでもでかいですが、その下のChewbaccaは230cmなのでもっとでかい…StarWarsのキャラクターって、誰が一番高いんでしょうか。

スクリーンショット 0031-03-17 16.44.54.png

誰が一番身長高いんでしょうか。

身長をsw_peopleから抽出するのはさきほど同様です。ダースベータは4番目です。1番を大きいのは、54番目の264cmですね。"Yarael Poof"が1番高いようですが、これだと面倒ですね。2番目、3番目とか一気に調べたいですね。

R
sw_people %>% 
  map_chr(., "height") %>% 
  readr::parse_number(na = "unknown")

 [1] 172 167  96 202 150 178 165  97 183 182 188 180 228 180 173 175 170 180  66 170 183 200 190 177 175 180 150  NA
[29]  88 160 193 191 170 196 224 206 183 137 112 183 163 175 180 178  94 122 163 188 198 196 171 184 188 264 188 196
[57] 185 157 183 183 170 166 165 193 191 183 168 198 229 213 167  79  96 193 191 178 216 234 188 178 206  NA  NA  NA
[85]  NA  NA 165

sw_people[[54]][["name"]]
[1] "Yarael Poof"

そんなときは、purrrtidyrset_names()を組み合わせて名前も同時に抽出してしまいます。名前の抽出もset_names()の中でmap_chr()を使います。ダースベータは、このStarWarsキャラクターリストだと上から10番目に身長が高いようです。

R
sw_people %>% 
  map_chr(., "height") %>% 
  readr::parse_number(na = "unknown") %>% 
  set_names(sw_people %>% map_chr(., "name")) %>% 
  sort(., decreasing = TRUE) %>% 
  head(10)

 Yarael Poof      Tarfful      Lama Su    Chewbacca Roos Tarpals     Grievous      Taun We   Rugor Nass   Tion Medon 
         264          234          229          228          224          216          213          206          206 
 Darth Vader 
         202 

そして、"Yarael Poof"って、誰なんでしょうか。Wikipediaで調べると、人間ではない感じのフォルムです。たしかに首だけそこそこ身長を稼げそうです。

スクリーンショット 0031-03-17 20.44.52.png
Source | Yarael Poof

戦闘能力が低そうなキャラクターは誰?

StarWarsを見たことがないので、誰が強く誰が弱いのか、検討もつきません。ここでは無理矢理に、体の肥満度合いの値であるBMIを擬似的な戦闘能力(肥満は弱いだろう…安直ですが。)と考え、どのキャラクターが一番弱いのかを見ていきます。

ここで問題になるのが、これまではリストの1つの値を計算してきましたが、BMIを計算するにはheightmass(MASSってkgでOK?)2つの値を使う必要があります。このような場合は、map()ではなく、map2()という2つの値を扱うことができる関数を利用します。

R
map2(.x, .y, .f, ...) # for each element of .x & .y do .f

.x : veector / list / dataframe(for each column)
.y : veector / list / dataframe(for each column)
.f = do something

結果は、群を抜いて"Jabba Desilijic Tiure"です。こんなやつらしいですが、明らかな肥満体ですね。首もないくらいに。

R
map2_dbl(.x = map_chr(sw_people, "mass") %>% 
       map(., parse_number, na = "unknown"),
     .y = map_chr(sw_people, "height") %>% 
       map(., parse_number, na = "unknown"),
     .f = ~ (.x* 10000 / (.y)^2)) %>% 
  set_names(map_chr(sw_people, "name")) %>% 
  sort(decreasing = TRUE) %>%
  head(5)

Jabba Desilijic Tiure              Dud Bolt                  Yoda             Owen Lars                 IG-88 
            443.42857              50.92802              39.02663              37.87401              35.00000 

スクリーンショット 0031-03-17 23.10.42.png
Source | Jabba Desilijic Tiure

各キャラクターに必要なカロリーは?

先ほどは、BMIを戦闘能力の高さに例え、強さ見てきました。次は、必要なカロリーの量を計算していきます。戦士には、栄養補給と休息も必要ですからね。というか金ピカの機械もいませんでしたっけ。機械にカロリーとか意味不明ですが、ここでは一旦忘れてください。

カロリーの量の計算は身長の2乗*BMI指数の22*重労働の運動強度の35で算出します。こんな感じのカロリー計算式があるらしい。詳しくはご自分でお調べください。本題はそこではなく、pmap()3つの値を扱えるという点です。

R
pmap(.l = (.x, .y, .z), .f, ...) # for each element of .x & .y & .z do .f

.x : veector / list / dataframe(for each column)
.y : veector / list / dataframe(for each column)
.z : veector / list / dataframe(for each column)
.f = do something

ここでは、BMI指数は22と運動強度は35と定数ですが、次の例ではリスト同士の計算例を載せています。一番、カロリーを必要としているのは"Yarael Poof"のようです。あの首が長いキャラクターですね。マクドナルドのビックマックが1つ530kcalらしいので、10個分に相当するカロリーです。

R
pmap_dbl(.l = list(x = map_chr(sw_people, "height") %>% map_dbl(., parse_number, na = "unknown"),
               y = 22,
               z = 35),
     .f = function(x, y, z) { (x/100)^2 * y * z}) %>% 
  set_names(map_chr(sw_people, "name")) %>% 
  sort(decreasing = TRUE) %>%
  head(10)

 Yarael Poof      Tarfful      Lama Su    Chewbacca Roos Tarpals     Grievous      Taun We 
    5366.592     4216.212     4037.957     4002.768     3863.552     3592.512     3493.413 
  Rugor Nass   Tion Medon  Darth Vader 
    3267.572     3267.572     3141.908 

各キャラクター情報一覧を作る?

先ほどは、定数を使って3つの値の計算を行いましたが、今回は定数ではなくリスト同士を計算します。各キャラクターに簡単な自己紹介(「名前」「身長」「体重(MASSってkgでOK?)」)を作成します。情報が非公開のキャラクターは-で置き換えます。

R
pmap_chr(.l = list(x = map_chr(sw_people, "name"),
                   y = map_chr(sw_people, "height") %>% if_else(. == "unknown", "-", .),
                   z = map_chr(sw_people, "mass") %>% if_else(. == "unknown", "-", .)),
         .f = function(x, y, z) { paste(stringr::str_c("I'm ", x, ". (Height is ", y, "cm / Weight is ", z, "kg)"))}) %>% 
  head(10)

 [1] "I'm Luke Skywalker. (Height is 172cm / Weight is 77kg)"    
 [2] "I'm C-3PO. (Height is 167cm / Weight is 75kg)"             
 [3] "I'm R2-D2. (Height is 96cm / Weight is 32kg)"              
 [4] "I'm Darth Vader. (Height is 202cm / Weight is 136kg)"      
 [5] "I'm Leia Organa. (Height is 150cm / Weight is 49kg)"       
 [6] "I'm Owen Lars. (Height is 178cm / Weight is 120kg)"        
 [7] "I'm Beru Whitesun lars. (Height is 165cm / Weight is 75kg)"
 [8] "I'm R5-D4. (Height is 97cm / Weight is 32kg)"              
 [9] "I'm Biggs Darklighter. (Height is 183cm / Weight is 84kg)" 
[10] "I'm Obi-Wan Kenobi. (Height is 182cm / Weight is 77kg)" 

ダースベーダの出演作品は?

ココらへんからトピックがなくなってきて辛いところです。StarWarsを見たことないですが、シリーズが多いということくらいは知っています。ダースベーダさんは、いくつの作品に出演しているか調べます。pluck()という関数は、リストのフィルタみたいなもので、リストの抽出に使えます。これでダースベーダーさんは4つ作品に出演していることが分かったのですが、これは多い方なんしょうかね?

R
sw_people %>% pluck(., 4, "films") %>% length()
[1] 4

キャラクターごとに確認してみます。基本的には1,2回の出演なので、4回は多いほうなんでしょうね。

R
sw_people %>% 
  map(., "films") %>% 
  map_int(., length) %>% 
  table(.)

.
 1  2  3  4  5  6  7 
46 18 13  2  5  2  1 

R2-D2は7回も出演しているキャラクターのようです。おそらくStarWarsでは、重要な役割を果たすキャラクターなんでしょう。確かにCMとかで見たことありますが、重要なんですかね。

R
sw_people %>% 
  map(., "films") %>% 
  map_int(., length) %>% 
  set_names(sw_people %>% map_chr(., "name")) %>%  
  sort(., decreasing = TRUE) %>% 
  head(10)

         R2-D2          C-3PO Obi-Wan Kenobi Luke Skywalker    Leia Organa      Chewbacca           Yoda 
             7              6              6              5              5              5              5 
     Palpatine    Darth Vader       Han Solo 
             5              4              4 

220px-Star_Wars_and_the_Power_of_Costume_July_2018_19_(R2-D2_costume_from_Episode_IV).jpg
Source | R2-D2

各キャラクターの出演作品フラグを作る

そろそろ想像力とmap()の知識の限界です…。最後に、tibble()と組み合わせて、各キャラクターの出演作品フラグを立てる例を最後に、この記事もおしまいとします。

まず、people_tbl$filmsの中のURLを使って、エピソード番号を引けるようにルックアップテーブルを作っておきます。

R
film_number_lookup <- map_chr(sw_films, "url") %>%
  map(~ stringr::str_split_fixed(.x, "/", 7)[, 6]) %>%
  as.numeric() %>%
  set_names(sw_films %>% map_chr(., "url"))

film_number_lookup
http://swapi.co/api/films/1/ http://swapi.co/api/films/5/ http://swapi.co/api/films/4/ 
                           1                            5                            4 
http://swapi.co/api/films/6/ http://swapi.co/api/films/3/ http://swapi.co/api/films/2/ 
                           6                            3                            2 
http://swapi.co/api/films/7/ 
                           7 

次に、map()を使いながらtibbleを作っていきます。people_tblは通常のデータフレームとは異なり、カラムにリストを格納しているデータ構造です。このtibble内のリストに対して、map()を適用していくことになります。

R
people_tbl <- tibble(
  name    = sw_people %>% map_chr("name"), 
  films   = sw_people %>% map("films"))

people_tbl
# A tibble: 87 x 2
   name               films    
   <chr>              <list>   
 1 Luke Skywalker     <chr [5]>
 2 C-3PO              <chr [6]>
 3 R2-D2              <chr [7]>
 4 Darth Vader        <chr [4]>
 5 Leia Organa        <chr [5]>
 6 Owen Lars          <chr [3]>
 7 Beru Whitesun lars <chr [3]>
 8 R5-D4              <chr [1]>
 9 Biggs Darklighter  <chr [1]>
10 Obi-Wan Kenobi     <chr [6]>
# … with 77 more rows

例えば、people_tbl$films[[1]]はこのようなURLのデータが入っています。このURLを使って、さきほどのルックアップテーブルからエピソード番号を取ります。

R
people_tbl$films[[1]]
[1] "http://swapi.co/api/films/6/" "http://swapi.co/api/films/3/"
[3] "http://swapi.co/api/films/2/" "http://swapi.co/api/films/1/"
[5] "http://swapi.co/api/films/7/"

people_tbl <- people_tbl %>%
  mutate(film_numbers = map(films, ~ film_number_lookup[.x])) %>% 
  select(-films)

people_tbl
# A tibble: 87 x 2
   name               film_numbers
   <chr>              <list>      
 1 Luke Skywalker     <dbl [5]>   
 2 C-3PO              <dbl [6]>   
 3 R2-D2              <dbl [7]>   
 4 Darth Vader        <dbl [4]>   
 5 Leia Organa        <dbl [5]>   
 6 Owen Lars          <dbl [3]>   
 7 Beru Whitesun lars <dbl [3]>   
 8 R5-D4              <dbl [1]>   
 9 Biggs Darklighter  <dbl [1]>   
10 Obi-Wan Kenobi     <dbl [6]>   

people_tbl$film_numbers[[1]]
http://swapi.co/api/films/6/ http://swapi.co/api/films/3/ http://swapi.co/api/films/2/ 
                           6                            3                            2 
http://swapi.co/api/films/1/ http://swapi.co/api/films/7/ 
                           1                            7 

あとは、このエピソード番号が入ったリストを展開していくだけです。ここでは、各キャラクターごとにカンマ区切りで展開しておきます。

R
people_tbl <- people_tbl %>% 
  mutate(films_squashed = map_chr(film_numbers, paste, collapse = ",")) %>% 
  select(-film_numbers)

people_tbl
# A tibble: 87 x 2
   name               films_squashed
   <chr>              <chr>         
 1 Luke Skywalker     6,3,2,1,7     
 2 C-3PO              5,4,6,3,2,1   
 3 R2-D2              5,4,6,3,2,1,7 
 4 Darth Vader        6,3,2,1       
 5 Leia Organa        6,3,2,1,7     
 6 Owen Lars          5,6,1         
 7 Beru Whitesun lars 5,6,1         
 8 R5-D4              1             
 9 Biggs Darklighter  1             
10 Obi-Wan Kenobi     5,4,6,3,2,1   
# … with 77 more rows

各キャラクターごとにカンマ区切りで展開している状態から、各エピソードに該当するかどうかのフラグを立てます。ここでもmap()を使っていきます。加工方法としては、フラグのユニークな一覧を作って、それをもとに判定していきます。このmap2_dfc()の使い方は、r-wakalangで昔に教えていただきました。ありがとうございました。

R
col_val <- people_tbl %>% 
  separate_rows(., films_squashed) %>% 
  distinct(films_squashed) %>% 
  arrange(films_squashed)

people_tbl <- people_tbl %>% 
  select(films_squashed) %>% 
  map2_dfc(., col_val$films_squashed, ~ str_detect(.x, pattern = .y)) %>% 
  set_names(str_c("Ep_", col_val$films_squashed)) %>% 
  mutate_if(is.logical, as.numeric) %>% 
  bind_cols(people_tbl %>% select(-films_squashed)) %>% 
  select(name, everything())

people_tbl
# A tibble: 87 x 8
   name                Ep_1  Ep_2  Ep_3  Ep_4  Ep_5  Ep_6  Ep_7
   <chr>              <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1 Luke Skywalker         1     1     1     0     0     1     1
 2 C-3PO                  1     1     1     1     1     1     0
 3 R2-D2                  1     1     1     1     1     1     1
 4 Darth Vader            1     1     1     0     0     1     0
 5 Leia Organa            1     1     1     0     0     1     1
 6 Owen Lars              1     0     0     0     1     1     0
 7 Beru Whitesun lars     1     0     0     0     1     1     0
 8 R5-D4                  1     0     0     0     0     0     0
 9 Biggs Darklighter      1     0     0     0     0     0     0
10 Obi-Wan Kenobi         1     1     1     1     1     1     0
# … with 77 more rows

以上で、「{purrr}で覗くStarWarsの世界」でした。ここまでmap()に固執しなくても、下記のように、tibbleにする方法を最初から取れば、簡単に列同士の計算ができるので、こっちのほうが慣れてるし楽かもしれません。

が、しかし、現実のデータは本当にいろんな構造をしています。そんなときに、いろんなデータの扱い方を知っていれば、データの前処理が少しは楽になるかもしれません。少しでも、この記事が、どこかのRユーザーのお役に立てれば幸いです。

R
people_tbl <- tibble(
  name = sw_people %>% map_chr("name"),
  height = sw_people %>% map_chr("height") %>% readr::parse_number(na = "unknown"),
  mass = sw_people %>% map_chr("mass") %>% readr::parse_number(na = "unknown"),
  hair_color = sw_people %>% map_chr("hair_color"),
  skin_color = sw_people %>% map_chr("skin_color"),
  eye_color = sw_people %>% map_chr("eye_color"),
  birth_year = sw_people %>% map_chr("birth_year"),
  gender = sw_people %>% map_chr("gender"),
  homeworld = sw_people %>% map_chr("homeworld"),
  films = sw_people %>% map("films"),
  species = sw_people %>% map_chr("species", .null = NA_character_),
  vehicles = sw_people %>% map("vehicles"),
  starships = sw_people %>% map("starships"),
  created = sw_people %>% map_chr("created") %>% readr::parse_datetime(),
  edited = sw_people %>% map_chr("edited") %>% readr::parse_datetime(),
  url = sw_people %>% map_chr("url")
)

# A tibble: 87 x 16
   name  height  mass hair_color skin_color eye_color birth_year gender homeworld films species
   <chr>  <dbl> <dbl> <chr>      <chr>      <chr>     <chr>      <chr>  <chr>     <lis> <chr>  
 1 Luke    172    77 blond      fair       blue      19BBY      male   http://s <chr http:/
 2 C-3PO    167    75 n/a        gold       yellow    112BBY     n/a    http://s <chr http:/
 3 R2-D2     96    32 n/a        white, bl red       33BBY      n/a    http://s <chr http:/
 4 Dart    202   136 none       white      yellow    41.9BBY    male   http://s <chr http:/
 5 Leia    150    49 brown      light      brown     19BBY      female http://s <chr http:/
 6 Owen    178   120 brown, gr light      blue      52BBY      male   http://s <chr http:/
 7 Beru    165    75 brown      light      blue      47BBY      female http://s <chr http:/
 8 R5-D4     97    32 n/a        white, red red       unknown    n/a    http://s <chr http:/
 9 Bigg    183    84 black      light      brown     24BBY      male   http://s <chr http:/
10 Obi-    182    77 auburn, w fair       blue-gray 57BBY      male   http://s <chr http:/
# … with 77 more rows, and 5 more variables: vehicles <list>, starships <list>, created <dttm>,
#   edited <dttm>, url <chr>
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away