R言語(S言語) 概説メモ

2023/4/9


この文章は講義の演習用に作成したもので、 まだ更新作業中です。御意見/誤り指摘など、次までよろしくお願いいたします。
....... 関 庸一 (せき よういち)[sekiyoichi(at)gunma-u.ac.jp]


関のHome Page へ戻る


目次

1. R言語 とは
2. R言語 との対話
3. オブジェクト
   原始オブジェクト
   ベクトルと行列
   代入と参照
   ベクトル/行列演算
   論理演算子と参照
   リスト
   オブジェクXの操作関数
4. 関数
   既成の関数
   関数の適用
   行列などの一括処理
   自作の関数
5. グラフィック環境
6. 最後に
  参考文献と関連 Home Pageへのリンク

R言語 の クイック・リファレンス ...... やりたいことから、関数名を探したい時に
また、 R-Tips(Rマニュアル)がR言語のマニュアルとしても大体使えます。

1. R言語 とは

データ解析とグラフィックスのための言語であり、環境です。 取り扱う数値などのデータ、関数などをオブジェクトとして、 統一的に表現できます。当初はS言語とよばれ、 S システムとして動いていました。これは ACM 1998年 Software System Awared を受賞しています (初回の受賞がUNIX、TeXやSMALLTALK、PostScript、TCP/IPなどが受賞した賞です)。

みなさんは、R言語 (S言語のオープンソース・フリーソフトウェア版)を使いましょう。 WikipediaではR言語と紹介されています。 インストールするには、たとえばなどを参考にしてください。そのほか、"R"と"知りたい言葉"を並べてググると参考になる情報が得られることが多いと思います。

紙に書かれたマニュアルを見たい場合には、 参考文献[1]の第I分冊の前半に目を通すと概要が分かります。 第II分冊は関数のマニュアルとなっています。また、Windows環境なら参考文献[3]を勧めます。

2. R言語との対話

Windows環境などでは、アイコンをクリックして始めましょう。 Unix 環境ではコマンドラインに、"R"を入力して下さい。
R version 4.0.3 (2020-10-10R version 4.0.3 (2020-10-10) -- "Bunny-Wunnies Freak Out"
Copyright (C) 2020 The R Foundation for Statistical Computing
Platform: x86_64-w64-mingw32/x64 (64-bit)
  :
  :
> 
となって、R言語の環境に入れるはずです。最後の1行は R言語 のプロンプトで、 ここに、何かを入力すると、入力した文字列が R言語として解釈できれば、 解釈した結果を次の行以下に表示して、プロンプト表示状態になります。 次の1行("2+3")を入力して下さい。
> 2+3
[1] 5
> 
このように普通の四則演算(+,-,*,/,^)は素直に実行してくれます。 また、%/%, %%で整数除算の商と余りを計算します ( (7%/%3) は 2、 (11%%4)は 3となる)。

2行目行頭の[1] については、次節で説明します。 仕事を終えて、R言語 から出て、UNIX環境に戻りたい時には、

> q()
と入力します。以上、R言語を起動して終了するまでを、1つのセッション(session)と 呼びます。

R言語は怠惰な表現の許される言語で、適当に思いつくやり方で表現しても、 何とかしてくれます。何でもやって見て下さい。

3. オブジェクト

原始オブジェクト

解析対象となるデータの基本構成要素(原始オブジェクト)には、 論理値(TURE, FALSE [T,Fと省略可]) 、整数、実数、(半角)英数字などがある これらは、この順に後ろのものほど一般表現となる。

ベクトルと行列

同じ種類のものは、c( ) と言う関数でベクトルにまとめられる。
> c(1,2,3)
[1] 1 2 3
R言語の演算子に":" がある。初項と末項から公差1の等差数列を作って くれる (関数 seq()も参照)。
> 101:121
 [1] 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
[20] 120 121
R が返した2行目の[20] は、先頭要素が表示ベクトルの 20番目の要素である ことを示す。

ベクトルの一般形として、行列もオブジェクトとして扱える。 matrix() と言う関数で作れる。

> matrix(1:6,nrow=2)   # 1から6の数列を行数2の行列とせよ。
     [,1] [,2] [,3] 
[1,]    1    3    5
[2,]    2    4    6

代入と参照

オブジェクトに名前をつけて保存することができる ( "付値"という )。 オブジェクトの名前は英字で始まる英数字とピリオドでつける。 (ただし、予約語は避ける)。 大文字と小文字は区別される( case sensitive )。 つまり、"A" と "a" は異なるオブジェクト名となる。 原則として英小文字 ( と先頭以外のピリオド )で構成される名前を使う。 代入は ''<-'' (2字の間に空白を含んではならない)、 または ''_''または ''=''を使う。
> x <- 3:10
> x
[1] 3 4 5 6 7 8 9 10
Rは この例のようにオブジェクト名だけを入力すれば、その内容を表示する。

なお、Rのオブジェクトを表す変数 (上の例の"x"などオブジェクト名) に(原則として)変数宣言/型宣言は必要ない。 任意の変数は、付値されたときに、付値された内容と型を持つ。

注意 : あなたが作成したオブジェクト(特に関数)が既成の関数と同じ名称であると、 その関数は参照できなくなる(使えなくなる)場合がある。 関数が一つ使用不能になると、その関数を使っている関数も使えなくなることがある。 特に、R言語で重要な関数 "c"や "t"を 上書きしないように注意のこと。 上書きしてしまった時には、次の"rm()"で 自分のオブジェクトを消去すれば良い。

自分が定義したオブジェクトは"ls()"で、 そのリストを見ることができる。 また、"ls()"でリストされるオブジェクトは 不要ならば、"rm("その名前")"とすることで、消去できる。

なお、この"ls()"で見られるオブジェクトのしまい場所は session frame と呼ばれる。その他にも、 各種のライブラリが用意されている。また、関数呼出しによって生成される frame もある。

ベクトル/行列演算

R言語の演算(後で述べる関数)では、オブジェクトの次元数など形式が不一致の 場合、適当に変換して計算をしてくれる。この機能はベクトルや行列の形式の データを扱うとき、大変便利なので良く理解して欲しい。
> x
[1] 3 4 5 6 7 8 9 10
> x+2
[1]  5  6  7  8  9 10 11 12              # x の各要素に2を足す。
> x^2
[1]   9  16  25  36  49  64  81 100      # x の各要素を巾乗する。
> y <- 1:4
> y
[1] 1 2 3 4
> x+y  
[1]  4  6  8 10  8 10 12 14 
# y の 長さが足らないので y を2回複製して、xに足し込んだ。
# つまり、3+1 4+2 5+3 6+4 7+1 8+2 9+3 10+4 を実施した。
> z <- 1:3
> z
[1] 1 2 3 
> x+z
[1]  4  6  8  7  9 11 10 12
 警告メッセージ: 
 x + z で: 
   長いオブジェクトの長さが短いオブジェクトの長さの倍数になっていません 
# z の 長さが足らないので z を複製して、xに足し込もうとしたが、
# 整数回の複製でピッタシにならなかったので、警告がでた。
# つまり、3+1 4+2 5+3 6+1 7+2 8+3 9+1 10+2 を実施した。
# 最後に複製した方が余ったので、本当にこの計算をしたかったのか
# Rは貴方の意図が不安になって、Warning messages を出してくれている。

行列についても、同様のルールが適用される。 なお、次元数が異なるときには 1次元に直した順で演算される。

> xx <- matrix(1:6,nrow=2)
> xx
     [,1] [,2] [,3] 
[1,]    1    3    5
[2,]    2    4    6
> z  
[1] 1 2 3 
> xx+z
     [,1] [,2] [,3] 
[1,]    2    6    7
[2,]    4    5    9
# z の 個数が足らないので z を2回複製して、xに足し込んだ。
# R では配列を1次元に解釈する時、前の添字が忙しく回るように
# 並べ直す原則を採用しているので、たとえば[2,1]要素は 2+2 
# (x[2,1]+z[2])をしている。

論理演算子と参照

論理演算子は
    &    |      !        &&   ||
(前二つは、論理値のベクトルを扱える。 後ろ二つは、C言語同様に先頭からの条件つき比較をし、単一の論理値を返す。 関数 ifelse() も参照)、 比較演算は
    <   >   <=   >=    ==   !=
を使う。ベクトルなどに関しても、これらの比較演算ができ、たとえば、 先ほどの xについて、以下となる。
> x %% 2 ==1       # 奇数かどうかの論理値ベクトル
[1] T F T F T F T F
この表現では、ベクトル( x)と 単一値( 2 1)が 混在していて論理的にはおかしいが、R言語のベクトル演算では 必要に応じて短い方のベクトルを適当に反復して複製して、 長さを揃えてから演算してくれる原則がここでも適用されている。

ベクトル、行列を表すオブジェクトの要素は次のように参照できる。

> x[2]      # 2番目の要素の参照
[1] 4
> x[2:4]    # 2から4番目の要素の参照
[1] 4 5 6
> x[ x %% 2 == 1]    # 値が 奇数であるものの参照
[1] 3 5 7 9   

リスト

タイプの異なる原始オブジェクトや、その他の複雑なオブジェクトを 無理矢理 1つのベクトルにまとめようとすると、
> c( T, 1, 2.4, "a", matrix(1:6,nr=2))
 [1] "TRUE" "1"    "2.4"  "a"    "1"    "2"    "3"    "4"    "5"    "6"   
となって、もっとも一般的な原始オブジェクト(この場合、文字型)に強制変換され、 配列などの構造を潰して、一つのベクトルにしてしまう。

このようなタイプの異なるものを一つにして扱いたいときには list() と言う関数を使い、リストにすると、 元の構造を保存したまま、ひとつのオブジェクトとできる。

> L <- list( T, 1, 2.4, "a", matrix(1:6,nr=2))
> L
[[1]]:                  #一番目のリストの要素の
[1] T                   #  ベクトルの一番目の要素は 論理値 T

[[2]]:                  #二番目のリストの要素の
[1] 1                   #  ベクトルの一番目の要素は 整数 1

[[3]]:                  #三番目のリストの要素の
[1] 2.4                 #  ベクトルの一番目の要素は 実数 2.4

[[4]]:                  #四番目のリストの要素の
[1] "a"                 #  ベクトルの一番目の要素は 文字 a

[[5]]:                  #五番目のリストの要素は
     [,1] [,2] [,3]     #  整数の配列
[1,]    1    3    5
[2,]    2    4    6
ベクトル同様に、部分参照が出来るが、リストの場合には 二重カギカッコを使う。
> L[[2]]                #  リストの2番目の要素は 整数 1
[1] 1   

> L[[5]]                #  リストの5番目の要素は 配列 
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
リストに対して一重カギカッコも使えるが、この場合部分リストの抽出を することになる。結果は単一の要素の指定でもリストである。
> L[2:3]                #  リストの2、3番目要素の部分リストは
[[1]]:
[1] 1

[[2]]:
[1] 2.4

> L[2]                  #  リストの2番目要素の部分リストは
[[1]]:
[1] 1
また、リストの要素には名前を付けることができる。
> L <- list( L=T, N=1, C="a")
> L
$L:
[1] T

$N:
[1] 1

$C:
[1] "a"
この場合は、以下のように$を使って、名前でもリストの要素を参照できる。
> L$C
[1] "a"

オブジェクXの操作関数

X という名前のオブジェクトがあったとき、それを調べるには以下のような関数が使えます。 また、オブジェクトxが複数の要素を持つ場合、その部分を抽出するには、以下の方法があります。

4. 関数

既成の関数

関数は関数名の後に ( )で括った引数を並べて参照する。
> rnorm(10, 1, 2)  # 平均 1, 標準偏差 2 の正規乱数 10個
 [1]  1.8253494 -2.0670295  0.8855791  4.6236200  0.9862706 -1.1668234
 [7] -3.1592610  6.6921252 -0.5139193 -0.6347702
引数がないときにも ( )は省略できない。省略すると、 関数自身の定義を表示する (関数定義も一種のオブジェクトです)。
> ls()             # R環境にあるオブジェクトのリストを表示せよ。

> ls               # 関数オブジェクト ls の内容を表示せよ。

引数には名前がついているので、参照時に名前を記述すれは順番を変更してよい。 参照時に名前をつけずに引数並びに並べられた引数は、 名前指定で対応づけられた残りの関数定義中の引数と、引数並びでの順番を頼りに、 対応づけられる。 また、引数の名前は区別できる限り省略してよい。以下は、皆同じこととなる。

 rnorm(10, mean=1, sd=2)
 rnorm(10, sd=2, mean=1)
 rnorm(10, s=2, m=1)
 rnorm(10, s=2, 1)
 rnorm(10, 1, 2)

引数には省略時の値(デフォルト)が指定されているものがある。 たとえば、先ほどの関数 rnorm は次の1行目のように定義されている。 よって、 rnorm(10)と参照しても、上述の例と同じ結果になる。 なお、デフォルトの指定されていない引数は省略できない。

> rnorm                          # rnormという関数は
function(n, mean = 0, sd = 1)   # 左のようにn,mean,sd という引数を持つ関数で
                                 # mean,sd はデフォルトとして0,1が設定されている。
.Call(C_rnorm, n, mean, sd)


                                 # 実体は内部関数の呼び出しとなっている。

既存の関数についての疑問は 関数名が分かるものについてはオンラインマニュアルで調べるとともに、 その実体をみてみると良い。 たとえば、mean (平均を求める関数) の定義を表示させ、 ?mean で表示されるマニュアルの内容がどう実現されているのか、読取ってみよう。

> help(mean)            # mean という関数のヘルプをみせよ。
                        # unix のコマンド more とおなじ環境、キー"q"で出られる。
> ? mean                # (上の行に同じ)

> mean                  # 関数のオブジェクトとしての実体をみる。
最後の例のようにして、関数オブジェクトの実体をみると、 先頭行のfunctionの後ろから、 その関数がどんな引数を用い得るかがわかる。 また、その下の関数の中身をみることで、手続きとして何をしてくれるのかがわかる。
何かあることをしたいが、そんな関数があるかを調べたい時は、 R言語 クイック・リファレンス または、参考文献[1]のII巻の最後の索引などを調べる。

関数の適用

R言語での解析は、対象データのオブジェクトを関数に与え、 得たい結果のオブジェクトに変換していく過程として見ることができます。 元のデータを、外部ファイルから scan するとか、 内部で生成するなどして解析が始まります。 関数の返す結果もオブジェクトですから、それをさらに必要な関数に与えて、 変換して行きます。 たとえば、
> x <-  rnorm(100) # 正規乱数を 100 個 生成
> mean(x)          # その平均値をもとめる。
という調子です。上の結果を簡潔に求めるには、
> mean(rnorm(100))      
としても結構です。ただし、途中経過に自信がないときには、 前者のように一つずつ付値して、途中の内容を確認してゆく方が、 結局早道であることもあります。

行列などの一括処理

行列やリストなど複数の要素をもつオブジェクトの各要素に、 指定した関数をそれぞれ適用し、 そこで得られた結果をまとめて返してくれる オブジェクトの集約/変形( 反復構文の排除のための関数 )の関数 がある。 代表的なものに、apply()がある。次のように使う。
> x <- matrix(1:12,nc=3)
> x
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> apply(x,2,sum)
[1] 10 26 42
ここでは、4×3の行列xの、第2次元の反復の一つ一つについて、 他の反復(第1次元)を取りまとめたベクトルを作成して、 そのベクトルにsum()関数を適用した結果を、 長さ3(xの第2次元の大きさ)のベクトルとして返してくれている。 データ解析では、データに対して反復処理が必要になることが多いが、 一般の手続き型言語では、反復構文(ex. for文)で複数行の記述が必要になる処理が一文で書けることになる。

自作の関数

自分で関数を作りたい時には、functionという関数を用います。 以下に関数の構文とその例を示す。
my.log <-            
# 自家版対数関数(関数名 my.log。負の数の場合0を返す対数関数)
function(x=1)        # function(引数名1=引数1の省略値, 引数名2=引数2の省略値, ... )
{                        # 引数を使った関数本体始まり
  if( x>0 ) y <- log(x)  
  else      y <-  0      #    y の計算
  y                      #    この関数の返し値
}                        # 関数本体の定義の終了
上記の関数を 1行ずつコマンドラインから入力してみよ。 ( 各行を入力すると、 2行目以降はプロンプトが" > "から" + " に変わる。これは、まだ、その前の行での入力での 構文が閉じていないので、R が続きを要求している印である。 また、S 言語の各行のうち、# 以降の内容はコメントであると見なされて 構文解析されない。) その後、ただfun.exと入力すると、 入力した通りの関数オブジェクトが実現したかどうかを確認出来る。
> my.log 
# 自家版対数関数(関数名 my.log。負の数の場合0を返す対数関数)
function(x = 1)
{
        # 引数を使った関数本体始まり
        if(x > 0) y <- log(x) else y <- 0
        #    y の計算
        y
}
実行するには、下のように引数を具体的に括弧内に指定して実行してみれば良い。
> my.log(2)          # 関数の引数を 2としての参照
[1] 0.6931472
> my.log(-1)         # 関数の引数を -1としての参照
[1] 0
> my.log()           # 関数の引数を 省略しての参照
[1] 0                # x はデファオルトの1として計算される

長い関数を定義したいときには、適当なエディターのウィンドーを新らたに開いて、 その上で、関数をエディットして、マウスで Rのウィンドーへコピーするのが早い。 ( コピー内容が沢山の行にわたる場合、コピーに失敗する可能性が高くなるので注意する。 本当にとても長い関数を定義したいときには、 source("ファイル名") コマンドなどで、 定義を記述したファイルを R環境に直接読み込む。 本格的に使う場合には、 RStadio をインストールするのがよいでしょう。 なお、エディターとしてemacs を使っていれば、そこで M-x shell を実行して、 emacs 上で R言語 を実行するという方法もあります。

関数の返し値は、その関数本体の最後の文の値となる。 返し値として複数のオブジェクトを返したいときには、 それらのリスト (同種の数値ベクトルなら配列でもよい。複雑な構造を返したいときには "クラス"を定義してそれを返すことも行われる。)を 返すのが標準である。 また、途中で関数を終了して、値を返すために return(返し値)がある。

制御構造としては、for, while, repeatも揃っている。

> x <- 1:10
> rslt<-NULL; for(a in x) rslt<-c(rslt,ifelse(a %% 2 ==1,"o","e"))
 # x の要素が偶奇に応じた"o","e"のベクトルを作る。
ここでは、 rsltを空 ( NULL )として用意して、その後、 x の要素を一個ずつ a へ取り出し、その偶奇に応じた文字を rsltに連結している。 後で要素を反復的に追加してゆこうとする初期値(オブジェクト)を 用意するためにはこのように NULL を用いる。 セミコロン ; で結ぶことにより、複数の文を1行中に書ける。 また、制御構造のブロックを作るためには中括弧 { }を使う。 また、反復中に、反復を終了させる breakや、今回の反復を中止して、 次の反復へ進む nextもある ( break nextは、 使わないで済む算法を考えた方が良いが。いやその前に、 適切な配列などのデータ形式を利用していれば、 反復構文自体を使わないで書ける場合が多い。 ( ifelse(x %% 2 ==1,"o","e") の結果は何になるか?) そのためには ベクトル/行列演算論理演算子と参照などの機能や、applyなどの データ集約 にまとめた適当な関数などを用いれば良い。 (最初のうちは簡潔に書くことを気にしすぎなくても良いが。))
  for( el in x ){          # 
    if( el%%3 == 0 ) next  # el が 3 の倍数だったら、反復の先頭へ戻れ。
    if( el > 7 ) break     # el が 7 より大きかったら、反復を終了せよ。
    cat(" ",el,"\n")       # el を表示せよ。
  }
印刷制御文字は C言語と同じで、たとえば、"\n"で改行が行われる。

もう一つ関数の例をあげておく。

get.prime<-
function( n=20 ){     # n 番目までの素数を求める。
  p <- 1
  prime.list <- 2
  while(length(prime.list) < n){    # 素数リストの長さが n 未満な限り以下を実行
    p<-p+2                          # 新規の素数候補を p とする。
    if( all(p%%prime.list != 0 ) )  # 既存の素数での剰余が 全て 0 でないなら、
      prime.list<-c(prime.list,p)   # 素数リストに p を追加。
  }
  prime.list                        # 素数リストを返す。
}
以上詳しくは、マニュアル[1]を参照されたい。

5. グラフィック環境

【ヒストグラム】図を生成する関数呼び出しを行うとグラフィックウィンドーが開く。 たとえば、
> hist( rnorm(1000) )
とすれば、平均 0, 標準偏差 1 の正規乱数 1000個のヒストグラムをそのウィンドーに 表示してくれる。
> hist( rnorm(1000), n=100 ) # 階級の数を100にしよう
> hist( rnorm(100000), n=100 ) # データの数を増やしてみよう
階級を細かく指定したいときには、breaksというオプションで階級の区分点を指定できる。
> hist( rbinom(200,10,0.4), breaks=-0.5:10.5 )
表題や日付を図に付けたいときには、以下のようにすればよい。
> hist( rbinom(200,10,0.4), breaks=-0.5:10.5, main="200個の二項乱数 b(10,0.4)" ) 
ヒストグラムの書き方のページも参考にしてください。

【散布図】関数 plot()は、同じ長さの引数を2つ取って、 座標を適当に設定してから、散布図を書いてくれる。

> x<-rnorm(500); y<-x+rnorm(500)
> plot(x,y)
表記する範囲を指定したければ、次のような指定を追加すれば良い。
> plot(x,y,xlim=c(-4,4),ylim=c(-6,6))

既存の座標上に線を追加したければ、

> lines(c(min(x),max(x)),2*c(min(x),max(x)))
タイトルを追加したいときには次が使える。
> title( "銀河?" )
などの関数もある。 普通の線グラフも関数 plot()で書ける。
> x<-(-300:300)*0.01
> plot(x,dnorm(x),ylim=c(0,1),type="l")
> lines(x,dnorm(x,sd=0.5))
引数 typeはプロットの形式を定めるもので、 "p","l","b","n","h" などで、それそれ、 点プロット(省略時)、 線プロット、 点と線のプロット、 軸のみでプロットしない、 各点からの垂線プロット を意味する。 その他のグラフの表示形式 (軸の引き方、軸名の付け方、表題の付け方などなど) については、関数 par()をマニュアルで参照されたい。

postscript形式のファイルだけが欲しい場合には、コマンドラインから
> postscript(file="ファイル名")

  plot など作図のためのコマンドの実行

>dev.off()
をすればよい。 dev.off()で作図機器(postscript)を閉じたときにファイル出力が実行される。 途中経過は motif の画面には出力されない(postscriptファイルに出力される)ので、 実施する plot など作図のためのコマンドで どんな画面が作成されるのか、事前に端末画面で描画して確認してから実行するとよい。 他のファイル形式についても、それぞれコマンドが用意されているので調べられたい。

描画した結果をLATEXの文書の中で用いるには、 LATEXの文書中で、LATEXコマンド\epsfileなど用いれば良い。 (例)

6. 最後に(受講学生へ)

やって見てわからないこと、どうもシステムがマニュアルどおり動いていない?、 このメモの誤りを見付けたなど、なんでも関まで問い合わせて下さい。 わかる事はお答えしますし、不具合は善処します。 メイルでも結構です。

注意: