Lesson 1-1: R を使ってみよう!

2018/09/28

第1回(その1)は R, RStudio の基本的な使い方を説明します。

R とR を取り巻く環境

R の成り立ちから話を始めることが多いのですが・・・・細かいことは気にせず 「R は統計処理と可視化が得意なフリーソフトウェア 」とだけ考えておいてください。

次のことを押さえましょう。

コミュニティに助けを求める

R Club に参加している方は,困ったことがあれば直接主催者に聞いてもらうか Slackで質問してください。できる限りお手伝いします。ただ残念ながら,あまりに高度な内容となると手に負えないということがあるかもしれません。

しかし,ご安心ください。R には大きなユーザーコミュニティがあるので,英語で質問を書けばたいていすぐに回答が得られます。質問のタイプごとに質問すべき相手が変わってきますので,自分が直面している問題の本質を見極めた上で質問を書きましょう。質問の書き方についての相談も歓迎します。

効率的に回答を得るために reprex を使ってみてください。

注意!

  • 投稿前にポスティングガイドを確認すること。
  • 複数のメーリングリスト・質問サイトに同じ質問を投稿することは「クロスポスティング」といってすごく嫌われてしまいます。回答がすぐに得られなくても気長に待つか,質問の内容を見直しましょう。

RStudio

RStudio はRを便利に使うためのソフトウェアです。Rと同様,RStudio も無料で使うことができます。R Club では RStudio 上で Rのプログラムを実行します。

RStudio を開いてみよう

デスクトップのショートカットやプログラムメニューから RStudio を探して起動してみてください。次のような画面が表示されましたでしょうか。

Fig: RStudio 起動後の画面(Macの場合)

Fig: RStudio 起動後の画面(Macの場合)

RStudio の構成部品を見てみよう

はじめて起動したときには以下のタブ(と他のいくつかのタブ)が開いていると思います。それぞれのタブをクリックしてみて,どのような機能があるか予想してみてください。

  • Console / コンソール
  • Environment / 環境
  • History / 履歴
  • Files / ファイル
  • Plots / プロット
  • Help / ヘルプ
  • Viewer / ビューワー

R を電卓として使う

コンピュータを「計算機」とも言うように,コンピュータの重要な仕事は「計算」です。「計算」が意味していることを一言で表すのは難しいのですが,ひとまず以下の一連の流れを覚えておいてください。

  1. 人間はコンピュータに「命令」する
  2. コンピュータは「命令」にしたがって計算する
  3. コンピュータは人間に計算結果を示す(ただし,そう命令された場合)

「計算結果を示す」という所まで「命令」しないといけないというのは面倒に思えるかもしれません。多くの場合は,実行環境であるRが面倒を見てくれます。ときどき,そうでない場合があって,「なんで表示されないの??」と困惑してしまう状況に出くわすかもしれません。そのときは「表示する命令を出さないといけない」ことを思い出しましょう。

さて,ここまで説明したところで早速 R を電卓(関数電卓)として使ってみましょう。

「コンソール(Console)」でキーボードのカーソルがカチカチ点滅していることを確認してください。点滅していなければコンソールをクリックしてください。(ショットカットキー「Ctrl + 2」でも移動できます。)

次のように打ち込んで,最後にエンターキー(リターンキー)を押してください。

> 90 + 30
## [1] 120

簡単ですね。色々な計算をやってみましょう。

コード例の読み方

上のコード例では,2段上下にコードが並んでいる格好になっています。この場合,

  • 上の段が実行してほしいコード
  • 下の段がその結果

となっています。実行してほしいコードに,> という記号がついている場合は,「コンソールで打ち込んでください」という意味です。 実はこれがあるとコピー&ペーストがやりにくいのですが,自分の手で打ち込む(写経する)ことで,筋肉が覚えてくれる側面もあるので,面倒ですがお付き合いください。

下段のハッシュ(#)は,コンソールには表示されませんが,テキスト上で「出力であることをわかりやすくするため」のお約束と思っておいてください。続く [1] は,その「右側にある数字が結果の1番目の数字だ」ということを表しています。後でベクトルの話がでてきたときに,役に立つことが分かると思います。

Fig: コードサンプルの読み方

Fig: コードサンプルの読み方

練習問題1

以下のコードはそれぞれどのような結果を返すか。結果を予想し,コンソールで実行して確認してください。

Code 1-1

> 120 + 30

## [1] 150

+ は足し算の記号です。

Code 1-2

> 1093 - 805

## [1] 288

- は引き算の記号です。負の数を作るときにも同じ記号を使います。

>  - 100
## [1] -100

Code 1-3

>  3 * 0.12

## [1] 0.36

* は掛け算の記号です。

- と違って,掛け算は2つの数字の間にないとエラーになります。

* 10     #=> Error: unexpected '*' in '*'

Code 1-4

> 50 / 60

## [1] 0.8333333

/ は割り算の記号です。ゼロで割ると無限大 Inf になります。

> 3 / 0
## [1] Inf

コンソールに + の記号が出てきた!

コマンドを途中まで打ちこんでエンターキーを押してしまうということがよくあります。 例えば,10 * 3 と計算しようとして,10 * でエンターを押してしまう,といったことです。

そんなとき,次のように「+」が表示されます。

> 10 * 
+

これは コマンドが完結していない ということを表す記号です。続けてコマンドを実行すれば問題ありません。

> 10 * 
+ 3
## [1] 30

もし,途中で書くのをやめたくなったら Esc キーを押すと中断できます。

それでは,少しひねった問題を出してみましょう。

Code 1-5

> 2 + 3 * 2 

## [1] 8

計算が実行される順序が決まっています。「+ より先に * を計算する」というのは数学の慣習と一致していますね。+ を先に計算したい場合には,カッコを使って次のようにします。

> (2 + 3) * 2
## [1] 10

*, /+, - より優先されます。 項を括る意味でのカッコは () だけを使います。

次のケースはどうでしょうか。^ はべき乗を計算する記号です。

Code 1-5

> 2 + 3 ^ 2 * 2

## [1] 20

これは \(2 + ((3^2) \times 2)\)

関数を使う

対数関数と指数関数

指数関数 \(a ^ x\), \(a > 0\) と対数関数 \(\log_a x\) の関係については覚えていますか?

\[a^{\log_a x} = x\]

\[\log_a (a^x) = x\] \[a^{x + y} = a^x a^y\] \[\log_a x^\alpha y^\beta = \alpha \log_a x + \beta \log_a y\]

などなど,いろいろな公式を覚えている(昔覚えたけど忘れている)ものと思います。

\(a\) のことを「底」(てい)と呼びますが,無数にある底の中でも特に重要なのが「自然対数の底」(Napier数)と呼ばれるもので \(e\) と表します。正規分布の密度関数にも

\[ \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x - m)^2}{2\sigma}} \]

のように現れます。\(e\) の肩がいかにも重たそうなので,\(\exp\) を使って

\[ \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left(-\frac{(x - m)^2}{2\sigma}\right) \]

と書くこともよくあります。R では,後者の表現がコマンド名になっています。

> exp(10)
## [1] 22026.47

自然対数 \(\log_e\) または単に \(\log\) あるいは \(\ln\)(自然対数の底を底に持つ対数関数・・・)は

> log(10)
## [1] 2.302585

\(\log(10 \times 5) = \log(10) + \log(5)\) であることを確かめるには

> log(10 * 5) - (log(10) + log(5))
## [1] -4.440892e-16

ちなみに,\(e\) の他にも 2 と 10 は底としてよく使いますので,R には log2, log10 が用意されています。

-4.440892e-16 ってどういう意味?

結論から言うと,これは

\[ -4.440892... \times 10^{-16} \] という意味です。すごく小さい数字ですがゼロではありません

理屈上は整数できれいな答えになるはずの計算であっても,計算の途中に「小数点」を含む計算がでてくるようなケースでは,コンピュータを使ってピッタリ正確に整数の答えがでるという状況はきわめて稀です。

ひょっとすると log() みたいに難しい関数を計算しなきゃならないから近似してるんでしょ?と思うかもしれませんね。半分正解で,半分間違っています。簡単そうに見える計算でも近似が入ってしまうのです。試しに次の計算をしてみてください。

> 0.1 + 0.1 + 0.1 - 0.3

私たちはこの答えが正確にゼロであることを一瞬で見極めることができます。しかし,私たちが普段使っているようなコンピュータはゼロという答えを出せません。これは,数の表現に関連しています。

私たちは小数を10進数の延長として表現・理解するので \(0.1\) は有限小数であるように見えますが,巷のコンピュータは2進数の小数表現を使うので \(0.1\) が有限小数にならないのです。当然,コンピュータは無限に長いデータを保持できないので,どこかで打ち切って近似をすることになります。近似によって生まれた誤差が結果の誤差につながったのです。

小難しい話は忘れてもかまいませんが 小数を含む計算結果を等号で比較してはいけない ということだけは肝に命じておきましょう。 いずれ使うべきときが来ると思いますが,それまでに all.equal() のヘルプを見ておいてください。

> ?all.equal
> all.equal(log(10 * 5) , (log(10) + log(5)))
> all.equal(0.1 + 0.1 + 0.1, 0.3)

形を見てみよう

R で 1変数の関数をプロットするのはとても簡単です。次のようにやります。

> plot(log)

> plot(exp)

じゃあ,いろんな関数のグラフをプロットしてみたいと思いますよね?自然な発想です。やってみましょう。 \[2e^x\] をプロットしてみてください。(ハッシュ # の右側は「コメント」です。打ち込まなくてもOK)

> plot(2 * exp)     # うまく動くかな?

解説

## Error in 2 * exp: non-numeric argument to binary operator

Error と出てしまいましたね。これはうまく行きません。「関数」を予め定義して,plot() の中に書き込まないといけないのです。

練習問題2

それぞれのコードがどのような結果を出すか予想してください。その後,実行して結果を確認してみましょう。

Code 2-1

> exp(log(10)) 

## [1] 10

\(e^{\log x} = x\) でしたね。

Code 2-2

> log(exp(10)) 

## [1] 10

\(\log(e^x) = x\) です。

Code 2-3

> sqrt(9) 

## [1] 3

sqrt(x)x の平方根(square root)を計算します:\(\sqrt{x}\)\(\sqrt{x} = x^{1/2}\) なので,次のようにしても同じ結果になります。

9 ^ (1/2)
## [1] 3

補遺:数学の関数とプログラムの「関数」

対数関数のコマンド log(x) や指数関数のコマンド exp(x) は数学における「関数」という概念にぴったり当てはまります。\(x\) に数字をあてはめると,\(\log x\) の値が定まる,というわけです。

プログラミングの視点でももちろんこれらは「関数」ですが,プログラムの世界で関数という用語はもう少し広い概念です。 例えば,グラフをプロットするときに使った plot(FUN) は「FUN に関数をあてはめるとグラフが出力される」という「関数」です。

これから,みなさんはたくさんの「関数」を作ることになります。それは数学的な関数に近い場合もあれば「複雑な仕事に名前をつける」という性質のものになるかもしれません。

エラーは怖くない!

プログラミング初学者にとってはエラーメッセージというのは少し怖いものかもしれません。エラーメッセージの出現とともに計算が止まってしまうので,「自分が何か悪いことをしたに違いない」と感じてしまうかもしれません。反射的にウインドウを消してしまいそうになったら,ここに書かれていることを思い出して,ぐっと堪えてください。

エラーは人間から人間へのメッセージです。きちんと読めば原因が分かるようになっているはずです。あなたがプログラムを書くときにも,他の人が原因究明する助けになるようなエラーを組み込まなければなりません。

試しに,コンソールで次のコマンドを実行してください。

> stop("エラーですよ")

実行結果

Error: エラーですよ

ここで発生するエラーはあなたが作ったものですから,まったく怖くないでしょう?他の人が作ったエラーも怖くないのです。要するに,「これ以上先に進んでもうまくいかない」ということが確実な場合にエラーを仕込んでおくのです。そうしておくと,うまくいかないコードを延々と走らせる無駄を省くことができるからです。有り難いことです。

さて,次のコードを実行して,どのようなエラーが出るかを見てみましょう。エラーメッセージに重要な情報が書かれていることを確かめてください。

例 1

> library("nosuchpackage")

解説

Error in library("nosuchpackage") : 
  there is no package called ‘nosuchpackage’

library() はR の拡張機能(=パッケージ)を読み込むための関数です。 “nosuchpackage” などというパッケージは存在しない,というエラーが出て止まります。入力間違いか,パッケージがインストールされていないことが予想されます。

例 2

> 5 = 10

解説

Error in 5 = 10 : invalid (do_set) left-hand side to assignment

= は後に説明する「変数への代入(右から左)」です。左辺が「数字」では機能しません。両辺が同じであるかをチェックするには,等号を2つ並べた == を使います。

5 == 10
## [1] FALSE

もちろん答えは「FALSE」(= 偽) ですね。これはエラーではありません。

例 3

> exp("10")

解説

Error in exp("10") : non-numeric argument to mathematical function

関数 exp() の括弧の中身は数字でなければなりません。引用符をつけた "10" は数字ではなく文字列("1""0" が並んだもの)で,引用符なしの 10 が数字です。この区別は重要です。

exp(10)
## [1] 22026.47

まとめ

今日学んだ数式と R コマンドの対応関係をまとめておきましょう。

数式 R
\(a + b\) a + b
\(a - b\) a - b
\(a \times b\) a * b
\(a \div b\) a / b
\(x^a\) x ^ a
\(e^x\) exp(x)
\(\log x\) or \(\ln x\) log(x)
\(\log_{10} x\) log10(x)
\(\sqrt x\) sqrt(x)

これらのコマンドと括弧を組み合わせれば,それなりに複雑な計算をこなすこともできるでしょう。 しかし先を急がず, R/RStudio の機能をもう少し習得することにしましょう。何事もスマートにこなす方がいいですからね。

コマンドを実行してエラーが出たときには,怖がらずにきちんとエラーメッセージを読むようにしてください。それはプログラマからあなたへのメッセージなのです。おいおい分かってくるとは思いますが,エラーは出ないけど計算結果が間違っているという方がよっぽど怖いことです・・・・・。

次のステップ