4 csvファイルの読み込みと保存

windows環境で過ごしていて日本語を使うRユーザーにおいては、csvファイルを扱う際に文字コードの違いというつらみ(いわゆる文字化け)に遭遇することが少なくありません。

出会う可能性が高い文字コードには、大きくcp932(Shift-JIS)UTF-8という形式があり、一般的に業務で読みこもうとするファイルは前者であることが多いことを知っておくと役に立ちます。

4.1 一つのcsvファイルを読み込む

csvファイルを読みこむには、readrパッケージのread_csv()関数を使います。tidyverseを読み込んだら一緒に読み込まれます。readrでは基本的にutf8の読み書きが想定されています。RStudioのメニューで以下の部分をUTF-8に変えておかないと、色々つらい思いをします。

  • Tools > Global Options > Code > Saving > Default text encoding:
  • Tools > Project Options > Code Editing > text encoding:

data > csvフォルダ(ここでは>は階層関係を示し、コードではdata/csv/で表現)に入っている「ペンギン(ひどい列名)ver_utf8.csv」を開きます。㊛㊚列のみ、環境依存文字のため、csvにする時点で文字化けています…

4.1.1 UTF-8でエンコードされたcsvファイル

df_csv <- 
 read_csv("data/csv/ペンギン(ひどい列名)ver_utf8.csv")

df_csv
## # 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`

4.1.2 Shift-JISでエンコードされたcsvファイル

正確にはShift-JISの拡張版であるcp932でエンコードされたファイルです。Windowsで作られた過去のcsvファイルはこの形式であることが多いです。

4.1.2.1 【エラー例】

以下コードを実行するとエラーが出てきます。

read_csv("data/csv/ペンギン(ひどい列名)ver_cp932.csv")

Error in nchar(x, “width”) : invalid multibyte string, element 1

4.1.2.2 Shift-JISのcsvファイルの読み込み方

これを読むためには,引数locale = locale(encoding = )でShift-JISのファイルであることを指定する必要があります。

read_csv("data/csv/ペンギン(ひどい列名)ver_cp932.csv"
         , locale = locale(encoding = "cp932"))
## # A tibble: 344 × 9
##   Spec…¹ 種 …²  ※島…³   ①クチ…⁴ ②クチバ…⁵ 翼:…⁶ ■体重…⁷ `??`  
##   <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`

4.1.3 read.csv()を使う場合

従来のcsvを読む関数read.csv()を使う場合も同様です。R-4.2からはデフォルトでUTF-8を読むようになったため,Shift-JISのファイルを読むためには引数で指定する必要があります。

read.csv("data/csv/ペンギン(ひどい列名)ver_cp932.csv", 
         fileEncoding = "cp932") |>
    as_tibble()  # データフレームをtibble型にし見やすい出力に
## # A tibble: 344 × 9
##   Speci…¹ 種.類 X.島…²  X.ク…³ X.クチバ…⁴ 翼.長…⁵ X.体…⁶ X..   
##   <chr>       <chr> <chr>    <dbl>    <dbl>   <int>  <int> <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 <int>, and abbreviated variable names
## #   ¹​Species, ²​X.島の名前, ³​X.クチバシ.長さ.mm.,
## #   ⁴​X.クチバシ.大きさ.mm., ⁵​翼.長さ.mm., ⁶​X.体重.単位はg

UTF-8を読む場合はデフォルトで読めます。

read.csv("data/csv/ペンギン(ひどい列名)ver_utf8.csv") |> 
    as_tibble()
## # A tibble: 344 × 9
##   Speci…¹ 種.類 X.島…²  X.ク…³ X.クチバ…⁴ 翼.長…⁵ X.体…⁶ X..   
##   <chr>       <chr> <chr>    <dbl>    <dbl>   <int>  <int> <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 <int>, and abbreviated variable names
## #   ¹​Species, ²​X.島の名前, ³​X.クチバシ.長さ.mm.,
## #   ⁴​X.クチバシ.大きさ.mm., ⁵​翼.長さ.mm., ⁶​X.体重.単位はg

4.1.4 大きいデータならfread()

これまで紹介したcsvファイルを読みこむための関数は、小規模なデータならそんなに時間はかかりませんが、データが数万行×数百列と大きくなってくると、時間がかかるようになります。

そこで大きく時間を短縮できるのが、data.tableパッケージのfread()関数です。

UTF-8を読む場合はデフォルトで読めます。data.frame形式にするには引数にdata.table = FALSEをつけます

data.table::fread("data/csv/ペンギン(ひどい列名)ver_utf8.csv",
                  data.table = FALSE) |> 
  as_tibble()
## # A tibble: 344 × 9
##   Spe…¹ `種 類` ※島…²   ①クチ…³ ②クチバ…⁴ 翼:…⁵ ■体重…⁶ `㊛㊚`
##   <chr>   <chr>    <chr>     <dbl>   <dbl>  <int>   <int> <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` <int>, and abbreviated variable names
## #   ¹​Species, ²​`※島の名前`, ³​`①クチバシ 長さ(mm)`,
## #   ⁴​`②クチバシ_大きさ(mm)`, ⁵​`翼:長さ(mm)`,
## #   ⁶​`■体重 単位はg`

R4.2からは,Shift-JISのファイルを読むと日本語が文字化けするようになってしまいました。現在の所,これは対処不可能みたいです。

4.1.5 大きいデータを読む場合のvroom

readrを速くしたようなパッケージにvroom[https://vroom.r-lib.org/]があります。しばらくは別々に開発が進むみたいですが,将来的に統合が考えられてるらしいです。shift-jisの大規模csvファイルを読む際のfreadに代わる選択肢として有望です

vroom::vroom("data/csv/ペンギン(ひどい列名)ver_utf8.csv")
## # 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`

Shift-JISのファイルはreadrと同じように引数で指定します

vroom::vroom("data/csv/ペンギン(ひどい列名)ver_cp932.csv",
             locale = locale(encoding = "cp932"))
## # A tibble: 344 × 9
##   Spec…¹ 種 …²  ※島…³   ①クチ…⁴ ②クチバ…⁵ 翼:…⁶ ■体重…⁷ `??`  
##   <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`

4.2 複数のcsvファイルを読み込む

2.3で紹介した方法で,読み込みの関数をread_csv()に変えるだけで同じことができますが,もっと簡単な方法もあります。

まず,csvファイルのパス一覧を取得します。

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

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

files
## [1] "data/複数/Adelie.csv"    "data/複数/Chinstrap.csv"
## [3] "data/複数/Gentoo.csv"

この3つのcsvファイルを一気に読み込んで縦につなげたいとします。

これは,read_csv()の第一引数にパス一覧オブジェクトを入れ,id =引数にファイル名の情報を示す列の名前(ここではfile_name)を決めるだけです。

`

read_csv(files, id = "file_name")
## # A tibble: 344 × 9
##   file_name  species island bill_…¹ bill_…² flipp…³ body_…⁴ sex  
##   <chr>      <chr>   <chr>    <dbl>   <dbl>   <dbl>   <dbl> <chr>
## 1 data/複数… Adelie  Torge…    39.1    18.7     181    3750 male 
## 2 data/複数… Adelie  Torge…    39.5    17.4     186    3800 fema…
## 3 data/複数… Adelie  Torge…    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

4.3 csvファイルの保存

csvファイルを保存するには、readrパッケージのwrite_csv()関数を使います。ただし、出力されたcsvファイルをExcelでそのまま開くとたぶん文字化けするので,インポートなどの操作が必要かもしれません。LibreOfficeのCalcであれば、最初にダイアログボックスが開いて読む文字コードを選べます。

4.3.1 write_csv()を使う

先ほど読みこんだdf_csvと、保存先を""中に指定します。

write_csv(df_csv, "out/df_csv_utf8.csv")

4.3.1.1 Excelで開いても読めるように

Excelで開いても読める、BOM(byte order mark, バイトオーダーマーク)付きファイルとして出力する関数です。

write_excel_csv(df_csv, "out/df_csv_utf8_forxl.csv")