2 Excelファイルの読み込み

2.1 一つのExcelファイルを読み込む

2.1.1 ファイルの準備と読み込み

ExcelファイルをRに読み込むには、readxlパッケージが便利です。7セクション1.2で述べた通り、ここからは、githubレポジトリのhttps://github.com/izunyan/excel_r をダウンロードしてプロジェクトを開いて進めてみてください。dataフォルダ(data/で表現)に入っている「ペンギン.xlsx」8を読み込んでみましょう。

読み込みにはread_xlsx()関数を使います。したがって、以下すべてExcelファイル形式は.xlsxを想定します。read_xls()read_excel()という関数もあるので、ファイル形式によって使い分けられます。ファイル形式が混ざっている時はread_excel()が有用かもしれません。

library(readxl)

df <- 
 read_xlsx("data/ペンギン.xlsx") # Excelファイルの読み込み

df # データの表示 
## # A tibble: 344 × 9
##   species 種類     island   bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>   <chr>    <chr>      <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Adelie  アデリー Torgers…    39.1    18.7     181    3750 male 
## 2 Adelie  アデリー Torgers…    39.5    17.4     186    3800 fema…
## 3 Adelie  アデリー Torgers…    40.3    18       195    3250 fema…
## # … with 341 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g

上記コードを実行すると、RStudioの右上(デフォルトの配置であれば)のEnvironmentタブに、

df  344 obs. of 9 variables

という表示が出ると思います。つまり、344行のデータと9列の変数が入っているデータを、dfという名前のもの(オブジェクト)としてRに読みこんだ、ということを示しています。df <-の部分がその作業に該当します。<-の右側の内容を左側のオブジェクトに格納するという意味です。ここで読み込まれた形がデータフレーム(はじめに>本書の構成の注参照)です。

オブジェクト名であるdfと打つことで、デフォルトでは最初の10行分のデータが表示されます。ここでは紙面の都合で設定を変えているので3行だけにしています。表示された最初の行にも、A tibble: 344 x 9と、行数x列数の情報が出ています。表示しきれなかった行は、with 341 more rowsと省略され、表示しきれなかった列は、flipper_length_mm <dbl>, body_mass_g <dbl>, sex <chr>, year <dbl>と、名前<データの型名>が表示されます。なお、読みこんだファイルの保存については3.1章で解説します。

2.1.1.1 最高な機能だよ!パスの自動補完

read_xlsx("")と打った後に、" "の中にカーソルを置いて、tabキーを押すと、プロジェクトの中身が一覧で表示されるので、選んでいくだけで目的のファイルがキーボードを打つことなしに選べます!RStudioは" "と打てばどこでもこの補完が可能です。9

上の階層のフォルダに行きたいときは、" "の中に../と打てば可能です。その後にtabキーを押せば上の階層のフォルダが選べます。

2.1.2 列名(変数名)がひどい場合の読み込み

read_xlsx("data/ペンギン(ひどい列名)ver.xlsx")
## # A tibble: 344 × 9
##   Spe…¹ `種 類` ※島…²   ①クチ…³ ②クチバ…⁴ 翼:…⁵ ■体重…⁶ `㊛㊚`
##   <chr>   <chr>    <chr>     <dbl>   <dbl>  <dbl>   <dbl> <chr> 
## 1 Adelie  アデリー Torger…    39.1    18.7    181    3750 male  
## 2 Adelie  アデリー Torger…    39.5    17.4    186    3800 female
## 3 Adelie  アデリー Torger…    40.3    18      195    3250 female
## # … with 341 more rows, 1 more variable:
## #   `2007~2009` <dbl>, and abbreviated variable names
## #   ¹​Species, ²​`※島の名前`, ³​`①クチバシ 長さ(mm)`,
## #   ⁴​`②クチバシ_大きさ(mm)`, ⁵​`翼:長さ(mm)`,
## #   ⁶​`■体重 単位はg`

読めることは読めますが、今後のデータ処理を進めるうえで不安が残ります。

2.1.2.1 スペースや記号などを自動的に変換してくれる関数できれいに

janitorパッケージのclean_names()関数を使って、列名に入り込んでいるスペースや記号などを安全な記号に変換します。

なお、日本語の列名では、clean_names()関数にcase = "old_janitor"をつけないと読みにくい結果になります。このように、関数の中に追加する情報のことを引数(ひきすう)と言います。引数によってさまざまな条件を変更することが可能になります。

read_xlsx("data/ペンギン(ひどい列名)ver.xlsx") |> 
  clean_names(case = "old_janitor")
## # A tibble: 344 × 9
##   speci…¹ 種_類 x_島…²  x_ク…³ x_クチバ…⁴ 翼_長…⁵ x_体…⁶ x     
##   <chr>       <chr> <chr>    <dbl>    <dbl>   <dbl>  <dbl> <chr> 
## 1 Adelie      アデ… Torger…   39.1     18.7     181   3750 male  
## 2 Adelie      アデ… Torger…   39.5     17.4     186   3800 female
## 3 Adelie      アデ… Torger…   40.3     18       195   3250 female
## # … with 341 more rows, 1 more variable:
## #   2007_2009 <dbl>, and abbreviated variable names
## #   ¹​species, ²​x_島の名前, ³​x_クチバシ_長さ_mm,
## #   ⁴​x_クチバシ_大きさ_mm, ⁵​翼_長さ_mm, ⁶​x_体重_単位はg

さて、ここで使われている |> は非常に大事なので解説しておきます。

2.1.2.2 |> とは?

「パイプ」と読みます10。処理を重ねてコードに書いていきたい際に重宝し、現代のtidyverseを使ったRのコードに欠かせないものです。まずtidyverseパッケージを読み込みます

たとえば、データフレームdfのspecies列を選択する、という処理の

select(df, species)

df |> select(species)

と書けます。 |>の左側にあるものを右側の最初の部分(第1引数)に渡すという働きです。パイプの利点は、いくつもつないで書いていけることです。たとえば、ペンギンの種類別にクチバシの長さの平均値を出したいときには次のようにできます。

df |> 
  group_by(species) |> 
  summarise(平均値 = mean(bill_length_mm, na.rm = TRUE))
## # A tibble: 3 × 2
##   species   平均値
##   <chr>      <dbl>
## 1 Adelie      38.8
## 2 Chinstrap   48.8
## 3 Gentoo      47.5

以下では|>を多用していきます。

なお、ショートカットctrl + shit + M(MacだとCmd + Shift + M)で出せます11

2.1.2.3 全角←→半角を自動で

stringiパッケージのstri_trans_nfkc()関数を使って、変数名で全角-半角のばらつきを統一させます。stringiパッケージは本書ではここでしか使わないので,一時的にパッケージから関数を呼び出す処理としてパッケージ名::関数名()を使います。

read_xlsx("data/ペンギン(ひどい列名)ver.xlsx") |> 
  rename_with(~stringi::stri_trans_nfkc(.))
## # A tibble: 344 × 9
##   Species `種 類`  ※島の…¹  1クチ…² 2クチ…³ 翼:長…⁴ ■体…⁵ 女男  
##   <chr>   <chr>    <chr>      <dbl>   <dbl>   <dbl> <dbl> <chr> 
## 1 Adelie  アデリー Torgers…    39.1    18.7     181  3750 male  
## 2 Adelie  アデリー Torgers…    39.5    17.4     186  3800 female
## 3 Adelie  アデリー Torgers…    40.3    18       195  3250 female
## # … with 341 more rows, 1 more variable: `2007~2009` <dbl>, and
## #   abbreviated variable names ¹​`※島の名前`,
## #   ²​`1クチバシ 長さ(mm)`, ³​`2クチバシ_大きさ(mm)`,
## #   ⁴​`翼:長さ(mm)`, ⁵​`■体重 単位はg`

ここでは、変数名をリネームするのにdplyr 1.0.0で登場したrename_with()関数を使いました。デフォルトで全列対象の.cols = everything()という引数が含められているので、すべての変数に対し、全角文字を含んでいたら半角に直すというコードになります。

2.1.2.4 上記の合わせ技

|> でつなぎ合わせて1つの実行で合わせてしまうこともできます。

read_xlsx("data/ペンギン(ひどい列名)ver.xlsx") |> 
  rename_with(~stringi::stri_trans_nfkc(.)) |> 
    clean_names(case = "old_janitor")
## # A tibble: 344 × 9
##   species 種_類    x_島の…¹ x1ク…² x2クチ…³ 翼_長…⁴ x_体…⁵ 女男  
##   <chr>   <chr>    <chr>     <dbl>    <dbl>   <dbl>  <dbl> <chr> 
## 1 Adelie  アデリー Torgers…   39.1     18.7     181   3750 male  
## 2 Adelie  アデリー Torgers…   39.5     17.4     186   3800 female
## 3 Adelie  アデリー Torgers…   40.3     18       195   3250 female
## # … with 341 more rows, 1 more variable: x2007_2009 <dbl>, and
## #   abbreviated variable names ¹​x_島の名前, ²​x1クチバシ_長さ_mm,
## #   ³​x2クチバシ_大きさ_mm, ⁴​翼_長さ_mm, ⁵​x_体重_単位はg

2.1.3 開始行を指定して読み込む

理想的なデータは1行目に列名が入力されている形ですが、最初の数行が空だったり、文字の説明が入っていたりすることも多いです。そうした場合は、以下のような読み込み結果になります。

read_xlsx("data/ペンギン(3行空き).xlsx") |> 
  select(1:3) # 紙面の都合のため最初の3列に制限
## # A tibble: 346 × 3
##   ...1    ここに説明とか書いてあるファイル読むのつらいの…¹ ...3  
##   <chr>   <chr>                                            <chr> 
## 1 <NA>    <NA>                                             <NA>  
## 2 species island                                           bill_…
## 3 Adelie  Torgersen                                        39.1  
## # … with 343 more rows, and abbreviated variable name
## #   ¹​ここに説明とか書いてあるファイル読むのつらいのです

列名が、セルに内容が入っている行から始まり、他の列名が...1, ...3といったものになりました。そしてデータがうまく読み込めていません。これを、指定した行から読み込むには、引数skip =にとばしたい行の数を指定します。

read_xlsx("data/ペンギン(3行空き).xlsx", skip = 3)
## # A tibble: 344 × 9
##   species island    bill_le…¹ bill_…² flipp…³ body_…⁴ sex    year
##   <chr>   <chr>         <dbl>   <dbl>   <dbl>   <dbl> <chr> <dbl>
## 1 Adelie  Torgersen      39.1    18.7     181    3750 male   2007
## 2 Adelie  Torgersen      39.5    17.4     186    3800 fema…  2007
## 3 Adelie  Torgersen      40.3    18       195    3250 fema…  2007
## # … with 341 more rows, 1 more variable: 種類 <chr>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g

このように、ちゃんと読む込むことができました。

2.1.4 セルを指定して読み込む

引数range =にセル範囲を指定すれば、そのセル範囲だけを読み込むこともできます。

read_xlsx("data/ペンギン.xlsx", range = "A1:D5")
## # A tibble: 4 × 4
##   species 種類     island    bill_length_mm
##   <chr>   <chr>    <chr>              <dbl>
## 1 Adelie  アデリー Torgersen           39.1
## 2 Adelie  アデリー Torgersen           39.5
## 3 Adelie  アデリー Torgersen           40.3
## 4 Adelie  アデリー Torgersen           NA

他にも、cell_cols =で読みたい列の指定、cell_rows =で読みたい行の指定も行えます。

詳細は、?readxlと打ち込んでヘルプを見るか、readxlのwebサイト 12を参照してください。

2.2 シートを指定して読み込む

2.2.1 シート名の確認

複雑なExcelファイルとなると、たくさんのシートが含まれていて、その全容を知るのも一苦労です。Rでは、readxlパッケージのexcel_sheets()関数でシート名の一覧を簡単に取得できます。

excel_sheets("data/ペンギン(シート別).xlsx")
## [1] "アデリー"   "ジェンツー" "ヒゲ"

2.2.2 普通の読み込み

シートが分かれているExcelファイルをそのまま読みこんでみます。

read_xlsx("data/ペンギン(シート別).xlsx")
## # A tibble: 152 × 9
##   species 種類     island   bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>   <chr>    <chr>      <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Adelie  アデリー Torgers…    39.1    18.7     181    3750 male 
## 2 Adelie  アデリー Torgers…    39.5    17.4     186    3800 fema…
## 3 Adelie  アデリー Torgers…    40.3    18       195    3250 fema…
## # … with 149 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g

デフォルトでは一番最初のシートのデータが読みこまれます。ここでは、シート「アデリー」が読み込まれました。

2.2.3 シートを指定した読み込み

引数のsheet =にシート名を指定することで読み込めます。

read_excel("data/ペンギン(シート別).xlsx", sheet = "ジェンツー" )
## # A tibble: 124 × 9
##   species 種類       island bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>   <chr>      <chr>    <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Gentoo  ジェンツー Biscoe    46.1    13.2     211    4500 fema…
## 2 Gentoo  ジェンツー Biscoe    50      16.3     230    5700 male 
## 3 Gentoo  ジェンツー Biscoe    48.7    14.1     210    4450 fema…
## # … with 121 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g

2.2.4 すべてのシートから一気に読み込み

今まで身につけた知識を使うと、すべてのシートからデータを読みたいときは、単純に

df_Adelie <- 
  read_excel("data/ペンギン(シート別).xlsx", sheet = "アデリー" )
df_Gentoo <- 
  read_excel("data/ペンギン(シート別).xlsx", sheet = "ジェンツー" )
df_Chinstrap <- 
  read_excel("data/ペンギン(シート別).xlsx", sheet = "ヒゲ" )

と1つずつ読み込めばよいとわかります。しかし、これが100シート分あったら読むだけで多くの時間がかかり、うんざりしてしまうでしょう。また、疲労によりミスも起こるかもしれません。コードも長くて読みにくくなってしまいます。そんな時に便利で正確で短くコードが書ける素敵な方法があるのです。おそらくこれを知って使えるようになることが、初心者から中級者への第一歩になるのではないでしょうか。

ここで一気にレベルが上がりますが、これこそがRを使ってExcelファイルを読み込む便利な部分(その用途に限らず、コード書いてコンピュータに働いてもらうの最高!ってなる部分)なので、その魅力をみていきましょう。

path_name <- "data/ペンギン(シート別).xlsx" # データのパスを格納

# シート名を取得しそれぞれから読み込んでリストにまとめる
df_list <-
  excel_sheets(path_name) |>                     
  set_names() |>           # 名前付きベクトルにする
  map(read_excel, path =  path_name)

df_list # 作成したリストの表示
## $アデリー
## # A tibble: 152 × 9
##   species 種類     island   bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>   <chr>    <chr>      <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Adelie  アデリー Torgers…    39.1    18.7     181    3750 male 
## 2 Adelie  アデリー Torgers…    39.5    17.4     186    3800 fema…
## 3 Adelie  アデリー Torgers…    40.3    18       195    3250 fema…
## # … with 149 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g
## 
## $ジェンツー
## # A tibble: 124 × 9
##   species 種類       island bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>   <chr>      <chr>    <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Gentoo  ジェンツー Biscoe    46.1    13.2     211    4500 fema…
## 2 Gentoo  ジェンツー Biscoe    50      16.3     230    5700 male 
## 3 Gentoo  ジェンツー Biscoe    48.7    14.1     210    4450 fema…
## # … with 121 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g
## 
## $ヒゲ
## # A tibble: 68 × 9
##   species   種類  island bill_len…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>     <chr> <chr>       <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Chinstrap ヒゲ  Dream        46.5    17.9     192    3500 fema…
## 2 Chinstrap ヒゲ  Dream        50      19.5     196    3900 male 
## 3 Chinstrap ヒゲ  Dream        51.3    19.2     193    3650 male 
## # … with 65 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g

それぞれのExcelシートから読みこまれた3つのデータ(アデリー、ジェンツー、ヒゲ)はデータフレームとして、df_listにリストと呼ばれる形式にてまとめて格納されています。リストは最初は理解が難しいですが、慣れるとなんでもリストにしたくなるくらい便利なものです。リストの中身を個別に取り出してみてみましょう。

df_list$ジェンツー
## # A tibble: 124 × 9
##   species 種類       island bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>   <chr>      <chr>    <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Gentoo  ジェンツー Biscoe    46.1    13.2     211    4500 fema…
## 2 Gentoo  ジェンツー Biscoe    50      16.3     230    5700 male 
## 3 Gentoo  ジェンツー Biscoe    48.7    14.1     210    4450 fema…
## # … with 121 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g

これは、df_listというリストの中の、ジェンツーという要素(ここではデータフレーム)を取り出す、というコードです。$が「(左側にくるオブジェクト)の中の」という意味を表しています。自分でコードを打つと、df_list$と打った時点で、中の要素の一覧が表示されるはずなので、そこからクリックして選ぶこともできます。

それでは、先ほど実行した読み込みコードの解説をします。

path_name <- "data/ペンギン(シート別).xlsx"

これは、単にファイルの場所をpath_nameに格納しただけです。自分のデータで試してみたいときは、基本的にここのパス名を変えるだけで実行できるはずです。

df_list <-
  excel_sheets(path_name) |>                    
  set_names() |>                           
  map(read_excel, path =  path_name) 

excel_sheets()は上で実行したのと同じです。実行結果はベクトルとして保存されています。set_names()は、ベクトルを名前付きベクトルにする働きをします。なので、ここでできるのは、

excel_sheets(path_name) |>                    
  set_names()
##     アデリー   ジェンツー         ヒゲ 
##   "アデリー" "ジェンツー"       "ヒゲ"

です。

それぞれについてpurrrパッケージのmap()関数を使ってread_excel()を1つ1つのシート(ここでは作成した名前付きベクトルの要素)に適用していき、データを読み込みデータフレームにし、1つのリストにまとめるという作業をします。繰り返し似たような作業をするときに、このmap()関数が非常に便利です。

2.2.4.1 一つのデータフレームにする

bind_rows()は、データフレームを縦に連結します。データフレームがリストになったものが引数にくると、それらをすべて縦につなげてくれます。引数.id =で、リストの要素名を変数の値として入れることができるので、どのデータフレームから来たのか識別することが可能になります。ここではgroupという名前にしています。

df_all <- 
  bind_rows(df_list, .id = "group")

2.2.4.2 作成したデータフレームの確認

最初の3行と最後の3行だけを表示してどんなものができたか確認します。dplyrパッケージのslice_head(), slice_tail()関数を使って、引数n =に表示したい行数を指定することで、最初および最後の数行を取得できます。

# 最初の3行
df_all |> slice_head(n = 3)
## # A tibble: 3 × 10
##   group    species 種類    island bill_…¹ bill_…² flipp…³ body_…⁴
##   <chr>    <chr>   <chr>   <chr>    <dbl>   <dbl>   <dbl>   <dbl>
## 1 アデリー Adelie  アデリ… Torge…    39.1    18.7     181    3750
## 2 アデリー Adelie  アデリ… Torge…    39.5    17.4     186    3800
## 3 アデリー Adelie  アデリ… Torge…    40.3    18       195    3250
## # … with 2 more variables: sex <chr>, year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g
# 最後の3行
df_all |> slice_tail(n = 3)
## # A tibble: 3 × 10
##   group species   種類  island bill_len…¹ bill_…² flipp…³ body_…⁴
##   <chr> <chr>     <chr> <chr>       <dbl>   <dbl>   <dbl>   <dbl>
## 1 ヒゲ  Chinstrap ヒゲ  Dream        49.6    18.2     193    3775
## 2 ヒゲ  Chinstrap ヒゲ  Dream        50.8    19       210    4100
## 3 ヒゲ  Chinstrap ヒゲ  Dream        50.2    18.7     198    3775
## # … with 2 more variables: sex <chr>, year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g

一気にやるにはslice()関数が便利です。1:3は1行目から3行目、(n()-2):n()は、列数(ただし現在のgroup内)を表すn()とそれから-2行した(n()-2)で表されています。

df_all |> 
  slice(1:3, (n()-2):n())
## # A tibble: 6 × 10
##   group    species   種類  island bill_…¹ bill_…² flipp…³ body_…⁴
##   <chr>    <chr>     <chr> <chr>    <dbl>   <dbl>   <dbl>   <dbl>
## 1 アデリー Adelie    アデ… Torge…    39.1    18.7     181    3750
## 2 アデリー Adelie    アデ… Torge…    39.5    17.4     186    3800
## 3 アデリー Adelie    アデ… Torge…    40.3    18       195    3250
## 4 ヒゲ     Chinstrap ヒゲ  Dream     49.6    18.2     193    3775
## 5 ヒゲ     Chinstrap ヒゲ  Dream     50.8    19       210    4100
## 6 ヒゲ     Chinstrap ヒゲ  Dream     50.2    18.7     198    3775
## # … with 2 more variables: sex <chr>, year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g

2.3 複数のExcelファイルを読み込む

それでは、さらにRの恩恵を深く実感できる部分に入ります。読みこみたいExcelファイルが大量にある場合です。これも実務上よく遭遇します。やり方としては、2.2.4で使った方法とほぼ同じです。

ただし、ここでは読み込むファイルの構造がすべて同様の場合に限ります。残念ながら、それがかなわない状況に、現実ではたくさん遭遇します。いつか本書の応用編を書くことがあったら、そちらで解説することとして、今回は構造が単純な場合に限って解説します。

おそらく、単純に思いつく方法は、

df_Adelie    <- read_xlsx("data/複数/アデリー.xlsx")
df_Gentoo    <- read_xlsx("data/複数/ジェンツー.xlsx")
df_Chinstrap <- read_xlsx("data/複数/ヒゲ.xlsx")

と1つずつ読んでいく方法ですが、これも大量にあったら泣きたくなる作業です。1つ1つファイル名を入力やコピペする間にいくらでもミスが生じます。2.1.1.1で紹介した自動補完を使っても、楽しいのは最初だけでしょう。そこで、ファイルを指定するところから極力人の手を介さず進めていく方法を次に解説していきます。

2.3.1 読み込むファイル名の一覧のオブジェクト作成

まず、読み込みたいファイルが格納されているフォルダのファイル名、およびパス名の一覧を取得します。

files <-
    list.files(path = "data/複数/", full.names = TRUE)

files
## [1] "data/複数/Adelie.csv"      "data/複数/Chinstrap.csv"  
## [3] "data/複数/Gentoo.csv"      "data/複数/アデリー.xlsx"  
## [5] "data/複数/ジェンツー.xlsx" "data/複数/ヒゲ.xlsx"      
## [7] "data/複数/フォルダ1"       "data/複数/フォルダ2"      
## [9] "data/複数/フォルダ3"

list.files()関数は、path =で指定したフォルダ内の情報を取得します。full.names = TRUEでパスも含めます。これをつけないと、ファイル名と拡張子だけの取得になります。

このうち、使用するのはxlsxファイルだけなので、文字列で該当するデータを取得するstr_subset()を用い、以下のように限定します。

files <- 
  files |> str_subset("xlsx")

files
## [1] "data/複数/アデリー.xlsx"   "data/複数/ジェンツー.xlsx"
## [3] "data/複数/ヒゲ.xlsx"

2.3.2 ファイルを一括で読み込む

ldata <-
    map(files, ~read_xlsx(.))

ldata
## [[1]]
## # A tibble: 152 × 9
##   species 種類     island   bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>   <chr>    <chr>      <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Adelie  アデリー Torgers…    39.1    18.7     181    3750 male 
## 2 Adelie  アデリー Torgers…    39.5    17.4     186    3800 fema…
## 3 Adelie  アデリー Torgers…    40.3    18       195    3250 fema…
## # … with 149 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g
## 
## [[2]]
## # A tibble: 124 × 9
##   species 種類       island bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>   <chr>      <chr>    <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Gentoo  ジェンツー Biscoe    46.1    13.2     211    4500 fema…
## 2 Gentoo  ジェンツー Biscoe    50      16.3     230    5700 male 
## 3 Gentoo  ジェンツー Biscoe    48.7    14.1     210    4450 fema…
## # … with 121 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g
## 
## [[3]]
## # A tibble: 68 × 9
##   species   種類  island bill_len…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>     <chr> <chr>       <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Chinstrap ヒゲ  Dream        46.5    17.9     192    3500 fema…
## 2 Chinstrap ヒゲ  Dream        50      19.5     196    3900 male 
## 3 Chinstrap ヒゲ  Dream        51.3    19.2     193    3650 male 
## # … with 65 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g

ここでできたldataは、2.2.4で作成したdf_listと同じ構造です。違いはそれぞれのデータフレームの要素名(アデリー、ジェンツー、ヒゲ)が入っていない点です。各要素の上の部分にある名前が[[1]], [[2]], [[3]]と表示されています(つまり、1, 2, 3の数値が割り当てられている)。要素名が入っていないのは不便なので、以下で要素名を改めてつけます。

2.3.2.1 ファイル名抽出

先ほど作成したfilesから、ファイル名部分だけに加工します。str_replace()は、stringrパッケージの、文字の置換をする関数です。ここでは、拡張子とパス名をそれぞれ""、つまり空白に置換しています。

file_name <- 
  str_replace(files, ".xlsx", "") |> 
  str_replace("data/複数/", "")

file_name
## [1] "アデリー"   "ジェンツー" "ヒゲ"

2.3.2.2 リストの要素名にファイル名を付与

2.2.4で使ったset_names()関数は、リストの要素名を付ける時にも使えます。リストldataの3つの要素に、file_nameの中身を割り当てます。

ldata <-
    set_names(ldata, file_name)

ldata
## $アデリー
## # A tibble: 152 × 9
##   species 種類     island   bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>   <chr>    <chr>      <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Adelie  アデリー Torgers…    39.1    18.7     181    3750 male 
## 2 Adelie  アデリー Torgers…    39.5    17.4     186    3800 fema…
## 3 Adelie  アデリー Torgers…    40.3    18       195    3250 fema…
## # … with 149 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g
## 
## $ジェンツー
## # A tibble: 124 × 9
##   species 種類       island bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>   <chr>      <chr>    <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Gentoo  ジェンツー Biscoe    46.1    13.2     211    4500 fema…
## 2 Gentoo  ジェンツー Biscoe    50      16.3     230    5700 male 
## 3 Gentoo  ジェンツー Biscoe    48.7    14.1     210    4450 fema…
## # … with 121 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g
## 
## $ヒゲ
## # A tibble: 68 × 9
##   species   種類  island bill_len…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>     <chr> <chr>       <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 Chinstrap ヒゲ  Dream        46.5    17.9     192    3500 fema…
## 2 Chinstrap ヒゲ  Dream        50      19.5     196    3900 male 
## 3 Chinstrap ヒゲ  Dream        51.3    19.2     193    3650 male 
## # … with 65 more rows, 1 more variable: year <dbl>, and
## #   abbreviated variable names ¹​bill_length_mm, ²​bill_depth_mm,
## #   ³​flipper_length_mm, ⁴​body_mass_g

このように、ちゃんと要素に名前が付きました。これらを1つのデータフレームにまとめるには、 2.2.4.1と同じ手順でできます。

bind_rows(ldata, .id = "group")

2.3.3 読み込むファイルが複数フォルダにある場合

data/複数フォルダの中に、さらにフォルダ1~フォルダ3がありました。この中にもそれぞれxlsxファイルが入っていて、それぞれ読み込みたいとします。その場合は、先ほど使ったlist.files()関数の引数、recursive = TRUEを追加します。これによって、フォルダの深い階層までもすべて読み込むことが可能になります。

files <-
    list.files(path = "data/複数/", full.names = TRUE, recursive = TRUE)

files
## [1] "data/複数//フォルダ1/アデリー.xlsx"  
## [2] "data/複数//フォルダ2/ジェンツー.xlsx"
## [3] "data/複数//フォルダ3/ヒゲ.xlsx"      
## [4] "data/複数/Adelie.csv"                
## [5] "data/複数/Chinstrap.csv"             
## [6] "data/複数/Gentoo.csv"                
## [7] "data/複数/アデリー.xlsx"             
## [8] "data/複数/ジェンツー.xlsx"           
## [9] "data/複数/ヒゲ.xlsx"

このうち、使用するのはフォルダ1~3に入っているxlsxファイルだけなので、str_subset()関数で以下のように絞り込みます。ここの""の中に入る文字列がどうなるかが難しいところかもしれませんが、ここは正規表現という本書の範囲を超える世界なので、深入りはしません。

files <- 
  files |> str_subset("フォルダ")

あとは2.3.2と同じ手順で読み込めます。