3  オブジェクトと変数・定数

3.1 プログラミング言語としてのR

R言語は統計の計算を行うために開発されたプログラミング言語です。プログラミング言語としての仕様はS言語という、ベル研究所によって開発された言語を参考としています。R言語は、「動的型付け、型推論、インタプリタ型、オブジェクト指向の関数型言語」というタイプのプログラミング言語です。プログラミング未体験の方にはすべての単語が意味不明だと思いますが、単語の意味については順々に紹介していきます。

まずは、「インタプリタ」について説明します。インタプリタとは、プログラムをコンパイルすることなく実行することができる環境のことを指します。

この、「コンパイル」というのは、プログラムを機械語に置き換える変換のことを指します。

「機械語」というのも聞き覚えがない言葉だと思います。機械語とは、コンピュータが読み取れる、1と0だけからなる数字の列のことです。コンピュータは我々の言語や画像などをそのまま処理することはできず、1ビット単位(1と0)の情報だけを取り扱うことができます。プログラミング言語のうち、例えばCやJavaでは、プログラムはまず機械語に変換、コンパイルされます。コンパイルされたプログラムだけがコンピュータ上で実行できます(下図1)。

図1:コンパイルと機械語への変換

図1:コンパイルと機械語への変換

一方、インタプリタ型の言語では、プログラミング言語をコンパイルすることなく実行することができます。インタプリタ型の言語にはPythonRubyPHPなどがあります。コンパイルには通常時間がかかりますが、インタプリタ型言語ではコンパイルに時間をかけることなく、すぐにプログラムを実行することができるというメリットがあります。一方で、コンパイルを除いたプログラムを実行・完了するまでの時間はコンパイルを行うプログラミング言語よりも長くなるというデメリットもあります。

Rはインタプリタ型の言語ですので、記述したプログラム(スクリプトとも呼びます)はすぐに実行されます。一方で、Rでの計算速度はインタプリタ型言語の中でもかなり遅い部類に入ります。ただし、Rは主にad hocな(その場一回限りの)統計解析に用いられる言語です。1回限りであれば、それほど計算が早くなくても問題とはなりませんし、入力したプログラムがすぐに実行されるという性質も統計解析との相性がよいものです。コンピュータの性能も昔より遥かに高くなっており、R言語での計算が遅いと感じることは減ってきています。

3.2 オブジェクトとは?

Rはオブジェクト指向(Object oriented)の言語である、とされています。この「オブジェクト指向」という言葉はプログラミング言語ではよく用いられるものですが、厳密な定義は複雑です。

このオブジェクトというのは、プログラミングで取り扱う「もの」すべてを指す言葉です。プログラミングでは、数値文字などを取り扱い、数値の演算を行ったり、文字に対して検索や置換、文字の追加などを行います。このとき、取り扱う数値や文字はオブジェクト、つまりプログラミングで用いる「もの」であるということになります。Rでは数値や文字の他に、因子(factor)論理値(booleanまたはlogical)関数(function)などを取り扱います。これらのすべてがプログラミングで取り扱う「もの」、つまりオブジェクトです。

上で述べたように、プログラミングで用いるオブジェクトには数値、文字、因子、関数など、様々な種類のものがあります。数値も文字もプログラミングで扱う「もの」であることは共通していますが、数値と文字に対して同じ演算をしたい、ということは通常ありません。数値なら掛け算や割り算を行うことがあっても、文字に対して掛け算や割り算はしません。プログラミング言語も、数値なら数値の演算、文字なら文字の演算を行う必要があります。このように、数値なら数値の、文字なら文字の処理を行うために、オブジェクトには「型(type)」というものがあります。

型と演算の関係
1 * 1 # 数値同士を掛け算することがあっても、
## [1] 1

1 * "dog" # 数値と文字列を掛け算できてしまうと困る(エラーが出る)
## Error in 1 * "dog": non-numeric argument to binary operator

3.3 型(type)とは?

型(type)とは、そのオブジェクトの種類を定めるためのラベルのようなものです。例えば、Rで数値を入力すると、Rは自動的にその数値がnumericであると認識します。同様に、“(ダブルクオーテーション)で文字を囲うと、Rは自動的にその文字がcharacter(文字列型)であると認識します。Rはこの認識した型に従い、そのオブジェクトに対する演算を行います。

オブジェクトの型はmode関数で確認することができます。関数については後ほど詳しく説明します。

mode関数で型を確認する
mode(1) # 1は数値
## [1] "numeric"
mode("Hello world") # "Hello world"は文字列
## [1] "character"
mode("1") # "1"は文字列
## [1] "character"

上記のように、「1」の数字をmode()のカッコの中に入れると、numericが返ってきます。これは、1というオブジェクトの型がnumeric(数値)であることを示しています。同様に、ダブルクオーテーションで囲まれた"Hello world"mode()のカッコに入れると、characterが返ってきます。これは、"Hello world"の型がcharacter(文字列)であることを意味しています。では、ダブルクオーテーションで囲まれた"1"がどうなるかというと、これはcharacter、つまり文字列になります。

Rでは、このように「ダブルクオーテーションで囲まれている」というオブジェクトの状態を調べ、囲まれていればそのオブジェクトは文字列型であると判断します。同様に、オブジェクトが「数値でかつダブルクオーテーションに囲まれていない」場合には、そのオブジェクトが数値型であると判断します。このように、プログラム上でオブジェクトの型を特に指定していなくても、Rは自動的にそのオブジェクトの型を決定してくれます。このようなプログラムの性質を「型推論」と呼びます。

では、Rの代表的な型について、これから簡単に説明していきます。

3.3.1 文字列(character)

一般的なプログラミング言語で最も取り扱うことが多いオブジェクトは文字列型(character)です。文字列、つまり文章などを検索したり、一部を取り出したり、条件に合っているか確認したりすることはプログラミング利用の目的の一つとなります。

Rは統計学のプログラミング言語ですので、どちらかというと文字列よりは数値を取り扱うことが多いのですが、文字列を取り扱える仕組みも一通り備えています。

Rで文字列型のオブジェクトを作成するときには、"(ダブルクオーテーション)もしくは'(シングルクォーテーション)で文字を囲みます。ダブルクオーテーション・シングルクオーテーションのどちらを用いても文字列のオブジェクトを作成することはできます。クオーテーションが無い場合にはエラーとなります。

文字列オブジェクトの例
"Hello world" # ダブルクオーテーションで囲った場合

'Hello R' # シングルクオーテーションで囲った場合

Hello world # エラー
## Error: <text>:5:7: unexpected symbol
## 4: 
## 5: Hello world
##          ^

ダブルクオーテーションとシングルクオーテーションには違いはありません。どちらを用いても問題ないのですが、Rではダブルクオーテーションを用いるのが一般的です。

Rでは、文字列を入力すればその文字列がそのまま表示されますが、文字列の表示を明示したい場合にはprint関数を用います。

print関数
print("Hello world")
## [1] "Hello world"

3.3.1.1 エスケープ文字(エスケープシーケンス)

プログラミング言語によっては、ダブルクオーテーションとシングルクオーテーションでエスケープ文字(エスケープシーケンス)の取扱いに違いがある場合があります。エスケープシーケンスとは、バックスラッシュ(\、日本語キーボードでは¥)とアルファベットを組み合わせて、特定の意味を持たせる表現のことを指します。例えば、\nは改行を、\tはタブを示す記号です。RではC言語由来のエスケープシーケンスを利用できます。以下の表1にエスケープシーケンスの例を挙げます。

表1:エスケープシーケンスの例
エスケープシーケンス エスケープシーケンスの意味
\a アラート
\b バックスペース
\f ページ分割
\n 改行
\r キャリッジリターン
\t 水平タブ
\v 垂直タブ
\\ バックスラッシュ
\' シングルクオーテーション
\" ダブルクオーテーション

Rのデータをテキストファイルなどに書き出すときには、エスケープシーケンス、特に\n(改行)や\t(タブ)を用いることがあります。データ書き出しの際のエスケープシーケンスに関しては、13章で詳しく説明します。

エスケープシーケンスを変換した文字列を表示する場合には、writeLines関数を用います。

writeLines関数で文字列にエスケープシーケンスを反映
writeLines("Hello world")
## Hello world

writeLines("Hello\nworld") # \nは改行に変換
## Hello
## world

print("Hello\nworld") # print関数はエスケープシーケンスを変換しない
## [1] "Hello\nworld"

3.3.1.2 文字列を結合する

Rで文字列を用いるときに、文字列Aと文字列Bをくっつけたい、ということがあります。このようなときに用いるのが、paste関数です。paste関数はカッコの中に2つ以上の文字列をコンマでつないで入れると、文字列をスペースを挟んでつなぎ合わせてくれます。文字列の間にスペースが必要ない場合には、paste0関数を用います。

文字列をつなぐpaste関数
paste("Hello", "world")
## [1] "Hello world"

paste0("Hello", "R")
## [1] "HelloR"

文字列の取扱いに関しては、9章で詳しく説明します。

3.3.2 数値(numeric)

Rは統計の言語ですので、数値データを取り扱う機会が特に多くなります。グラフを記述したり、データを要約する場合にも主に取り扱うのは数値です。Rでは、数値はnumericという型を持ちます。

3.3.2.1 数値型のdouble(浮動小数点)とinteger(整数)

数値には更に詳細な型があります。詳細な型はtypeof関数で調べることができます。Rでの数値は通常doubleという型を持ちます。

数値にはdouble以外に、integer(整数)という型もあります。Rで整数型の数値を利用する時には、数字の後ろにLをつけます。また、数値であってもダブルクオーテーションで囲うと文字列 (character)になります。

double型とinteger型
mode(1) # modeでの型はnumeric
## [1] "numeric"

typeof(1) # これはdouble
## [1] "double"

typeof(1L) # これはinteger
## [1] "integer"

typeof("1") # これはcharacter
## [1] "character"

Rではintegerを取り扱う機会は非常に少なく、通常数値はdoubleとして取り扱います。

多くのプログラミング言語では、小数点を含む数値は、その精度(桁数)により、single(浮動小数点型)、double(倍精度浮動小数点型)などの型を持ちます。このsingleはdoubleよりオブジェクトのファイルサイズが小さい代わりに、あまり大きい桁数の数値は取り扱えないという特徴があります。Rにはsingleという型はありません。

3.3.2.2 クラス(class)

Rではオブジェクトは型以外に、クラス(class)という性質を別に持っています。Rでの数値型は、numeric(数値)というクラスを持ちます。クラスの確認にはclass関数を用います。

クラス、モードとtypeof関数
mode(1) # 型はnumeric
## [1] "numeric"

typeof(1) # typeofだとdouble
## [1] "double"

class(1) # クラスはnumeric
## [1] "numeric"

Rのオブジェクトは型だけでなく、アトリビュート(attribute)という性質を別に持っています。クラスはこのアトリビュートの一つです。オブジェクト指向プログラミングではクラスは非常に重要な意味を持ちますので、18章で詳しく説明します。

3.3.2.3 演算子(operator)

数値を扱う際には、四則演算等の計算を行うことがあります。この四則演算を行うための記号のことを、演算子と呼びます。Rでは以下の四則演算子を利用できます。

表2:Rで使える演算子
演算子 演算の種類
+ 足し算
- 引き算
* 掛け算
/ 割り算
%% 剰余(割り算の余り)
%/% 整数の割り算
^ 累乗

演算子それぞれの計算結果は以下のようになります。演算子の意味はExcelなどで用いられているものとほぼ同じです。

四則演算の例
3 + 2 # 足し算
## [1] 5

3 - 2 # 引き算
## [1] 1

3 * 2 # 掛け算
## [1] 6

3 / 2 # 割り算
## [1] 1.5

3 %% 2 # 剰余(余り)
## [1] 1

3 %/% 2 # 整数の割り算
## [1] 1

3^2 # 累乗
## [1] 9

数値については8章で詳しく説明します。

3.3.3 論理型(logical)

論理型(logical)は、TRUE(真)FALSE(偽)からなる2値の型です。TRUEとFALSEはその名の通り、その関係が正しいか、間違っているかを意味するものです。論理型はそのまま使用することもありますが、プログラミングでは比較演算子と共に用いることが多い型です。

3.3.3.1 比較演算子

比較演算子とは、演算子の右と左を比較して、その関係が正しい(TRUE)のか、間違っているのか(FALSE)を返す演算子です。比較演算子の例を以下に示します。

表3:Rで使える比較演算子
比較演算子 比較演算子の意味
== 等しい
!= 等しくない
< 小なり
<= 小なりイコール
> 大なり
>= 大なりイコール
& かつ
&& かつ
| または
|| または

&|は比較演算子同士を結びつけるための演算子(論理演算子)です。&&&|||の違いについては、4章で説明します。

比較演算子を用いた演算の例を以下に示します。比較演算子や論理型は主に条件分岐で用います。

比較演算子
1 == 1 # 等しいのでTRUE
## [1] TRUE
1 == 2 # 等しくないのでFALSE
## [1] FALSE

1 != 1 # 等しいのでFALSE
## [1] FALSE
1 != 2 # 等しくないのでTRUE
## [1] TRUE

1 < 2 # 2は1より小さいのでTRUE
## [1] TRUE
1 < 1 # 1は1より小さくないのでFALSE
## [1] FALSE

1 <= 2 # 2は1より小さいのでTRUE
## [1] TRUE
1 <= 1 # 1は1に等しいのでTURE
## [1] TRUE

3 > 2 # 3は2より大きいのでTRUE
## [1] TRUE
2 > 2 # 2は2より大きくないのでFALSE
## [1] FALSE

3 >= 2 # 3は2より大きいのでTRUE
## [1] TRUE
2 >= 2 # 2は2と等しいのでTRUE
## [1] TRUE

1 == 1 & 2 == 2 # TRUEかつTRUEなのでTRUE
## [1] TRUE
1 == 1 & 2 == 3 # TRUEかつFALSEなのでFALSE
## [1] FALSE

1 == 1 | 2 == 2 # TRUEまたはTRUEなのでTRUE
## [1] TRUE
1 == 1 | 2 == 3 # TRUEまたはFALSEなのでTRUE
## [1] TRUE

3.3.3.2 演算子の優先順位

数値の計算で掛け算・割り算を足し算・引き算より前に計算するように、演算子の優先順位、計算する順番は決まっています。概ね通常の計算と同じですが、以下のような順序で演算子は計算されます。

  1. カッコでくくられている計算
  2. 累乗(^
  3. 剰余・整数の割り算(%%%/%
  4. 掛け算・割り算(*/
  5. 足し算・引き算(+-
  6. 比較演算子(==!=<<=>>=
  7. 論理演算子(&|

計算式は長くなることが多く、演算子の計算順を間違う場合も多いため、優先する計算は積極的にカッコで囲むとよいでしょう。

演算子の計算順序
(2 + 1) / 3 # カッコ内は最優先
## [1] 1

2 ^ 3 %% 5 # 累乗は剰余より先に計算(8/5の余り)
## [1] 3

3 / 3 %% 2 # 剰余は割り算より先に計算(3/1を計算)
## [1] 3

3 / 3 + 1 # 割り算は足し算より先に計算
## [1] 2

3 + 3 > 5 # 比較演算子は足し算より後に計算
## [1] TRUE

5 > 1 & 6 > 2 # 論理演算子は最後に計算
## [1] TRUE

3.3.4 その他の型・クラス

以上の3つ(文字列、数値、論理型)がRでの基本的な型になります。しかし、Rにはこの3つ以外の型を持つオブジェクトも存在します。

3.3.4.1 欠損値など

データ分析では欠損値や、計算結果が表示できないもの、計算結果が無限大になるものなど、データとしてうまく取り扱えない値が生じることがよくあります。このような場合に対応するため、Rは欠損値、計算できない値、無限大にそれぞれNANaNInfという型が設定されています。Rでは中身が何もないオブジェクト、NULLというものを作成することもできます。

欠損値、非数、無限大
NA # 欠損値(Not Available)
## [1] NA

0/0 # 非数(NaN、Not a Number)
## [1] NaN

1/0 # 無限大(Inf)
## [1] Inf

10000^1000000 # 大きすぎて取り扱えない数値もInfになる
## [1] Inf

NULL # 中身がないオブジェクト(NULL)
## NULL

3.3.4.2 複素数(complex)

Rでは複素数(整数+虚数)を取り扱うこともできます。複素数を表すときには、数値の後にiを入力します。

複素数の作成と演算
1 + 1i # 複素数
## [1] 1+1i

mode(1 + 1i) # 複素数の型はcomplex
## [1] "complex"

(1 + 1i) + (3 + 3i) # 複素数同士の足し算
## [1] 4+4i

3.3.4.3 日時のクラス(Date、POSIXct、POSIXlt、difftime)

日付は数値や文字列とは異なる性質を持ちます。統計では日付や時間を演算に用いることもあります。Rでは日付はDateというクラスを持ちます。また、日時のデータはPOSIXctやPOSIXltというクラスに属します。

DateやPOSIXct、POSIXltは引き算などの演算に用いることができます。日時の差はdulationsというクラスを持ちます。

Date、POSIXct、POSIXlt、dulationはいずれもクラスで、データの型としてはdouble、つまり数値型のデータとして取り扱われます。

日時のクラスと型
Sys.Date() # 現在の日付を表示する関数
## [1] "2025-03-29"

class(Sys.Date()) # 日付のクラスはDate
## [1] "Date"

typeof(Sys.Date()) # 日付の型はdouble
## [1] "double"


Sys.time() # 現在の日時を表示する関数
## [1] "2025-03-29 08:10:57 +09"

class(Sys.time()) # 日時のクラスはPOSIXctとPOSIXlt
## [1] "POSIXct" "POSIXt"

typeof(Sys.time()) # 日時の型はdouble
## [1] "double"


Sys.Date() - as.Date("2023-01-01") # 2023/1/1から今日までの日数
## Time difference of 818 days

class(Sys.Date() - as.Date("2023-01-01")) # 日時の差のクラスはdifftime
## [1] "difftime"

3.4 変数と定数

3.4.1 変数

ココまでは、数値や文字列などの、単純なオブジェクトについて説明してきました。単純なオブジェクトはプログラミングの要素として重要です。しかし、オブジェクトを毎回作成し直すのは面倒です。オブジェクトを作ったら、それを一時的に保管しておいて、後から演算に使える方が便利です。

電卓では、このような「一時的に結果を記録する」方法として、メモリー機能があります。Excelなどでは、計算結果をセルに記録しておくこともあるでしょう。プログラミング言語にも、計算結果を一時的に保管しておくものが準備されています。この「計算結果を一時的に保管しておくもの」のことを、プログラミング言語では変数と呼びます。

変数には名前がついています。名前付きの箱の中にオブジェクトを入れているようなものが変数です。下の図では、変数「dog」にオブジェクト「"犬"」を入れています。「"犬"」を取り出して使いたいときには、変数である「dog」を持ってくればよい、ということになります。

図2:変数のイメージ

図2:変数のイメージ

Rで変数を作成する場合には、変数名に「<-」の記号でオブジェクトを代入します。

変数への代入
dog <- "inu" # dogという変数に"inu"という文字列を代入する
number <- 1 # numberという変数に、1という数値を代入する
dog # 変数dogには"inu"が入っている
## [1] "inu"

number # 変数numberには1が入っている
## [1] 1

変数には型・クラスがあり、代入したオブジェクトと同じ型・クラスを持つことになります。また、変数はそのまま演算に用いることができます。

変数の型
mode(dog) # dogの中身は文字列
## [1] "character"

mode(number) # numberの中身は数値
## [1] "numeric"


paste(dog, "walk") # dogの中身と"walk"をつなぐ
## [1] "inu walk"

number + 5 # numberの中身に5を足す
## [1] 6

dog + 1 # dogの中身は文字列なので、足し算はできない
## Error in dog + 1: non-numeric argument to binary operator

変数への代入は、「=」や「->」の演算子によっても行うことができます。ただし、これらを代入に用いると、プログラムを読み解くのが難しくなるため、Rでは「<-」を用いることが推奨されています。

=や->による代入
dog = "犬" # イコールも代入に使うことができる
2 -> number # ->も代入に使える(方向は<-と逆になる)

dog
## [1] "犬"

number
## [1] 2

定義されている変数の一覧を確認するには、ls関数を用います。

変数の確認
ls()
## [1] "d"      "dog"    "number"

3.4.2 変数と定数

変数のうち、一度代入したら中身を変えられないもののことを定数と呼びます。他のプログラミング言語では定数を設定できるものが多いのですが、Rには定数を設定する方法はありません。変数の中身はいつでも置き換えできます。変数を置き換えると、置き換えに用いたオブジェクトの型・クラスに従い、変数の型・クラスも置き換わります。

変数の置き換え
dog <- "inu" # 変数に文字列を代入
mode(dog) # 型は文字列になる
## [1] "character"

dog <- 1 # 変数に数値を入れ直す
mode(dog) # 変数の型は数値になる
## [1] "numeric"

多くのプログラミング言語では、上記のように変数の型が変化するのを抑える仕組み(型宣言)を持っています。型宣言が必要な言語では、変数は厳密に型のチェックを受けます(静的型付け)。Rにはこのような仕組みがなく、代入されたオブジェクトに従って型が決まり、型チェックされることなくプログラムが実行されます。このような言語のことを動的型付けと呼びます。

プログラム中で変数の型が変わると、バグの原因となります。Rでは、プログラムを書いているうちに変数の型が変化していて、正しい計算結果が得られない、ということがたびたび起きます。変数の型を常に確認しながらプログラミングした方がよいでしょう。

定数とは少し異なりますが、Rでは代入なしに使える変数もあります。例えば、円周率のπは「pi」という変数名で始めから登録されています。このような変数にも別のオブジェクトを代入することはできますが、後々混乱する原因となるため避けたほうがよいでしょう。

また、統計手法を試すためのデータが代入されている変数(データセット)もたくさん設定されています。データセットについては、14章で詳しく説明します。

あらかじめ設定されている変数
pi # 円周率
## [1] 3.141593

letters # アルファベット(小文字)
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
## [20] "t" "u" "v" "w" "x" "y" "z"

LETTERS # アルファベット(大文字)
##  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
## [20] "T" "U" "V" "W" "X" "Y" "Z"

month.abb # 月(短縮表記)
##  [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"

month.name # 月
##  [1] "January"   "February"  "March"     "April"     "May"       "June"     
##  [7] "July"      "August"    "September" "October"   "November"  "December"

pi <- 3 # piに3を代入する
pi # piは3になってしまう
## [1] 3

3.4.3 値渡しと参照渡し

Rでは、変数への代入が行われるたびに、その変数に対するメモリのアドレスを新規に作成し直す、という特徴があるため、他の言語で理解が必要となる値渡しと参照渡しの問題がほとんど起きません。

値渡し
x <- 1 # xに1を代入
y <- x # yにxを代入(yとxはメモリを共有)
x <- 2 # xに2を代入(xのメモリのアドレスが変わる)
x # xは新しいアドレスを参照(2が返ってくる)
## [1] 2
y # yは古いアドレスを参照(1が返ってくる)
## [1] 1

上のコードでは、参照渡しであれば、xの値が2になった場合、xとメモリを共有しているyも2になります。Rでは、代入時にメモリのアドレスが別に準備されるため(値渡し)、参照渡しが起こることは基本的にありません。この特徴はプログラミング初心者には優しいのですが、変数の変更のたびにメモリ上にオブジェクトを新規作成するため、Rの実行速度が遅い原因になります。

3.5 便利なオブジェクト・クラス

ここまでは、オブジェクトが一つだけの場合のデータ型や、変数について見てきました。しかし、統計で取り扱うのは、複数の数値や記録です。数値や記録がたくさんある場合には、数値や記録を一つづつ別々に取り扱うのは非効率です。多くのプログラミング言語では、このような複数の数値や記録を取り扱う専用のクラスを備えています。Rでは、複数の記録を取り扱うクラスとして、ベクター(vector)リスト(list)データフレーム(data.frame)行列(matrix)の4つが用いられます。以下にこの4つについて簡単に説明します。それぞれのクラスについてはさらに別章で詳しく説明します。

3.5.1 ベクター(vector)

Rで最も基本的なオブジェクトは、ベクター(vector)です。ベクターは同じ型を持つオブジェクトの集まりで、1次元の、つまり縦横の構造がないデータとして取り扱われます。ベクターはc関数(cはcombine、「結合する」の意味)で作成することができます。

ベクターは同じ型を持つデータの集まりです。ですので、ベクターの要素に文字列が交じると、自動的にすべての要素が文字列になる、という特徴があります。

ベクターの作成
vec_n <- c(1, 2, 3, 4) # 数値のベクター
vec_c <- c("dog", "cat", "pig", "horse") # 文字列のベクター
vec_temp <- c(1, 2, 3, "dog") # 文字列が交じると文字列のベクターになる

vec_n
## [1] 1 2 3 4

vec_c
## [1] "dog"   "cat"   "pig"   "horse"

vec_temp
## [1] "1"   "2"   "3"   "dog"

Rでは数値1つや文字列1つの要素も、ベクターとして取り扱われます。ですので、Rのオブジェクトの最小単位はベクターとなります。要素が1つであれば、c関数でつなぎ合わせる必要はありません。

1 # 数字1つでもベクター
## [1] 1

"Hello world" # 文字列1つでもベクター
## [1] "Hello world"

vectorはベクトルと表記されることもあります。この文書では、Rのオブジェクトをベクター、方向と大きさを持つ量のことをベクトルと表記することとします。

3.5.1.1 ベクターに要素を追加する

ベクターに要素を追加するために、append関数というものが用意されています。しかし、上記のc関数でもベクターに要素を追加することができます。

append関数では位置を特定して要素を追加することができますが、位置を特定して要素を追加することはまれです。

ベクターに要素を追加する
append(vec_n, 5) # 上の数値ベクターに5を追加
## [1] 1 2 3 4 5

c(vec_n, 5) # 上と同じ
## [1] 1 2 3 4 5

3.5.1.2 ベクターの要素を取り出す

ベクターの要素を取り出すときには、インデックスというものを用います。インデックスとは、ベクターなどの複数の値を取り扱うオブジェクトにおいて、値のある位置を示す数値のことです。インデックスはベクターの変数の後に、四角カッコ([ ])に数値を入れることで指定することができます。Rではインデックスは1から始まります。

図3:ベクターとインデックス

図3:ベクターとインデックス
ベクターの要素をインデックスで取り出す
vec <- c(4, 3, 2, 1) # 数値のベクターを作成する
vec[1] # インデックス1には4が入っている
## [1] 4

vec[3] # インデックス3には2が入っている
## [1] 2

多くのプログラミング言語では、インデックスは0から始まります。インデックスが1から始まるプログラミング言語はまれです。

3.5.1.3 ベクターの要素の置き換え

ベクターの要素を置き換えるときには、置き換えたいベクターのインデックスを指定し、数値などを代入します。この時、数値のベクターの要素を文字列に置き換えると、ベクター全体が文字列に置き換わるので注意して下さい。

ベクターの要素を置き換える
vec # 数値のベクター
## [1] 4 3 2 1

vec[3] <- 5 # インデックス3の数値を5に置き換える
vec # 3番めが2から5に置き換わる
## [1] 4 3 5 1

vec[4] <- "dog" # インデックス4の数値を"dog"(文字列)に置き換える
vec # ベクターはすべて文字列になる
## [1] "4"   "3"   "5"   "dog"

3.5.1.4 ベクターの要素を取り除く

ベクターの要素を取り除くときには、ベクターのインデックスをマイナスで指定します。マイナスのインデックスで指定した要素は取り除かれ、ベクターの長さが短くなります。

ベクターの要素を取り除く
vec
## [1] "4"   "3"   "5"   "dog"
vec[-3] # インデックス3の要素(5)を取り除く
## [1] "4"   "3"   "dog"

3.5.1.5 ベクターの演算

ベクターは、そのまま演算に用いることができます。数値のベクターに数値を足せば、ベクターのすべての要素に数値が足されます。文字列のベクターにpaste関数で文字を継ぎ足せば、すべての要素に文字が継ぎ足されます。

ベクターを演算に用いる
vec_n # 数値のベクター
## [1] 1 2 3 4
vec_n + 5 # 数値のベクターに5を足すと、すべての要素に5が足される
## [1] 6 7 8 9

vec_c # 文字のベクター
## [1] "dog"   "cat"   "pig"   "horse"
paste(vec_c, "is an animal.") # 文字のベクターにpaste関数で文字をつなぎ合わせる
## [1] "dog is an animal."   "cat is an animal."   "pig is an animal."  
## [4] "horse is an animal."

ベクターについては11章でさらに詳しく説明します。

3.5.2 因子(factor)

因子(factor)はR以外のプログラミング言語にはないクラスの一つです。因子とは、カテゴリを表すときに用いるクラスです。カテゴリとは、例えば男性/女性や、成人/未成年、喫煙者/非喫煙者などの、そのデータの性質を表す要素のことを指します。統計では、例えば男性と女性で分けて数値を集計する、といったシチュエーションがたくさんあります。このように、カテゴリごとの集計や統計を行いやすくするために準備されているクラスが因子です。因子はfactor関数を用いて作成します。

因子型(factor)
factor("male") # 男性を示す因子
## [1] male
## Levels: male

class(factor("male")) # 因子のクラスはfactor
## [1] "factor"

3.5.2.1 因子のレベル(levels)

因子には、レベル(levels)というアトリビュートが付いています。因子はカテゴリを示すものですので、通常1つだけで用いることはありません(カテゴリが1つだけであれば、カテゴリ分けする必要がありません)。つまり、因子は複数の要素を持つベクターとして作成することになります。このときのベクター内の各カテゴリ(男性・女性など)のことをレベルと呼びます。因子については10章で詳しく説明します。

3.5.3 リスト(list)

統計の計算をしていると、複数の計算結果をまとめて取り扱いたい、という場合があります。ベクターは1次元のオブジェクトで、かつすべての要素のデータ型が同じですので、ベクターでは型や長さの違う、様々な結果を一度に取り扱うことはできません。このような、型の違うデータを一度に取り扱うときに用いられるのが、リスト(list)と呼ばれるオブジェクトです。リストは、様々なオブジェクトをまとめて一つにしたようなデータ構造を持ちます。リストを作成するときには、list関数を用います。

リスト(list)の作成
vec1 <- c(1, 2, 3, 4) # 数値のベクター
vec2 <- c("dog", "cat", "pig", "horse") # 文字列のベクター
num <- 10 # 数値
char_temp <- "Hello world" # 文字列

list_temp <- list(vec1, vec2, num, char_temp) # 色々な要素をリストにまとめる
list_temp # まとめたリストを表示
## [[1]]
## [1] 1 2 3 4
## 
## [[2]]
## [1] "dog"   "cat"   "pig"   "horse"
## 
## [[3]]
## [1] 10
## 
## [[4]]
## [1] "Hello world"

3.5.3.1 リストの要素を取り出す

リストの要素を取り出す場合には、ベクターと同様にインデックスを用います。ただし、リストのインデックスは多層化、ネストされているため、呼び出しはやや複雑です。リストの要素を取り出すときには、四角カッコを2重にして用います([[ ]])。[[1]]で呼び出すと、リストの1番目の要素を呼び出すことになります。ベクターと同様に[1]で呼び出すと、リストの1番目の要素を、リストとして呼び出すことになり、要素までたどり着けません。

リストの要素を取り出す
list_temp[[1]] # リストの1番目の要素を取り出す
## [1] 1 2 3 4

list_temp[[2]] # 2番目の要素を取り出す
## [1] "dog"   "cat"   "pig"   "horse"

list_temp[1] # リストの1番目の要素を、リストとして取り出す
## [[1]]
## [1] 1 2 3 4

list_temp[[1]][1] # リストの1番目の要素(ベクター)の、1番目の要素を取り出す
## [1] 1

リストについては、12章で詳しく説明します。

3.5.4 データフレーム(data.frame)

データフレーム(data.frame)はExcelの表のように、行と列を持ち、長方形の形に整形された表形式のオブジェクトです。データフレームはExcelの表のように取り扱うことができます。

データフレームは縦方向(列)に同じデータ型を持つ、ベクターの集合になっています。データフレームは横方向(行)には異なる型を持つことができますが、縦方向(列)は必ず同じ型を持つ必要があります。列はベクターですので、ベクターと同じように数値の列の1つのデータを文字列に置き換えると、その列のデータが全て文字列に変換されるという特徴があります。

データフレームはdata.frame関数を用いて作ることができます。データフレームを作成するときには、「列名」=「列の要素」という形でカッコの中に入力します。

データフレームの作成
d <- data.frame( # データフレームを作成する(各列を同じ長さにする)
  number = c(1, 2, 3, 4), # 1列目は数値
  animal = c("dog", "cat", "pig", "horse"), # 2列目と3列目は動物と果物
  fruits = c("apple", "orange", "banana", "grape")
)

d # データフレームの表示
##   number animal fruits
## 1      1    dog  apple
## 2      2    cat orange
## 3      3    pig banana
## 4      4  horse  grape

データフレームは同じ長さのベクターをリストにしたものです。ですので、縦(列)はベクターとして同じ型を持ちます。データフレームはリストでもあるので、リストと同じように取り扱うこともできます。

3.5.4.1 データフレームの次元(dimension)と行数・列数

データフレームには、次元(dimension)という性質(アトリビュート、attribute)があります。この次元とは、行の数、列の数のことです。次元を取得する時には、dim関数を用います。また、行の数、列の数はそれぞれnrow関数、ncol関数で取得することができます。

データフレームの次元を取得する
dim(d) # 次元の取得(前が行の数、後ろが列の数)
## [1] 4 3
nrow(d) # 行の数
## [1] 4
ncol(d) # 列の数
## [1] 3

3.5.4.2 データフレームのインデックス

ベクターやリストと同じく、データフレームでもインデックスで要素を取り出すことができます。データフレームのインデックスは、[行, 列]という形で指定します。行も列も、1行目・1列目のインデックスが1となります。

データフレームでは、行だけ、列だけをインデックスとして指定することもできます。行だけをインデックスとして指定した時([行, ]の形で指定)には、その行がデータフレームとして取り出されます。一方、列だけを指定した時([, 列]の形で指定)には、その列がベクターとして取り出されます。データフレームを行と列で取り出した場合には異なるものが取り出されるので、特にデータフレームの行を取り出す際には注意が必要です。

データフレームの要素を取り出す
d
##   number animal fruits
## 1      1    dog  apple
## 2      2    cat orange
## 3      3    pig banana
## 4      4  horse  grape

d[2, 3] # 2行3列目のデータを取り出す
## [1] "orange"

d[2, ] # 2行目を取り出す(データフレーム)
##   number animal fruits
## 2      2    cat orange

d[, 3] # 3列目を取り出す(ベクター)
## [1] "apple"  "orange" "banana" "grape"

データフレームの列は、列の名前を用いても取り出すことができます。列を取り出すときには、$(ドルマーク)に列名を繋げて記述します。

列を列名で呼び出す
d$number # 1列目の列名はnumber
## [1] 1 2 3 4

d$animal # 2列目の列名はanimal
## [1] "dog"   "cat"   "pig"   "horse"

d$fruits # 3列目の列名はfruits
## [1] "apple"  "orange" "banana" "grape"

3.5.4.3 データフレームの要素の置き換え

データフレームの要素の置き換えは、ベクターと同じように、置き換えたい場所のインデックスを指定して、値を代入する形で行います。この時、その置き換える列の型と代入するデータの型が異なると、列の型がすべて置き換わることがあるので注意が必要です。

データフレームの要素を置き換える
d[2, 3] <- "peach" # 2行3列目の要素をpeachに置き換える
d # 2行3列目がpeachに置き換わる
##   number animal fruits
## 1      1    dog  apple
## 2      2    cat  peach
## 3      3    pig banana
## 4      4  horse  grape

d[2, 1] <- "tomato" # 2行1列目をtomato(文字列)に置き換える
d # 2行1列目がtomatoに置き換わる
##   number animal fruits
## 1      1    dog  apple
## 2 tomato    cat  peach
## 3      3    pig banana
## 4      4  horse  grape

mode(d[, 1]) # 1列目が文字列に置き換わる
## [1] "character"

3.5.4.4 データフレームの行・列の削除

データフレームの行や列を削除する場合には、ベクターと同じように、インデックスをマイナスで与えます。インデックスをマイナスで指定することで、そのインデックスの行・列を取り除くことができます。ただし、データフレームの1つの要素だけを削除することはできません(指定した行・列がまるごと削除されます)。1つの要素だけを取り除く場合には、その要素のインデックスに対してNAを代入するとよいでしょう。

データフレームの行・列を削除する
d # 元々のデータフレームは4行3列
##   number animal fruits
## 1      1    dog  apple
## 2 tomato    cat  peach
## 3      3    pig banana
## 4      4  horse  grape

d[-1, ] # 1行目を削除
##   number animal fruits
## 2 tomato    cat  peach
## 3      3    pig banana
## 4      4  horse  grape

d[, -1] # 1列目を削除
##   animal fruits
## 1    dog  apple
## 2    cat  peach
## 3    pig banana
## 4  horse  grape

d[-2, -3] # 2行目と3列目を削除
##   number animal
## 1      1    dog
## 3      3    pig
## 4      4  horse

d[2, 3] <- NA # 1要素だけを取り除くときは、NAを代入する

3.5.5 行列(matrix)

行列(matrix)は、線形代数(高校数学での行列計算)に用いるものです。行列は基本的には一つの型の要素からなる、行と列のあるオブジェクトです。行列はデータフレームとよく似ていますが、データフレームが列方向のベクターのリストであるのに対し、行列は次元(dimension)を持つベクターに近いものとなります。

Rで行列を作成するときには、matrix関数を用います。matrix関数では、カッコの中に、ベクター、行数、列数を指定する数値を与えます。

行列を作成する
# 2行3列の行列
mat <- matrix(c(1,2,3,4,5,6), nrow=2, ncol=3) # nrowは行数、ncolは列数
mat
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6

3.5.5.1 行列の次元とインデックス

行列の次元とインデックスは、データフレームとほぼ同じように取り扱うことができます。行列の行・列に名前をつけることもできます。従って、列を取り出すときに列名を利用することもできます。取り出したものはいずれもベクターになります。要素・行・列の削除もデータフレームと同じ方法で行います。

行列の要素の取り出し
mat[1, 1] # 1行1列目の要素
## [1] 1

mat[1, ] # 1行目の要素(ベクター)
## [1] 1 3 5

mat[, 1] # 1列目の要素(ベクター)
## [1] 1 2

dim(mat) # matのdimensionを表示
## [1] 2 3

nrow(mat) # matの行数を表示
## [1] 2

ncol(mat) # matの列数を表示
## [1] 3

3.5.5.2 行列の演算

データフレームとは異なり、数値の行列は演算に用いることができます。行列(線形代数)の計算のために、Rには行列積、外積、クロネッカー積に対応する演算子が準備されています。

表4:Rで使える行列の演算子
行列の演算子 演算子の意味
%*% 行列の積
%o% 外積
%x% クロネッカー積
行列の演算
mat2 <- matrix(c(1, 2, 3, 4, 5, 6), nrow=3, ncol=2)

mat %*% mat2 # 行列の積
##      [,1] [,2]
## [1,]   22   49
## [2,]   28   64

mat %o% mat2 # 外積
## , , 1, 1
## 
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
## 
## , , 2, 1
## 
##      [,1] [,2] [,3]
## [1,]    2    6   10
## [2,]    4    8   12
## 
## , , 3, 1
## 
##      [,1] [,2] [,3]
## [1,]    3    9   15
## [2,]    6   12   18
## 
## , , 1, 2
## 
##      [,1] [,2] [,3]
## [1,]    4   12   20
## [2,]    8   16   24
## 
## , , 2, 2
## 
##      [,1] [,2] [,3]
## [1,]    5   15   25
## [2,]   10   20   30
## 
## , , 3, 2
## 
##      [,1] [,2] [,3]
## [1,]    6   18   30
## [2,]   12   24   36

mat %x% mat2 # クロネッカー積
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]    1    4    3   12    5   20
## [2,]    2    5    6   15   10   25
## [3,]    3    6    9   18   15   30
## [4,]    2    8    4   16    6   24
## [5,]    4   10    8   20   12   30
## [6,]    6   12   12   24   18   36

3.5.5.3 3次元以上のオブジェクト:array

行列はベクターに次元を2つ(行と列)与えたものですが、3次元以上の次元を与えることもできます。このような3次元以上のデータを取り扱う場合には、arrayというオブジェクトを使用します。arrayはarray関数で作成することができ、各次元の数(行数、列数に当たるもの)をベクターで与えます。統計やデータ解析で3次元以上のデータを取り扱うことは比較的まれです。

arrayを作成する
array(c(1, 2, 3, 4, 5, 6, 7, 8), dim = c(2, 2, 2)) # 2行2列2シートの行列
## , , 1
## 
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
## 
## , , 2
## 
##      [,1] [,2]
## [1,]    5    7
## [2,]    6    8

3.5.6 その他のオブジェクト

Rに基本的に備わっているオブジェクトとして、ベクター、リスト、データフレーム、行列の他に、時系列(time series、ts)というオブジェクトがあります。時系列とは、例えば株価や為替相場の時間変化のような、時間とともに定期的に記録されたデータのことを指します。時系列はクラスとして設定されており、中身はベクターです。

時系列データ(ts)
co2[1:10] # 1959年からのCO2濃度の推移
##  [1] 315.42 316.31 316.50 317.56 318.13 318.00 316.39 314.65 313.68 313.18

class(co2) # クラスはts
## [1] "ts"

typeof(co2) # 型はdouble
## [1] "double"

3.6 関数

ここまでに、mode関数、typeof関数、class関数、c関数、list関数、data.frame関数、matrix関数など、様々な関数を用いて、オブジェクトの型やクラスを調べたり、ベクターやリストなどを作成してきました。R言語の関数とは、オブジェクトに一定の演算を加えて、結果を表示するオブジェクトのことを指します。関数のクラスはfunction(関数)、型もfunctionです。

オブジェクトとしての関数
class(typeof) # 関数のクラスはfunction
## [1] "function"

mode(typeof) # 関数の型もfunction
## [1] "function"

Rでの関数は、引数と呼ばれる、カッコの中に記載されたオブジェクトに対して、一定の演算を加えるものです。Excelの関数をイメージしていただければ理解しやすいと思います。関数のイメージを図にすると、以下のようになります。

図4:関数のイメージ図

図4:関数のイメージ図

Rにはmean関数という、数値の平均値を表示してくれる関数があります。上の図では、ベクターである、c(5, 10, 15)を引数として与えると、mean関数は引数を読み取って平均値を計算し、平均値である10を表示してくれます。この、表示される関数の計算結果のことを、返り値と呼びます。

関数、引数と返り値
vec <- c(5, 10, 15) # 引数とするベクター
mean(vec) # mean関数に引数vecを与えると、10が返り値として返ってくる
## [1] 10

Rには、上記の関数以外にも、数値や文字列、データフレームを演算するための関数を数多く備えています。

代表的な関数と、関数としての演算子
sd(vec) # 標準偏差を計算する関数
## [1] 5

median(vec) # 中央値を計算する関数
## [1] 10

log10(vec) # 常用対数を計算する関数
## [1] 0.698970 1.000000 1.176091

exp(vec) # ネイピア数の指数を計算する関数
## [1]     148.4132   22026.4658 3269017.3725

mode(`+`) # 演算子の+の型はfunction(関数)
## [1] "function"

`+`(2, 3) # 関数なので、引数を2つ取ると足し算になる
## [1] 5

mode(`[`) # インデックスも関数
## [1] "function"

mode(`if`) # if(条件分岐)も関数
## [1] "function"

mode(`for`) # for(繰り返し文)も関数
## [1] "function"

Rでは、演算子やインデックス指定、条件分岐、繰り返し文も関数です。

このように、Rでは多くの演算を関数によって処理しています。この性質から、Rは関数型言語であるとされています。

正確には、Rは厳密な意味では関数型言語ではないように思います。関数型言語にはHaskellなどがありますが、関数型言語では再帰的関数(関数内で関数を呼び出す)ような処理を用いて繰り返し計算を避ける場合が多く、Rのような逐次型処理に慣れていると読みにくいコードをよく書くイメージがあります。Rでも再帰的関数を用いることはできますが、頻繁には使用されません。

3.6.1 関数を自作する

どのようなプログラミング言語にも、関数を自作する方法が備わっています。Rでは、function文を用いて関数を自作することができます。関数を変数に代入して用いるのが一般的な関数の作成方法です。function文の書き方は以下の通りです。

関数名 <- function(引数群){引数を使った処理}

関数の返り値は、return関数を使って明示することもできますが、単に最後に記載したオブジェクトを返り値とすることもできます。

また、Rではfunctionと書く代わりに、\(バックスラッシュ)をfunctionの代わりに用いることもできます。

作成した関数を用いて演算するときには、「関数名(引数)」という形で表記します。これはmode関数やclass関数の使い方と同じです。

関数を自作する
# 引数をそのまま帰す関数
return_selfx <- function(x){return(x)} # 返り値をreturn関数で表示
return_selfy <- function(y){y} # 最後に返り値を書く
return_selfz <- \(z){z} # functionの代わりにバックスラッシュを用いる

# どれも同じ演算をする関数になる
return_selfx(1)
## [1] 1

return_selfy(1)
## [1] 1

return_selfz(1)
## [1] 1

実際に関数を作るときには、もう少し複雑な処理を{ }(中かっこ)の中に書きます。処理は一つ一つ改行しながら書き、最後に返り値を書きます。中かっこの中で改行を行っても問題ありませんが、引数のかっこ(「)」)の後にかっこの前側(「{」)が記載されている必要があります。

関数内の処理の書き方
# sum2関数を作成する
sum2 <- function(x, y, z){ # 引数はx、y、zの3つ
  sum_of_xyz <- x + y + z # 引数を足し算する
  sum_of_xyz # 足し算したものを返り値にする
}

sum2(x = 1, y = 2, z = 3)
## [1] 6

上の例のように、引数を指定するときには、引数の種類を明示的に記載することもできます。明示的に記載する場合には、「引数名=値」という形で書きます。引数名を省略した場合には、記載した引数の順番に従って、引数が用いられます。

関数を作成するときには、引数のデフォルト値を設定しておくこともできます。デフォルト値が設定されている関数では、その引数を入力しなかったときには、自動的に引数にデフォルト値が入ります。

引数のデフォルト値と省略
sum3 <- function(x, y = 1){ # yのデフォルト値を1とする
  return(x + y)
}

sum3(x = 1, y = 2) # 引数を明示的に記載
## [1] 3

sum3(1, 2) # xに1、yに2が入る
## [1] 3

sum3(1) # 引数yが省略されているので、デフォルト値(1)が用いられる
## [1] 2

sum3(y = 1) # xにはデフォルトが設定されていないので、省略できない
## Error in sum3(y = 1): argument "x" is missing, with no default

3.7 型・クラスの確認と変換

3.7.1 型・クラスの確認:is.関数群

Rでは、型やクラスを確認するための関数として、typeof関数・mode関数・class関数以外に、is.関数というものを備えています。is.関数を用いると、オブジェクトの型が、ある型と一致しているかどうかを確認することができます。引数が数値であるかどうかは、is.numeric関数、is.integer関数、is.double関数を用いて確認することができます。例えばis.numeric(1)TRUEを返し、is.numeric("dog")FALSEを返します。このis.関数には、文字列やNANaN等を確認する関数もあります。is.関数を以下の表2に示します。

表2:xの型の確認に用いる関数
is.関数名 チェックする型
is.numeric(x) 数値型
is.integer(x) 整数型
is.double(x) double型
is.complex 複素数型
is.character(x) 文字列型
is.logical(x) 真偽型
is.factor(x) 因子型
is.atomic(x) ベクター
is.list(x) リスト
is.matrix(x) マトリックス
is.data.frame(x) データフレーム
is.na(x) NA
is.nan(x) NaN
is.null(x) NULL
is.infinite(x) 無限大

is.関数の中では、is.na関数の使用頻度が高いです。is.na関数を用いると、ベクターやデータフレームからNAを含む要素をうまく取り除くことができます。

is.関数群
c(is.numeric(1), is.numeric("1")) # 文字列("1")は数値ではない
## [1]  TRUE FALSE

c(is.integer(1L), is.integer(1)) # Lが付いていないとdoubleになる
## [1]  TRUE FALSE

c(is.double(1), is.double(1L)) # Lが付いているとintegerになる
## [1]  TRUE FALSE

c(is.complex(1+1i), is.complex(1+1)) # iがあると複素数になる
## [1]  TRUE FALSE

c(is.character("dog"), is.character(1)) # 数値は文字列ではない
## [1]  TRUE FALSE

# 0はFALSE扱いされるが、logicalではない
c(is.logical(T), is.logical(0), is.logical("dog")) 
## [1]  TRUE FALSE FALSE

c(is.factor(factor(1)), is.factor(1))
## [1]  TRUE FALSE

c(is.atomic(1), is.atomic(list(1))) # ベクターはTRUE、リストはFALSE
## [1]  TRUE FALSE

c(is.vector(1), is.vector(list(1))) # is.vectorもあるが、リストもTRUEになる
## [1] TRUE TRUE

c(is.list(list(1)), is.list(1))# ベクターはFALSE、リストはTRUE
## [1]  TRUE FALSE

c(is.matrix(matrix(1, ncol=1)), is.matrix(1))
## [1]  TRUE FALSE

c(is.data.frame(data.frame(1)), is.data.frame(list(1))) # リストはFALSE
## [1]  TRUE FALSE

# NAとNaNはNA扱い、NULLは無いもの扱い
c(is.na(NA), is.na(1), is.na(NaN), is.na(Inf), is.na(NULL)) 
## [1]  TRUE FALSE  TRUE FALSE

# NULLは無いもの扱い
c(is.nan(NA), is.nan(1), is.nan(NaN), is.nan(Inf), is.nan(NULL))
## [1] FALSE FALSE  TRUE FALSE

# NULLを評価する
c(is.null(NA), is.null(1), is.null(NaN), is.null(Inf), is.null(NULL)) 
## [1] FALSE FALSE FALSE FALSE  TRUE

# NULLは無いもの扱い
c(is.infinite(NA), is.infinite(1), is.infinite(NaN), is.infinite(Inf), is.infinite(NULL)) 
## [1] FALSE FALSE FALSE  TRUE

ベクターはis.atomic関数で評価します。これは、ベクターのことをatomic vectorと呼ぶためです。atomic vectorはvectorと同じ意味を持ちます。エラーやメッセージには時々このatomic vectorという表記が出てきますが、これは通常のベクターのことを述べているだけで、atomic vectorという特別なものがあるわけではありません。

3.7.2 型・クラスの変換:as.関数群

is.関数はデータのクラスや型をチェックし、論理型を返す関数です。Rには、関数名がよく似たas.関数があります。as.関数は、引数の型を指定した型に変換する関数です。例えば、as.numeric関数は引数をnumericに変換する関数です。as.関数の一覧を以下の表3に示します。

表3:xの型の変換に用いる関数
as.関数名 変換する型
as.numeric(x) 数値型に変換
as.integer(x) 整数型に変換
as.double(x) double型に変換
as.complex 複素数型に変換
as.character(x) 文字列型に変換
as.logical(x) 真偽型に変換
as.factor(x) 因子型に変換
as.Date 日時型に変換
as.POSIXct POSIXct型に変換
as.POSIXlt POSIXlt型に変換
as.list(x) リストに変換
as.matrix(x) マトリックスに変換
as.data.frame(x) データフレームに変換
as.null(x) NULLに変換
as.関数群
as.numeric(TRUE)
## [1] 1

as.integer(1.1)
## [1] 1

as.double(1L)
## [1] 1

as.complex(1)
## [1] 1+0i

as.character(1)
## [1] "1"

c(as.logical(1), as.logical(0))
## [1]  TRUE FALSE

as.factor(c("dog", "cat"))
## [1] dog cat
## Levels: cat dog

as.Date("2022-02-22") # わかりにくいが、日付型になっている
## [1] "2022-02-22"

# わかりにくいが、日時型になっている
as.POSIXct("2022-02-22 15:00:00")
## [1] "2022-02-22 15:00:00 +09"

as.POSIXlt("2022-02-22 15:00:00")
## [1] "2022-02-22 15:00:00 +09"

as.list(1)
## [[1]]
## [1] 1

as.data.frame(list(1, 1))
##   X1 X1.1
## 1  1    1

as.matrix(data.frame(x=1, y=1))
##      x y
## [1,] 1 1

as.null(1)
## NULL

3.8 NAの取り扱い

Rでは、データに欠測値(NA)、計算できない値(NaN)、空の値(NULL)、無限大(Inf)が含まれることがあります。これらのうち、NANaNを取り除く関数がna.omit関数です。na.omit関数はベクターやデータフレームを引数に取り、NANaNを取り除いてくれる関数です。NAと異なり、Infは取り除かれません。

na.omit関数
vec <- c(1, NA, NaN, NULL, Inf) # NULLは要素として含められない
vec
## [1]   1  NA NaN Inf

na.omit(vec)
## [1]   1 Inf
## attr(,"na.action")
## [1] 2 3
## attr(,"class")
## [1] "omit"

3.9 予約語

上の例では関数や変数に名前をつけていますが、関数名や変数名の付け方にはルールがあります。

  • 名前の始めに数値(1、2など)をつけることはできない
  • 名前の始めにアンダーバー(_)を用いることはできない
  • 大文字と小文字は区別される(SUMとsumは別扱い)
  • 演算子や記号(!?+-# など)は使えない
  • 予約語を用いることはできない

予約語(reserved word)とは、R言語がすでに役割を与えているために、関数名や変数名には使用できない文字列です。Rで設定されている予約語は以下の通りです。

  • if
  • else
  • repeat
  • while
  • function
  • for
  • in
  • next
  • break
  • TRUE
  • FALSE
  • NULL
  • Inf
  • NaN
  • NA
  • NA_integer_
  • NA_real_
  • NA_complex_
  • NA_character_
  • ..1
  • ..2

Rでは、ピリオド(.)が予約語に含まれていないため、変数名にピリオドを利用することができます。ただし、他の言語ではこのピリオドをメソッド(method)という、関数の仲間のようなものに用いることが多く、勘違いを起こしやすい表記になります。Rでも変数名にピリオドを用いないほうがよいとされています。

3.10 ヘルプ

ヘルプを呼び出すことでRの関数の使い方を確認することができます。ヘルプは関数名の前に?を付けて実行することで呼び出すことができます。RStudioでは、右下のパネルにヘルプの内容が表示されます。

ヘルプの呼び出し
?mean # mean関数のヘルプを呼び出す