Rのデータ型
Rのすべての値は、少数の原子型のいずれかを持ちます。そのうち4つがほとんどの仕事をこなします。
- double — 小数:
3.14、-2、1e6。Rが「numeric」と言うときはこれを指し、入力した数値の既定の型でもあります。 - integer — 正確に保存される整数。
Lを付けて42Lのように書きます。 - character — 引用符で囲んだテキスト:
"hello"。 - logical — 2つの真理値
TRUEとFALSE(および欠損値NA。欠損値を参照)。
信号処理の計算などでたまに使う complex(2 + 3i)もありますが、何年も必要にならないこともあります。値の型は typeof() で調べられます。
1行目に注目してください。整数に見える数値でも、素の数値は double です。typeof(42) は "double" で、integer になるのは 42L だけです。日々の分析でこの違いが問題になることはほとんどありません(Rが静かに変換してくれます)が、typeof() の一見不可解な出力の多くはこれで説明がつきます。
typeof() と class():なぜ食い違うのか
Rには「これは何?」に答えているように見える関数が2つあり、それぞれ微妙に違う問いに答えています。
typeof()は保存上の型を報告します。値がメモリ上でどうなっているか。class()は振る舞い上の型を報告します。たとえばどのprintやsummaryを実行するかを決める、Rのメソッドディスパッチが使うラベルです。
単純な値では、答えの違いは語彙だけです。
typeof() は double(保存)と答え、class() は numeric(振る舞い)と答えます。構造を持つものでは、その差はさらに広がります。
この行列は素の整数ベクトルとして保存されていますが、行列として振る舞います。グリッドとして表示するようRに伝えているのが class() です。同じ分裂はデータフレーム(typeof は "list"、class は "data.frame")や日付(typeof は "double"、class は "Date")でも見られます。
実務的なルールはこうです。日常的な意味で「これは何なのか」を知りたいときは class()、Rが裏で何をしているかをデバッグしたいときは typeof()。
is.*() による型の確認
各型には TRUE か FALSE を返す対応する述語関数があります。入力を検証する関数の中で重宝します。
知っておく価値のある罠がひとつ。is.numeric() は double と integer の両方で TRUE になりますが(どちらも数値なので)、is.integer() は保存形式を確認するため、素の 42 では FALSE になります。
数学的には明らかに整数である数値に対して is.integer(7) が FALSE になることに驚いた経験があるなら、理由はこれです。7 は double、7L が integer なのです。
as.*() による型の変換
明示的な変換には as.* の関数群を使います。変換先の型ごとに1つずつあります。
覚えておくべき挙動が2つあります。as.integer() は四捨五入ではなくゼロ方向に切り捨てます。7.9 は 7 になります。そして変換に意味がないとき、Rはエラーを投げず、NA を返して警告を出します。
実行すると NA と "NAs introduced by coercion" の警告が表示されます。これは本当に便利な挙動です。乱雑なテキストの列をまるごと数値に変換したとき、解析できない項目はスクリプトを落とすのではなく NA になります。しかし同時に、静かに NA がデータに紛れ込む可能性があるということでもあります。変換が重要な場面では、後から新しい NA が生じていないか確認しましょう。
logical と数値の相互変換は期待どおりです。as.numeric(TRUE) は 1、as.logical(0) は FALSE。だからこそ logical ベクトルの sum() は TRUE の個数を数えてくれます。
暗黙の型強制:ベクトルの「1つの型」ルール
Rの原子ベクトルは1つの型しか保持できません。c() で異なる型の値を組み合わせると、Rはその中で最も柔軟な型へ、決まったはしごに従ってすべてを静かに格上げします。
logical → integer → double → character
logical は 1 と 0 になり、integer は double になり、最後の行ではすべてがテキストになりました。どんな値も文字列として書けるので、character が常に勝ちます。typeof() で確認できます。
型強制は「なぜ私の列がテキストになっているのか」というバグの最大の原因です。数値の列に紛れ込んだ "N/A" という文字列ひとつで、ベクトル全体が character に強制されます。そうなったら、まず問題の値を直し、それから as.numeric() で戻しましょう。
この記事のまとめ
- 主力の型は4つ:double(「numeric」)、integer(
42L)、character、logical。 typeof()は保存のされ方、class()は振る舞い方。3.14はnumericとして振る舞うdoubleです。- 確認は
is.numeric()などで、変換はas.numeric()などで。変換に失敗すると、エラーではなく警告付きのNAが返ります。 - ベクトルが持てる型は1つだけで、混ぜると logical → integer → double → character の順に強制されます。
次は数値型をもっと詳しく——丸め、数学関数、そしてどの言語にも共通する浮動小数点の意外な挙動を見ていきます。
よくある質問
Rの基本的なデータ型は何ですか?
原子型は double(小数、Rが「numeric」と呼ぶもの)、integer(42L のように L を付けて書く整数)、character(引用符で囲んだテキスト)、logical(TRUE/FALSE)、そしてめったに使わない complex です。ベクトル、データフレーム、リストなど、それより大きなものはすべてこれらから作られています。
Rのtypeof()とclass()の違いは何ですか?
typeof() は値がメモリ上でどう保存されているか(低水準の型)を報告し、class() はその値がどう振る舞うか——Rがどのメソッドをディスパッチするかを決めるもの——を報告します。単なる小数では言い方が食い違い、typeof(3.14) は "double"、class(3.14) は "numeric" です。データフレームのような構造では、typeof() が "list"、class() が "data.frame" と答えます。
Rで型を変換するには?
as.* の関数群を使います。as.numeric("3.5") は 3.5、as.character(42) は "42"、as.integer(7.9) は切り捨てて 7 になります。変換が不可能なとき、Rはエラーではなく NA を返して警告を出します。as.numeric("abc") は NA です。
Rにおける型強制(coercion)とは何ですか?
1つのベクトルに異なる型を混ぜると、Rは logical → integer → double → character の順に従って、すべてを最も柔軟な型に静かに変換します。そのため c(1, 2, "three") は文字列ベクトル "1" "2" "three" になります。