Rが用意している演算子
Rの演算子は4つのグループに分かれます。算術(+ - * / ^ %% %/%)、比較(== != < <= > >=)、論理(& | && || ! xor)、そして所属判定の %in% です。多くの言語と違う点が2つあります。ほぼすべてがベクトル化されていて、ベクトル全体に要素ごとに作用すること。そして、互いに置き換えられない AND 演算子が2つ、OR 演算子が2つあることです。このページではそれらすべてに加え、静かに誤った答えを生む優先順位の落とし穴も扱います。
算術:+、-、*、/、^、%%、%/%
最初の5つは予想どおりに動きます。パーセントで囲まれた2つ——%%(剰余、余り)と %/%(整数除算、商)——が、よく検索されるものです。
/ は常に浮動小数点の除算を行うことに注意してください。17 / 5 は 3.4 であって、決して 3 にはなりません。整数部分が欲しいなら、そのための演算子が %/% です。
%% の日常的な仕事は割り切れるかの判定です。2で割って余りが出なければ偶数です。
2行目は立ち止まる価値があります。オペランドが負のとき、Rの %% は除数の符号を持つ結果を返します(-7 = -3 * 3 + 2 なので -7 %% 3 は 2)。逆の流儀の言語もあるので、コードを移植するときは確認しましょう。
比較演算子はベクトル化されている
==、!=、<、<=、>、>= は要素ごとに比較し、単一の答えではなく論理ベクトルを返します。
これがRのほぼすべての絞り込みを支えるエンジンです。ベクトル全体をある値と比較して論理マスクを得て、そのマスクで部分集合を取り出します。小数に == を使うときは1つ注意点があります。浮動小数点数は近似的に保存されるため、0.1 + 0.2 == 0.3 は FALSE になります。小数の比較には all.equal() を使うか、abs(x - y) < 1e-9 を確認しましょう。
論理演算子:& と &&(定番の混乱)
RにはAND演算子が2つ、OR演算子が2つあり、間違ったほうを選ぶのは通過儀礼のようなものです。
& と | はベクトル化されています。 2つの論理ベクトルを要素ごとに結合します。
データに対するフィルタを組み立てるときは常にこちらを使います。df[df$age > 30 & df$city == "Lisbon", ] のように。
&& と || はスカラー用で短絡評価します。 単一の値を取り、単一の TRUE/FALSE を返し、最初のオペランドで答えが決まれば2つ目をまったく評価しません。
2行目が短絡評価の実演です。x < 0 が FALSE なので、Rは stop() の呼び出しを一度も評価しません。&& が if() の条件にふさわしい理由がまさにこれです。if (!is.na(x) && x > 10) と書けば、x が NA のときに x > 10 の部分は安全に飛ばされます。
目安はこうです。ベクトルとデータの絞り込みには &/|、if() の条件には &&/||。 そしてR 4.3以降、これは厳格に強制されています。長さが1より大きいベクトルを && や || に渡すのはエラーです(古いバージョンのRは最初の要素だけを静かに使っており、それが何年も本当のバグを隠していました)。
xor(a, b) がこの一式を締めくくります。2つのうちちょうど一方がTRUEのときにTRUEになります。
%in%:所属の判定
x %in% table は x の各要素について「これは table のどこかに現れるか?」を問います。実務のRコードで最もよく使われる演算子のひとつです。
判定される側はベクトル全体でもよいので、%in% は許可された値の集合で行を絞り込む自然な道具になります。
代わりに書くことになる選択肢——| でつないだ == の連鎖——よりも優れています。
許可する値が5つになると == の連鎖は繰り返しの壁になりますが、%in% 版はベクトルが伸びるだけです。もうひとつ、より微妙な利点もあります。%in% は決して NA を返しません。
NA == 1 が NA になるのは、未知の値が1と等しいかをRが知りようがないからです(この挙動は欠損値で詳しく扱っています)。そしてその NA は、たどり着いた if() を汚染します。%in% は常に TRUE か FALSE を返すことでこの問題全体を回避します。欠損の可能性があるデータの条件判定で、より安全な選択肢である理由です。
優先順位の落とし穴
演算子の優先順位に関する2つの罠が、「Rが壊れている」と感じる瞬間の不釣り合いに大きな割合を占めています。1つ目は、^ が単項マイナスより強く結合すること。
2つ目は、コロンが二項算術より強く結合すること。
迷ったらかっこを足しましょう。コストはゼロですし、すべての読み手(未来のあなたを含む)がインタプリタと同じように読み取れます。
$ と [ ]:アクセス演算子
$、[ ]、[[ ]] も常に目にします。これらも厳密には演算子で、計算するのではなく構造から値を取り出すために使われます。
これらはベクトル、リスト、データフレームのページで詳しく扱います。ここでは同じ演算子ファミリーの一員だと認識できれば十分です。
この記事のまとめ
%%は余り、%/%は整数の商を返します。x %% 2 == 0で偶数を判定できます。- 比較はベクトル化されており、絞り込みに使える論理ベクトルを返します。
&/|はベクトルを要素ごとに結合し、&&/||はif()の中の単一の値向けで短絡評価します。R 4.3以降、長いベクトルに&&を使うのはエラーです。x %in% tableは==の連鎖を置き換え、決してNAを返しません。-2^2は-4で、1:n - 1は0から始まります。迷ったらかっこで囲みましょう。
次は、これらの演算子を if、else、ifelse() の中で働かせます。Rの条件分岐です。
よくある質問
Rの %% は何をしますか?
%% は剰余演算子で、割り算の余りを返します。17 %% 5 は 2 です。相方の %/% は整数除算を行い、余りを含まない商を返します。17 %/% 5 は 3 です。%% の定番の用途は偶数判定で、x %% 2 == 0 と書きます。
Rの & と && の違いは何ですか?
& はベクトル化されており、2つのベクトルを要素ごとに比較して同じ長さのベクトルを返します。&& は単一の値だけを扱い、短絡評価を行い(最初のオペランドで結果が決まれば2つ目を飛ばします)、TRUEかFALSEをちょうど1つ返します。ベクトルを絞り込むときは &、if() の条件の中では && を使いましょう。R 4.3以降、長さ1より大きいベクトルを && や || に渡すのは警告ではなくエラーです。
Rの %in% は何をしますか?
x %in% table は x の各要素が table のどこかに現れるかを判定し、要素ごとにTRUEかFALSEを返します。"mango" %in% basket は | でつないだ == の連鎖を置き換えられます。さらに == と違って決してNAを返さず、判定される側の欠損値は単にFALSEになります。
Rで -2^2 が -4 になるのはなぜ?
^ が単項マイナスより強く結合するため、Rは -2^2 を -(2^2) と読み、結果は -4 になります。マイナス2の2乗を意味したいなら (-2)^2 と書けば 4 になります。コロンにも似た落とし穴があり、1:n - 1 は 1:(n - 1) ではなく (1:n) - 1 を意味します。