1 + 2[1] 3
2 - 3[1] -1
3 * 4[1] 12
6 / 3[1] 2
ここから実際にR/RStudioをつかった演習に入る。前回すでに言及したように,この講義用のプロジェクトを準備し,RStudioはプロジェクトが開かれた状態であることを前提に話を進める。
まずはRを使った計算である。Rスクリプトファイルを開き,最初の行に次の4行を入力してみよう。 各行を実行(Runボタン,あるいはctrl+enter)し,コンソールの結果を確認しよう。
1 + 2[1] 3
2 - 3[1] -1
3 * 4[1] 12
6 / 3[1] 2
それぞれ加減乗除の計算結果が正しく出ていることを確認してほしい。なお,出力のところに[1]とあるのは,Rがベクトルを演算の基本としているからで,回答ベクトルの第1要素を返していることを意味する。
四則演算の他に,次のような演算も可能である。
# 整数の割り算
8 %/% 3[1] 2
# 余り
7 %% 3[1] 1
# 冪乗
2^3[1] 8
ここで,#から始まる行はコメントアウトされたものとして,実際にコンソールに送られても計算されないことに注意しよう。スクリプトが単純なものである場合はコメントをつける必要はないが,複雑な計算になったり,他者と共有するときは「今どのような演算をしているか」を逐一解説するようにすると便利である。
実践上のテクニックとして,複数行を一括でコメントアウトしたり,アンコメント(コメントアウトを解除する)したりすることがある。スクリプトを複数行選択した上で,CodeメニューからComment/Uncomment Linesを押すとコメント/アンコメントを切り替えられるので試してみよう。また,ショートカットキーも確認し,キーからコメント/アンコメントができるように慣れておくと良い(Ctrl+↑+C/Cmd+↑+C)。
One more tip.コメントではなく,大きな段落的な区切り(セクション区切り)が欲しいこともあるかもしれない。Codeメニューの一番上に「Insert Section」があるのでこれを選んでみよう。ショートカットキーから入力しても良い(Ctrl+↑+R/Cmd+↑+R)。セクション名を入力するボックスに適当な命名をすると,スクリプトにセクションが挿入される。次に示すのがセクションの例である。
# 計算 --------------------------------------------------------------これはもちろん実行に影響を与えないが,ソースが長くなった場合はこのセクション単位で移動したり(スクリプトペインの左下),アウトラインを確認したり(スクリプトペインの右上にある横三本線)できるので,活用して欲しい。
Rでは変数,関数などあらゆるものをオブジェクトとしてあつかう。オブジェクトには任意の名前をつけることができる(数字から始まる名前は不可)。 オブジェクトを作り,そこにある値を代入する例は次の通りである。
a <- 1
b <- 2
A <- 3
a + b # 1 + 2におなじ[1] 3
A + b # 3 + 2におなじ[1] 5
ここでは数字をオブジェクトに保管し,オブジェクトを使って計算をしている。大文字と小文字が区別されてるため,計算結果が異なることに注意。
代入に使った記号<-は「小なり」と「ハイフン」であるが,左矢印のイメージである。次のように,=や->を使うこともできる。
B <- 5
7 -> Aここで,二行目に7 -> Aを行った。先ほどA <- 3としたが,その後にAには7を代入し直したので,値は上書きされる。
A + b # 7 + 2におなじ[1] 9
このように,オブジェクトに代入を重ねると,警告などなしに上書きされることに注意して欲しい。似たようなオブジェクト名を使い回していると,本来意図していたものと違う値・状態を保管していることになりかねないからである。
ちなみに,オブジェクトの中身を確認するためには,そのままオブジェクト名を入力すれば良い。より丁寧には,print関数を使う。
a[1] 1
print(A)[1] 7
あるいは,RStudioのEnvironmentタブをみると,現在Rが保持しているオブジェクトが確認でき,単一の値の場合はValueセクションにオブジェクト名と値を見ることができる。
注意点として,オブジェクト名として,次の名前は使うことができない。> break, else, for, if, in, next, function, repeat, return, while, TRUE, FALSE.
これらはRで特別な意味を持つ予約語と呼ぶ。特にTRUEとFALSEは真・偽を表すもので,大文字のT,Fでも代用できるため,この一文字だけをオブジェクト名にするのは避けた方が良い。また,TとFは予約語ではないため,オブジェクト名として使用可能だが,混乱を避けるため使用は推奨されない。
関数は一般に\(y=f(x)\)と表されるが,要するに\(x\)を与えると\(y\)に形が変わる作用のことを指す。 プログラミング言語では一般に,\(x\)を引数(ひきすう,argument),\(y\)を戻り値(もどりち,value)という。以下,関数の使用例を挙げる。
sqrt(16)[1] 4
help("sqrt")最初の例は平方根square rootを取る関数sqrtであり,引数として数字を与えるとその平方根が返される。第二の例は関数の説明を表示させる関数helpであり,これを実行するとヘルプペインに関数の説明が表示される。
先ほどのhelp関数に与えた引数"sqrt"は文字列である。文字列であることを明示するためにダブルクォーテーション(")で囲っている(シングルクォーテーションで囲っても良い)。このように,Rが扱う変数は数字だけではない。変数の種類は数値型(numeric),文字型(character),論理値(logical)の3種類がある。
obj1 <- 1.5
obj2 <- "Hello"
obj3 <- TRUE数値型は整数(integer),実数(double)を含み1,そのほか,複素数型(complex),欠測値を表すNA,非数値を表すNaN(Not a Number),無限大を表すInfなどがある。
文字型はすでに説明した通りで,対になるクォーテーションが必要であることに注意してほしい。終わりを表すクォーテーションがなければ,Rは続く数字や文字も含めた「語」として処理する。この場合,enterキーを押しても文字入力が閉じられていないため,コンソールには「+」の表示が出る(この記号は前の行から入力が続いており,プロンプト状態ではないことを表している)。
また,文字型は当然のことながら四則演算の対象にならない。ただし,論理型のTRUE/FALSEはそれぞれ1,0に対応しているため,計算結果が表示される。次のコードを実行してこのことを確認しよう。
obj1 + obj2
obj1 + obj3ここまでみてきたように,数値や文字など(まとめてリテラルという)にも種類があるが,これをストックしておくものは全てオブジェクトである。オブジェクトとは変数のこと,と理解しても良いが,関数もオブジェクトに含まれる。
Rのオブジェクトは単一の値しか持たないものではない。むしろ,複数の要素をセットで持つことができるのが特徴である。次に示すのは,ベクトルオブジェクトの例である。
vec1 <- c(2, 4, 5)
vec2 <- 1:3
vec3 <- 7:5
vec4 <- seq(from = 1, to = 7, by = 2)
vec5 <- c(vec2, vec3)それぞれのオブジェクトの中身を確認しよう。 最初のc()は結合combine関数である。また,コロン(:)は連続する数値を与える。 seq関数は複数の引数を取るが,初期値,終了値,その間隔を指定した連続的なベクトルを生成する関数である。
ベクトルの計算は要素ごとに行われる。次のコードを実行し,どのように振る舞うか確認しよう。
vec1 + vec2[1] 3 6 8
vec3 * 2[1] 14 12 10
vec1 + vec5[1] 3 6 8 9 10 10
最後の計算でエラーが出なかったことに注目しよう。たとえばvec1 + vec4はエラーになるが,ここでは計算結果が示されている(=エラーにはなっていない)。数学的には,長さの違うベクトルは計算が定義されていないのだが,vec1の長さは3,vec5の長さは6であった。Rはベクトルを再利用するので,長いベクトルが短いベクトルの定数倍になるときは反復して利用される。すなわち,ここでは \[ (2,4,5,2,4,5) + (1,2,3,7,6,5) = (3,6,8,9,10,10)\]
の計算がなされた。このRの仕様については,意図せぬ挙動にならぬよう注意しよう。
ベクトルの要素にアクセスするときは大括弧([ ])を利用する。 特に第二・第三行目のコードの使い方を確認しておこう。大括弧の中は,要素番号でも良いし,真/偽の判断でも良いのである。この真偽判断による指定の方法は,条件節(if文)をつかって要素を指定できるため,有用である。
vec1[2][1] 4
vec2[c(1, 3)][1] 1 3
vec2[c(TRUE, FALSE, TRUE)][1] 1 3
ここまで,ベクトルの要素は数値で説明してきたが,文字列などもベクトルとして利用できる。
words1 <- c("Hello!", "Mr.", "Monkey", "Magic", "Orchestra")
words1[3][1] "Monkey"
words2 <- LETTERS[1:10]
words2[8][1] "H"
ここでLETTERSはアルファベット26文字が含まれている予約語ベクトルである。
ベクトルを引数に取る関数も多い。たとえば記述統計量である,平均,分散,標準偏差,合計などは,次のようにして計算する。
dat <- c(12, 18, 23, 35, 22)
mean(dat) # 平均[1] 22
var(dat) # 分散[1] 71.5
sd(dat) # 標準偏差[1] 8.455767
sum(dat) # 合計[1] 110
他にも最大値maxや最小値min,中央値medianなどの関数が利用可能である。
数学では線型代数でベクトルを扱うが,同時にベクトルが複数並んだ二次元の行列も扱うだろう。 Rでも行列のように配置したオブジェクトを利用できる。
次のコードで作られる行列\(A\),\(B\)がどのようなものか確認しよう。
A <- matrix(1:6, ncol = 2)
B <- matrix(1:6, ncol = 2, byrow = T)行列を作る関数matrixは,引数として要素,列数(ncol),行数(nrow),要素配列を行ごとにするかどうかの指定(byrow)をとる。ここでは要素を1:6としており,1から6までの連続する整数をあたえている。ncolで2列であることを明示しているので,nrowで行数を指定してやる必要はない。byrowの有無でどのように数字が変わっているかは表示させれば一目瞭然であろう。
与える要素が行数\(\times\)列数に一致しておらず,ベクトルの再利用も不可能な場合はエラーが返ってくる。
また,ベクトルの要素指定のように,行列も大括弧を使って要素を指定することができる。行,列の順に指定し,行だけ,列だけの指定も可能である。
A[2, 2][1] 5
A[1, ][1] 1 4
A[, 2][1] 4 5 6
行列はサイズの等しいベクトルのセットであるが,サイズの異なる要素をまとめて一つのオブジェクトとして保管しておきたいときはリスト型をつかう。
Obj1 <- list(1:4, matrix(1:6, ncol = 2), 3)このオブジェクトの第一要素([[1]])はベクトル,第二要素は行列,第三要素は要素1つのベクトル(スカラー)である。オブジェクトの要素の要素(ex.第二要素の行列の2行3列目の要素)にどのようにアクセスすれば良いか,考えてみよう。
このリストは要素へのアクセスの際に[[1]]など数字が必要だが,要素に名前をつけることで利便性が増す。
Obj2 <- list(
vec1 = 1:5,
mat1 = matrix(1:10, nrow = 5),
char1 = "YMO"
)この名前付きリストの要素にアクセスするときは,$記号を用いることができる。
Obj2$vec1[1] 1 2 3 4 5
これを踏まえて,名前付きリストの要素の要素にアクセスするにはどうすれば良いか,考えてみよう。
リスト型はこのように,要素のサイズ・長さを問わないため,いろいろなものを保管しておくことができる。統計関数の結果はリスト型で得られることが多く,そのような場合,リストの要素も長くなりがちである。リストがどのような構造を持っているかを見るために,str関数が利用できる。
str(Obj2)List of 3
$ vec1 : int [1:5] 1 2 3 4 5
$ mat1 : int [1:5, 1:2] 1 2 3 4 5 6 7 8 9 10
$ char1: chr "YMO"
str関数の返す結果と同じものが,RStudioのEnvironmentタブからオブジェクトを見ることでも得られる。 また,リストの要素としてリストを持つ,すなわち階層的になることもある。そのような場合,必要としている要素にどのようにアクセスすれば良いか,確認しておこう。
Obj3 <- list(Obj1, Second = Obj2)
str(Obj3)List of 2
$ :List of 3
..$ : int [1:4] 1 2 3 4
..$ : int [1:3, 1:2] 1 2 3 4 5 6
..$ : num 3
$ Second:List of 3
..$ vec1 : int [1:5] 1 2 3 4 5
..$ mat1 : int [1:5, 1:2] 1 2 3 4 5 6 7 8 9 10
..$ char1: chr "YMO"
リスト型は要素のサイズを問わないことはすでに述べた。しかしデータ解析を行うときは得てして,2次元スプレッドシートのような形式である。すなわち一行に1オブザベーション,各列は変数を表すといった具合である。このように矩形かつ,列に変数名を持たせることができる特殊なリスト型をデータフレーム型という。以下はそのようなオブジェクトの例である。
df <- data.frame(
name = c("Ishino", "Pierre", "Marin"),
origin = c("Shizuoka", "Shizuoka", "Hokkaido"),
height = c(170, 180, 160),
salary = c(1000, 20, 800)
)
# 内容を表示させる
df name origin height salary
1 Ishino Shizuoka 170 1000
2 Pierre Shizuoka 180 20
3 Marin Hokkaido 160 800
# 構造を確認する
str(df)'data.frame': 3 obs. of 4 variables:
$ name : chr "Ishino" "Pierre" "Marin"
$ origin: chr "Shizuoka" "Shizuoka" "Hokkaido"
$ height: num 170 180 160
$ salary: num 1000 20 800
ところで,心理統計の初歩としてStevensの尺度水準(Stevens 1946)について学んだことと思う。そこでは数値が,その値に許される演算のレベルをもとに,名義,順序,間隔,比率尺度水準という4つの段階に分類される。間隔・比率尺度水準の数値は数学的な計算を施しても良いが,順序尺度水準や名義尺度水準の数字はそのような計算が許されない(ex.2番目に好きな人と3番目に好きな人が一緒になっても,1番好きな人に敵わない。)
Rには,こうした尺度水準に対応した数値型がある。間隔・比率尺度水準は計算可能なのでnumeric型でよいが,名義尺度水準はfactor型(要因型,因子型とも呼ばれる),順序尺度水準はordered.factor型と呼ばれるものである。
factor型の変数の例を挙げる。すでに文字型として入っているものをfactor型として扱うよう変換するためには,as.factor関数が利用できる。
df$origin <- as.factor(df$origin)
df$origin[1] Shizuoka Shizuoka Hokkaido
Levels: Hokkaido Shizuoka
要素を表示させて見ると明らかなように,値としてはShizuoka,Shizuoka,Hokkaidoの3つあるが,レベル(水準)はShizuoka,Hokkaidoの2つである。このようにfactor型にしておくと,カテゴリとして使えて便利である。
次に示すのは順序つきfactor型変数の例である。
# 順序付き要因型の例
ratings <- factor(c("低い", "高い", "中程度", "高い", "低い"),
levels = c("低い", "中程度", "高い"),
ordered = TRUE
)
# ratingsの内容と型を確認
print(ratings)[1] 低い 高い 中程度 高い 低い
Levels: 低い < 中程度 < 高い
集計の際などはfactor型と違わないため,使用例は少ないかもしれない。しかしRは統計モデルを適用する時に,尺度水準に対応した振る舞いをするものがあるので,データの尺度水準を丁寧に設定しておくのも良いだろう。
データフレームの要素へのアクセスは,基本的に変数名を介してのものになるだろう。たとえば先ほどのオブジェクトdf の数値変数に統計処理をしたい場合は,次のようにすると良い。
mean(df$height)[1] 170
sum(df$salary)[1] 1820
また,データフレームオブジェクトを一括で要約する関数もある。
summary(df) name origin height salary
Length:3 Hokkaido:1 Min. :160 Min. : 20.0
Class :character Shizuoka:2 1st Qu.:165 1st Qu.: 410.0
Mode :character Median :170 Median : 800.0
Mean :170 Mean : 606.7
3rd Qu.:175 3rd Qu.: 900.0
Max. :180 Max. :1000.0
解析の実際では,データセットを手入力することはなく,データベースから取り出してくるか,別ファイルから読み込むことが一般的であろう。
統計パッケージの多くは独自のファイル形式を持っており,Rにはそれぞれに対応した読み込み関数も用意されているが,ここでは最もプレーンな形でのデータであるCSV形式からの読み込み例を示す。
サンプルデータBaseball.csvを読み込むことを考える。なおこのデータはUTF-8形式で保存されている2。これを読み込むには,Rがデフォルトで持っている関数read.csvが使える。
dat <- read.csv("Baseball.csv")
head(dat) Year Name team salary bloodType height weight UniformNum position
1 2011年度 永川 勝浩 Carp 12000 O型 188 97 20 投手
2 2011年度 前田 健太 Carp 12000 A型 182 73 18 投手
3 2011年度 栗原 健太 Carp 12000 O型 183 95 5 内野手
4 2011年度 東出 輝裕 Carp 10000 A型 171 73 2 内野手
5 2011年度 シュルツ Carp 9000 不明 201 100 70 投手
6 2011年度 大竹 寛 Carp 8000 B型 183 90 17 投手
Games AtBats Hit HR Win Lose Save Hold
1 19 NA NA NA 1 2 0 0
2 31 NA NA NA 10 12 0 0
3 144 536 157 17 NA NA NA NA
4 137 543 151 0 NA NA NA NA
5 19 NA NA NA 0 0 0 9
6 6 NA NA NA 1 1 0 0
str(dat)'data.frame': 7944 obs. of 17 variables:
$ Year : chr "2011年度" "2011年度" "2011年度" "2011年度" ...
$ Name : chr "永川 勝浩" "前田 健太" "栗原 健太" "東出 輝裕" ...
$ team : chr "Carp" "Carp" "Carp" "Carp" ...
$ salary : int 12000 12000 12000 10000 9000 8000 8000 7500 7000 6600 ...
$ bloodType : chr "O型" "A型" "O型" "A型" ...
$ height : int 188 182 183 171 201 183 177 173 176 188 ...
$ weight : int 97 73 95 73 100 90 82 73 80 97 ...
$ UniformNum: int 20 18 5 2 70 17 31 6 1 43 ...
$ position : chr "投手" "投手" "内野手" "内野手" ...
$ Games : int 19 31 144 137 19 6 110 52 52 40 ...
$ AtBats : int NA NA 536 543 NA NA 299 192 44 149 ...
$ Hit : int NA NA 157 151 NA NA 60 41 11 35 ...
$ HR : int NA NA 17 0 NA NA 4 2 0 1 ...
$ Win : int 1 10 NA NA 0 1 NA NA NA NA ...
$ Lose : int 2 12 NA NA 0 1 NA NA NA NA ...
$ Save : int 0 0 NA NA 0 0 NA NA NA NA ...
$ Hold : int 0 0 NA NA 9 0 NA NA NA NA ...
ここでhead関数はデータフレームなどオブジェクトの冒頭部分(デフォルトでは6行分)を表示させるものである。また,str関数の結果から明らかなように,読み込んだファイルが自動的にデータフレーム型になっている。
ちなみに,サンプルデータにおいて欠測値に該当する箇所にはNAの文字が入っていた。read.csv関数では,欠測値はデフォルトで文字列”NA”としている。しかし,実際は別の文字(ex.ピリオド)や,特定の値(ex.9999)の場合もあるだろう。その際は,オプションna.stringsで「欠測値として扱う値」を指示すれば良い。
さて,ここまでスクリプトを書いてきたことで,そこそこ長いスクリプトファイルができたことと思う。 スクリプトの記述については,もちろん「動けばいい」という考え方もあるが,美しくかけていたほうがなお良いだろう。「美しい」をどのように定義するかは異論あるだろうが,一般に「コード規約」と呼ばれる清書方法がある。ここでは細部まで言及しないが,RStudioのCodeメニューからReformat Codeを実行してみよう。スクリプトファイルが綺麗に整ったように見えないだろうか?
美しいコードはデバッグにも役立つ。時折Reformatすることを心がけよう。
Rを起動し,新しいスクリプトファイルを作成してください。そのファイル内で,2つの整数を宣言し,足し算を行い,結果をコンソールに表示してください。
スクリプトに次の計算を書き,実行してください。
Rのスクリプトファイル内で,ベクトルを作成してください。ベクトルには1から10までの整数を格納してください。その後,ベクトルの要素の合計と平均を計算してください。ベクトルを合計する関数はsum,平均はmeanです。
次の表をリスト型オブジェクトTblにしてください。
| Name | Pop | Area | Density |
|---|---|---|---|
| Tokyo | 1,403 | 2,194 | 6,397 |
| Beijing | 2,170 | 16,410 | 1,323 |
| Seoul | 949 | 605 | 15,688 |
先ほど作ったTblオブジェクトの,東京(Tokyo)の面積(Area)の値を表示させてください(リスト要素へのアクセス)
Tblオブジェクトの人口(Pop)変数の平均を計算してください。
Tblオブジェクトをデータフレーム型オブジェクトdf2に変換してください。新たに作り直しても良いですし,as.data.frame関数を使っても良い。
Rのスクリプトを使用して,別のサンプルデータBaseball2022.csv ファイルを読み込み,データフレームdatに格納してください。ただし,このファイルの欠測値は\(999\)という数値になっています。
読み込んだdatの冒頭の10行を表示してみてください。
読み込んだdatにsummary関数を適用してください。
このデータセットの変数teamは名義尺度水準です。Factor型にしてください。他にもFactor型にすべき変数が2つありますので,それらも同様に型を変換してください。
このデータセットの変数の中で,数値データに対して平均,分散,標準偏差,最大値,最小値,中央値を それぞれ算出してください。
課題を記述したスクリプトファイルに対して,Reformatなどで整形してください。
実数はreal numberじゃないのか,という指摘もあろうかとおもう。ここでは電子計算機上の数値の分類である,倍精度浮動小数点数(double-precision floating-point number)の意味である。倍精度とは単精度の倍を意味しており,単精度は32ビットを,倍精度は64ビットを単位として一つの数字を表す仕組みのことである。↩︎
UTF-8というのは文字コードの一種で,0と1からなる機械のデータを人間語に翻訳するためのコードであり,世界的にもっとも一般的な文字コードである。しかしWindowsOSはいまだにデフォルトでShift-JISというローカルな文字コードにしているため,このファイルを一度Windows機のExcelなどで開くと文字化けし,以下の手続が正常に作用しなくなることがよくある。本講義で使う場合は,ダウンロード後にExcelなどで開くことなく,直接Rから読み込むようにされたし。↩︎