Rはファイルを読み込むときに、変数型の推定をしてデータフレームを作っています。このとき、実数として扱いたい列に数値として変換できない文字が1つでも混ざっていると、その列は丸ごと文字列型として推定されます。
その場合の基本手順は、列を数値変換できる値になるように加工した上で、as.double() などで型を変換することです。ただ、実際には列ごとに細かく加工しなくても、文字を含む数行だけ削除すれば十分なこともあります。その場合に困るのは実数型への変換です。なぜなら、 列によって実数にしたいか文字列のままにしたいかが異なるので、一括でループを回せない からです。
そこで、一括ループではなく「ファイル読み込みのように、データフレームを列ごとに適切に変換する処理」を行えると便利です。この記事では、その方法を紹介します。
実数に変換できない列が残る問題
例として、実数にしたいはずの列に文字が混ざっているデータがあるとします。
example <- matrix(
c("A-01", "ページビュー", "100", "200",
"A-02", "イベント数", "2500", "300",
"A-03", "継続割合", "0.8", "0.2",
"B-01", "参照", "N/A", "ok"),
ncol = 4
)
example
[,1] [,2] [,3] [,4]
[1,] "A-01" "A-02" "A-03" "B-01"
[2,] "ページビュー" "イベント数" "継続割合" "参照"
[3,] "100" "2500" "0.8" "N/A"
[4,] "200" "300" "0.2" "ok"
2行目に説明のための行が入っているため、全ての列が文字列型になってしまいます。
一括でループを回せない(列ごとに型が異なる)
2行目だけを削除した後、as.double()で実数型にしようとすると、列をそれぞれ指定する必要が出てきます。A-01〜A-03は実数型にしてよいですが、B-01は文字列のままにしたいからです。そのため全ての列を一括で変換することができませんが、列ごとの分岐を書くのも面倒です。
このようなとき、read.csv() がやっているような「列ごとに型を判断する変換」ができると便利です。
読み込み時の型推定を流用する
そこで、単純に「再度read.csv()を実行すればよい」という発想から、加工済みのデータを一時ファイルに書き出し、read.csv() で読み直すという方法が思い付きます。
example_df <- read.csv("文字を含むデータ.csv")
chr_df <- example_df[-1, ] # 1行目を削除(ヘッダーを含む実際のデータでは2行目)
temp <- tempfile() # Rのtempフォルダに一時ファイルを作成
write.csv(chr_df, temp, row.names = FALSE)
type_df <- read.csv(temp)
ところがこの方法だとデータと同じサイズの一時ファイルができてしまいますし、ファイル入出力を繰り返すのも効率が悪いので、もっと良いやり方がありそうです。
type.convert() で型推定を行う
実はファイル読み込み時の型推定は type.convert() が行っています。この関数はベクトルやデータフレームに対して列ごとに型を推定するので、加工済みのデータに対してそのまま呼ぶことができます。
type_df <- type.convert(chr_df, as.is = TRUE)
全要素が数値に変換できる列は numeric に、それ以外は character のままで返ります。as.is = TRUE にすると文字列は character のままになり、FALSEにするとfactorになります。(指定しないと警告が出ます)。
NA という文字は既定で NA に変換されますが、N/A のような表記は対象外です。それらをも欠損として扱いたい場合は na.strings 引数で指定できます。
type.convert(chr_df, na.strings = c("NA", "N/A"), as.is = TRUE)
変換後の型は str() で確認する
type.convert() の結果は列ごとの値に依存するため、変換後の型は必ず確認するのがおすすめです。
type_df <- type.convert(chr_df, as.is = TRUE)
str(type_df)
Rに列ごとの変換を任せられるのは便利ですが、意図しない型の推定が行われるリスクが伴います。
2026-01-01 のような日付文字列は Date に推定されず、character のまま
00123 のような先頭に0を持つ文字列は numeric になり、0 が失われる
1e5 のような指数表記も numeric になる
- 全要素が
TRUE や FALSE の場合、logical になる
データを読み込むときの基本ではありますが、意図しない推定が行われていないか常に確認しましょう。
まとめ
read.csv()の内部では型推定をtype.convert()で行っています。メモリ上のデータフレームの型を直したいときは、列ごとに型変換コードを書くのではなく、type.convert() で丸ごと処理するのが簡単です。
特に、いったんRにデータを取り込んでから行削除などして使いたい場合には有用です。似たような場面が出てきたら、使ってみてはいかがでしょうか。