R入門(2)

前の資料へ

関数

関数とは、さまざまな処理をひとまとめにして名前をつけ、あとから簡単に 呼び出して使えるようにしたものです。 すでに cat と source という関数がありましたが、 R には、ほかにも、 さまざまな統計計算、グラフの描画等、の関数が用意されています。

R の関数は他のプログラミング言語同様、命令のかたまり(モジュール)です。 R の関数を使うときにかならずしも値を渡さなくてもよいですし、関数は意味 のある計算結果を返さない場合もあります。呼ばれたときに行われるさまざま な動作(たとえば画面に Hello, world と 表示するような)が主な機能という 関数も多いです。

VBA の Sub プロシージャと Function プロシージャのどちらの役割も R では 「関数」でおこなう、ということです。
R では元々用意されている関数だけでなく、自分で関数を書いて使うことがで きます。一連の処理を書き、それに関数としての名前をつけ、後で使えるよう にします。R の関数を定義する、すなわち処理と名前を結びつけて名前で処理 を呼べるようにするには、以下のようにします。
関数名 <- function(もしあれば引数の名前)
{
    処理の内容
}
この書き方は変数に値を代入したときと似ています。 <- の前に名前(前は変 数の、今度は関数の)を書き、 <- のあとにはその名前で呼び出したい内容 (先程は変数の値、今度は関数の処理内容)を書きます。
JavaScript も同じような書き方ができます。これは、関数をオブジェクトとし て扱える言語ということなのですが、ここでは詳細は略します。
前述の挨拶プログラムを関数として定義するには プログラムファイルの内容を 以下のように書き換えます(これを hello4.R という名前で名前をつけて保存 しなおしてください)。
hello.goodby <- function()
{
    x <- ('Hello, world\n')  #  あいさつの文字列を変数 x に代入する。
    cat(x)                   #  変数 x を関数 cat に渡す。
    x <- ('good bye, world\n')   #  別のあいさつを変数 x に代入する。
    cat(x)                       #  ふたたび変数 x を関数 cat に渡す。
}
そして source('hello4.R') と入力してプログラムを読み込みます。
source() を入力する前に、先週の授業資料にあった↓を忘れず 実行するようにしてください。
R が注目する作業ディレクトリを、このプログラムファイルが置いてある 練習用ディレクトリに変更します。やりかたは、まず「ファイル」メニュー から「ディレクトリの変更」を選択し、「フォルダーの参照」が表示され ますので、「rdata」フォルダを選択すれば完了です。
あるいは source('I:/rdata/hello4.R') のようにフルパスで指定してくださ い。来週以降も同様です(!)
この段階 では、R に関数の処理内容と名前を教えただけなので、実行はされません。続 けて hello.goodby() と入力してみましょう。関数が呼び出され挨拶が表示さ れるはずです。

次は引数を与える例です。

hello.to.you <- function(to.whom)
{
    cat('Hello,', to.whom, '.\n')    # cat に表示させたいものは、いくつも並べて渡せる。
    cat('good by,', to.whom ,'.\n') 
}
関数名に使える文字は変数名と同じです。hello4.R に上の内容を書きたして source('hello4.R')で読み込みます。 その上で、例えば以下のように挨拶させ たい人の名前を引数として渡して関数 hello.to.you を呼び出します。 引数と して文字列を与えるときは、 引用符で囲む ことを忘れないように します。引用符がないと変数名とみなされます。
hello.to.you('maechan')
なお R は、source 関数を使って読み込んだプログラムファイルが、読み込ん だ後でエディタで編集されたかどうかを知ることは当然ながらできません。で すので、プログラムファイルを編集した後はあらためてsourceで 読み込 み直さ ないと、いつまでも前に読み込んだものが有効になっています。
<練習>
  1. hello.to.you を実行してみましょう。
  2. 引数に日本語の文字列を与えて、正常に表示されるかどうか確かめてみましょう。

補足:インデントについて

上の関数の例で、{ と } で挟まれた関数の内容は、4文字分下げて書かれてい ます。このように字下げとすることを インデント といいます。文 法上はインデントは無視されるのであってもなくてもよいのですが、構造を把 握しやすくするためにされることが多いです。このように書けば、他にいろい ろな処理が書かれたプログラムでも、どこからどこまでが関数の定義か理解し やすいです。
ちなみに python というプログラミング言語では、インデントでブロックを表 現するという文法になっているので、インデントは必須です。
後で、このようなインデントが何重にも入れ子になる例もでてきます。繰り返 しのfor 構文や while 構文、条件判断の if 構文など、複雑な構造のプログラ ムほど、きちんと字下げしてその構造を明示することが重要です。プログラム を読んで処理内容を理解するためだけでなく、バグを探したり修正して再利用 したりするためにも、プログラムが見やすく書かれていることが大切です。最 初は手間かもしれませんが、 { と } で囲まれた中はインデントする習慣をつ けましょう。

関数の命名

プログラムを書くときは、最初は関数にはせずファイルに一連の処理内容を書 いて source('プログラムファイル名') だけで実行して動作を確認するのがよ いでしょう。そして、期待通りに動くようになったら関数として定義して名前 を付けます。関連する自作関数がほかにもあるなら、まとめてひとつのファイ ルに入れておくと管理しやすいかもしれません。関数として定義すると、他の プログラムからも呼び出せます。

関数の名前は、内容が分かる(少なくとも想像可能な)名前にすることと、す でに存在する関数名とダブらないことに注意して決めます。すでに使われてい る名前かどうかを知るには、R の入力画面にその名前を打ち込みます。その時 にカッコは付けてはいけません。カッコをつけると、関数を実行させることに なります。すでに存在する関数の名前を入力すると、その内容(プログラムコー ド)が表示されます。

<練習>
  1. R の入力画面に cat や source と入力し、それらのプログラムコードが 表示されることを確認しましょう。
  2. 自作のプログラムファイル hello4.R を source で読み込んだあと、 hello.to.you と入力してプログラムコードが表示されることを確認してみましょ う。
  3. すでに用意されている関数の場合、関数名の前に ? を書くと、使用法が 表示されますので ?cat とか ?source とか入力してためしてみましょう。

R のデータ型

上では詳細を略していましたが、Rのデータ型にはスカラ(単一のデータ)型と して があります。そもそも、なぜ(変数に、データの)型が必要かについては なぜ変数に型は必要か? (プログラミング入門補助資料なのでVBAを前 提としています)等を参考にしてください。
それぞれは、他の言語とほぼ同様の使い方をします。これらは必要に応じて説 明します。
さらに、スカラ型ではない、つまり複数のデータを取り扱うためのデータ型と して、 があります。以下にそれぞれ説明 します。

ベクトル

1次元(1行または1列) のデータセットをベクトル (Vector)と呼びま す。Excel での1行(列)のデータに対応します。他の言語では配列と読んで いるものにほぼ対応しますが、順序でデータを指定することはできません。つ まりExcel での行データでいうと、A列目,B列目のような指定ができないという ことです。順序で指定したい場合にはR では配列 (array) というデータ型を使 います(後述)。
そもそも 次元とは何か? については稿を改めて説明する予定です。

【ソースコード】

price <- c(108,216,162,97) # price object に vector dataを代入
pname <- c("A", "B", "C", "D") # pname object に vector dataを代入
names(price)<- pname # price のラベルを pnameにする 
price # price を出力
price^2 # priceの2乗を出力
mean(price) #price vector の要素の平均を出力
round(mean(price),0) # price vector の要素の平均の小数点以下を四捨五入
length(price) # price vector の要素数を出力
c() という関数は Combine の意で、複数のデータを引数として、それらを束ね たベクトルを作って返り値とするものです。

【実行結果】

> price <- c(108,216,162,97) # price object に vector dataを代入
> pname <- c("A", "B", "C", "D") # pname object に vector dataを代入
> names(price)<- pname # price のラベルを pnameにする 
> price # price を出力
  A   B   C   D 
108 216 162  97 
> price^2 # priceの2乗を出力
    A     B     C     D 
11664 46656 26244  9409 
> mean(price) #price vector の要素の平均を出力
[1] 145.75
> round(mean(price),0) # price vector の要素の平均の小数点以下を四捨五入
[1] 146
> length(price) # price vector の要素数を出力
[1] 4

行列(マトリクス)

行列、すなわち2次元(の表) のデータを表します。ちなみに数学 用語で行列をマトリクスといいます。これは Excel でのテーブルに近いです。 Rには、いわゆる の表現として、行列とデータフレームが用意 されていて、個々のデータが全て数値として扱う場合に行列を用います。行列 用の演算子も用意されています(後述)。データが混在している場合には後述 のデータフレームを用います。

【ソースコード】

price <- matrix(0,2,4) # 要素が 0 の 2行4列の行列を定義する
price # 行列 price を表示
pname <- c("A", "B", "C", "D")
cityname <- c("Osaka","Tokyo")
colnames(price)<- pname # price の列ラベルを pnameにする 
rownames(price)<- cityname # price の行ラベルを citynameにする 
price[1,] <- c(105,202,155,91) # 1 行目に Vector を 入力
price[2,] <- c(108,216,162,97) # 2 行目に Vector を 入力
price # 行列 price を表示
dim(price) # price の次元(サイズ)を求める
nrow(price) # price の行数を求める
ncol(price) # price の列数を求める
(price[2,3] <- 156) # 数値を代入してその結果を出力する。()で囲まないと代入だけして無言。

【実行結果】

> price <- matrix(0,2,4) # 要素が 0 の 2行4列の行列を定義する
> price # 行列 price を表示
     [,1] [,2] [,3] [,4]
[1,]    0    0    0    0
[2,]    0    0    0    0
> pname <- c("A", "B", "C", "D")
> cityname <- c("Osaka","Tokyo")
> colnames(price)<- pname # price のラベルを pnameにする 
> rownames(price)<- cityname # price のラベルを pnameにする 
> price[1,] <- c(105,202,155,91) # 1 行目に Vector を 入力
> price[2,] <- c(108,216,162,97) # 2 行目に Vector を 入力
> price # 行列 price を表示
        A   B   C  D
Osaka 105 202 155 91
Tokyo 108 216 162 97
> dim(price) # price の次元(サイズ)を求める
[1] 2 4
> nrow(price) # price の行数を求める
[1] 2
> ncol(price) # price の列数を求める
[1] 4
> (price[2,3] <- 156) # 数値を代入してその結果を出力する
[1] 156
最後の入力は、代入式に()がついていることに注意が必要です。こうするこ とで、代入した値を式自体の値として評価させる(コンソール出力する)こと が出来ます。

データフレーム

データフレームは行列と同じ 2 次元の配列ですが、データフレームの各行・列 はラベルを必ず持ちラベルによる操作が可能です。Excel のテーブルに さらに近いかもしれません。さらに、各列の要素の型は バラバラでも構ません。データフレームは関数 data.frameを用いて作成するこ とができます。データフレームから行列への変換は as.matrix を用います。逆 に、行列からデータフレームに変換するのには関数 as.data.frame を用います。

【ソースコード】

df <- data.frame(cbind(LETTERS[1:4], 1:4)) # cbindは同じ長さのデータを列単位に結合する関数
colnames(df) <- c("Symbol","Number") # 列の名前をつける
df # 出力
as.matrix(df) # df を matrix に変換
ここで、1:4 で 1,2,3,4 という連続した数を表現できることに注意が必要です。

【実行結果】

> df <- data.frame(cbind(LETTERS[1:4], 1:4)) # cbindは同じ長さのデータを列単位に結合する関数
> colnames(df) <- c("Symbol","Number") # 列の名前をつける
> df # 出力
  Symbol Number
1      A      1
2      B      2
3      C      3
4      D      4
> as.matrix(df) # df を matrix に変換
     Symbol Number
[1,] "A"    "1"   
[2,] "B"    "2"   
[3,] "C"    "3"   
[4,] "D"    "4"  

配列

配列とは行列を多次元に拡張したものです.行列は 2 次元ですが、配列はその 次元に応じて 3 次元、4 次元、…と、制限なく作成することが出来ます。 配列は以下の手順で作成出来ます。

【ソースコード】

ar <- array(0:19, c(2,5,2)) #2 × 5 × 2 の配列に、0 から 19までの値を入れ 作成する。
ar # 出力

【実行結果】

> ar <- array(0:19, c(2,5,2)) #2 × 5 × 2 の配列に、0 から 19までの値を入れ 作成する。
> ar # 出力
, , 1

     [,1] [,2] [,3] [,4] [,5]
[1,]    0    2    4    6    8
[2,]    1    3    5    7    9

, , 2

     [,1] [,2] [,3] [,4] [,5]
[1,]   10   12   14   16   18
[2,]   11   13   15   17   19

リスト

リストはベクトル、行列、データフレーム、配列、さらにはリスト自身等の異 なる型のデータをひとつのオブジェクトとして扱うことが可能なオブジェクト です。リストは関数 list を用いて作成します。

【ソースコード】

l <- list(c(0:5), c("A","B"), matrix(0:9,2,5)) # それぞれを要素に持つlistを作成する
l # 出力

【実行結果】

> l <- list(c(0:5), c("A","B"), matrix(0:9,2,5)) # それぞれを要素に持つlistを作成する
> l # 出力
[[1]]
[1] 0 1 2 3 4 5

[[2]]
[1] "A" "B"

[[3]]
     [,1] [,2] [,3] [,4] [,5]
[1,]    0    2    4    6    8
[2,]    1    3    5    7    9

データ型の確認

関数 class でデータ型をチェックすることができます。

【ソースコード】

v <- c(108,216,162,97) # vector
class(v) # 型 出力
m <- matrix(0,2,4) # matrix
class(m) # 型 出力
df <- data.frame(cbind(LETTERS[1:4], 1:4)) # data.frame
class(df) # 型 出力
a <- array(0:19, c(2,5,2)) # array
class(a) # 型 出力
l <- list(c(0:5), c("A","B"), matrix(0:9,2,5)) # list
class(l) # 型 出力

is.vector(v) # v が vector か check
is.vector(m) # m が vector か check
is.list(v) # v が list か check
is.list(l) # l が list か check

【実行結果】

> v <- c(108,216,162,97) # vector
> class(v) # 型 出力
[1] "numeric"
> m <- matrix(0,2,4) # matrix
> class(m) # 型 出力
[1] "matrix"
> df <- data.frame(cbind(LETTERS[1:4], 0:3)) # data.frame
> class(df) # 型 出力
[1] "data.frame"
> a <- array(0:19, c(2,5,2)) # array
> class(a) # 型 出力
[1] "array"
> l <- list(c(0:5), c("A","B"), matrix(0:9,2,5)) # list
> class(l) # 型 出力
[1] "list"
> 
> is.vector(v) # v が vector か check
[1] TRUE
> is.vector(m) # m が vector か check
[1] FALSE
> is.list(v) # v が list か check
[1] FALSE
> is.list(l) # l が list か check
[1] TRUE

補足:代入表現

Rでは実は以下の3つの代入式と、代入関数 assign が使えます。
x <- c(10,20,30,40) 

x = c(10,20,30,40) 

c(10,20,30,40) -> x

assign("x", c(10,20,30,40)) 
ただし、 <-, -> については記号の間は空白 を入れてはいけない(他の場合は大抵無視されるだけ)ということも注意が必 要です。

実際に次のソースを実行すると、以下の【実行結果】 になります。

【ソースコード】

price1 <- c(10,20,30,40)
price1 
price2 = c(10,20,30,40) 
price2
c(10,20,30,40) -> price3
price3
assign("price4", c(10,20,30,40)) 
price4

【実行結果】

>price1 <- c(10,20,30,40) 
> price1 
[1] 10 20 30 40
> 
> price2 = c(10,20,30,40) 
> price2
[1] 10 20 30 40
> 
> assign("price3", c(10,20,30,40)) 
> price3
[1] 10 20 30 40
> 
> c(10,20,30,40) -> price4
> price4
[1] 10 20 30 40

次の資料へ
目次にもどる
講義用スタイル
印刷用スタイル