この Notebook は,
テキスト「オープンソースソフトウェアによる情報リテラシー −第2版−」の
のプログラミング部分に相当する内容を R を使って書いてみたものです。
R は統計解析向けのプログラミング言語です。この Notebook では,プログラミング言語としての共通部分に焦点を絞って解説します。R 本来の得意分野である統計解析の分野は省いていますので,R そのものの入門というよりは,Jupyter Notebook での R の使用例として見ていただければと思います。
RStudio や R commander (Rcmdr) を駆使している方がほとんどかと思いますが,Jupyter Notebook でもできることをご確認いただければと思います。
では,はじめましょう。
エンゲル係数とは,家計の消費支出に占める飲食費(食料費,食費)の割合(パーセント単位)です。
消費支出 100,000円,飲食費 40,000円の人のエンゲル係数を求める例。R では以下のような電卓的な使い方ですぐ答えが出ます。
本稿のように Jupyter Notebook 環境では,以下の1行を書いたあとに,Shift キーを押しながら Enter キー(または Return キー)を押して実行します。
40000 * 100/100000
ここからは,単に電卓的に使うだけではなく,応用・発展も見据えて以下のようなプログラム文を作成して実行することにします。
以下の例では,
s1
に消費支出である 100000
(円)という数値を代入し,s2
に飲食費である 40000
(円)という数値を代入し,x1
に代入し,print()
関数で表示させています。R では代入演算子は <-
(または =
)を使うようです。
s1 <- 100000
s2 <- 40000
x1 <- s2*100/s1
print(x1)
意に反して,プログラムがうまく動作しない場合があります。たとえば,上記の 3行目を以下のように書いた場合。
掛け算を示す演算子は *
,割り算を示す演算子は /
であるところを誤って,×
や ÷
と書くと,これらの記号は R では演算子として定義されていないのでエラーとなります。このようなエラーは文法エラー と呼ばれ,Jupyter Notebook では,以下のように誤りやその箇所を指摘してくれます。
s1 <- 100000
s2 <- 40000
x1 <- s2 × 100 ÷ s1
print(x1)
別の種類の誤りもあります。たとえば,「100」を「1000」と入力した場合...
s1 <- 100000
s2 <- 40000
x1 <- s2*1000/s1
print(x1)
上記の例では Error
(文法エラー)の警告が出ませんが,答えは明らかに変です。(エンゲル係数の最大値は100だから。)
このような場合はコンピュータにとって誤りではなく,指示通りに計算し,その結果を表示します。 このようなプログラム作成者の不注意や勘違いによって生じるエラーには注意が必要です。
プログラムが正しく動作しない場合は,誤りの箇所を探し,修正して再度動作を確認します。正しく動作するようになるまで,プログラムを修正し,実行(Shift + Enter)します。この作業をデバグといいます。
上記の例の 1行目では,s1
という名前の変数に 100000
という
数値を代入しています。変数名はアルファベットで始まる英数字列にします。大文字と小文字は区別されます。
変数 ss
に文字列を代入する場合は,以下のように "
で囲みます。
ss <- "エンゲル係数"
print(ss)
掛け算を示す演算子は *
,割り算を示す演算子は /
。足し算は +
,引き算は -
です。
文字列の連結には +
ではなく,paste()
関数または cat()
関数を使います。以下の例を参照。
x0 <- "エンゲル"
y0 <- "係数"
paste(x0, y0, sep="")
cat(x0, y0, sep="")
+
の再定義で文字連結¶どうしても +
で文字列連結をしたい!という場合には,既存の +
演算子を以下のように再定義するという方法もあるようです。
"+" <- function(e1, e2) {
if (is.character(c(e1, e2))) {
paste(e1, e2, sep = "")
} else {
base::"+"(e1, e2)
}
}
x0 + y0
x0 + 2021
ですが,思わぬ副作用もありそうなので,元に戻しておきましょう。
rm("+")
文字列と数値を連結するときも,paste()
関数を使います。
s1 <- 100000
s2 <- 40000
x1 <- s2*100.0/s1
z1 <- paste("エンゲル係数は", x1, "です。")
cat(z1)
2 + (50 - 5 * 6)/4
除算 /
は常に浮動小数点数を返します。
冪乗は ^
です。(**
も可。)
17 / 3
2^4
2**4
上記の例では,プログラムの中で消費支出や飲食費を決めていましたが,今度はプログラムを実行する人が入力できるようにしてみます。
readline()
関数は入力された「文字列」を返すので,数値として計算するために as.numeric()
で数値(浮動小数点数)に変換します。
s1 <- readline("消費支出? ")
s2 <- readline("飲食費? ")
x1 <- as.numeric(s2)*100/as.numeric(s1)
cat("エンゲル係数は", x1, "です。")
(これまでの例では1回しか計算していませんが)よく使う計算を「関数」として定義する例です。
以下の例では,1行目から4行目でエンゲル係数を計算する関数 calc()
を定義し,8行目でその関数を呼び出しています。
#
から始まる行はコメント(実行に影響しない注釈)です。
calc <- function(s1, s2){
# 消費支出 s1 円と飲食費 s2 円からエンゲル係数を計算する。
return(as.numeric(s2)*100/as.numeric(s1))
}
s1 <- readline("消費支出? ")
s2 <- readline("飲食費? ")
x1 <- calc(s1, s2)
paste("エンゲル係数は", x1)
いったん定義された関数は,以下のように何回でも利用できます。
calc(120000, 54000)
消費支出を入力すると,エンゲル係数が 20 ~ 40 となる飲食費を表示するプログラムをつくりなさい。
関数は上記の例のように自分で定義することもできますが,あらかじめ用意されている「組み込み関数」を使うこともできます。
以下では,組み込み関数の例として,
floor()
trunc()
を使用しています。細かい話ですが floor()
と trunc()
では負の実数について取り扱いが異なることがわかります。
ceiling()
です。floor(12.3)
trunc(12.3)
floor(-12.3)
trunc(-12.3)
エンゲル係数を計算する部分はすでに関数 calc()
として定義していますが,プログラム全体を関数 engel()
として定義してしまいます。
engel <- function(){
s1 <- readline("消費支出? ")
s2 <- readline("飲食費? ")
x1 <- calc(s1, s2)
cat("エンゲル係数は", floor(x1), "です。(小数点以下切り捨て)")
}
engel()
小数点以下を切り上げたエンゲル係数の値を表示させるように上記のプログラムを変更しなさい。
R の組み込み関数に round()
があります。数値を丸める関数ですが,いわゆる四捨五入とはちょっと違うようです。
以下の例からわかるように,小数点以下が 0.5
未満の場合と 0.5
を超える場合は四捨五入と同様の丸め方ですが,ちょうど 0.5
のときは,偶数に丸められていることがわかります。
これを偶数への丸めといい,端数が 0.5
より小さいなら切り捨て,端数が0.5
より大きいなら切り上げ,端数がちょうど 0.5
なら切り捨てと切り上げのうち結果が偶数となる方へ丸めます。
cat(round(12.49), round(12.50), round(12.51), sep=", ")
cat(round(13.49), round(13.50), round(13.51), sep=", ")
四捨五入した値を表示する関数をつくりなさい。
engel <- function(){
s1 <- readline("消費支出? ")
s2 <- readline("飲食費? ")
x1 <- calc(s1, s2)
if (x1 >= 80) {
cat("エンゲル係数は", round(x1), "です。飲食費を使いすぎです。")
} else {
cat("エンゲル係数は", round(x1), "です。")
}
}
engel()
engel()
条件分岐の if
文の書式は以下のようになっています。
if (条件式 1) {
条件式 1 が満たされた場合に実行する文
} else if (条件式 2) {
条件式 2 が満たされた場合に実行する文
} else {
それ以外の場合に実行する文
}
上記の条件分岐を,エンゲル係数が
と表示させるように変更しなさい。
s1 <- 100000
s2 <- 40000
cat("消費支出", as.integer(s1), "円に対するエンゲル係数の値 \n")
while (s2 <= 80000) {
x1 = calc(s1, s2)
cat(" 飲食費", s2, "円の場合: ", x1, "\n")
s2 <- s2 + 5000
}
while
文の書式は以下のとおりです。
while (条件式){
条件式が成り立つ場合に実行される文
}
for
文¶同様の繰り返し処理を for
文を使って行うこともできます。
for
文の書式は以下のとおりです。
for (i in istart:iend) {
i が istart から iend までの間,実行される文
}
istart
から iend
まで増分 istep
ごとにする場合は,seq()
関数を使って
for (i in seq(istart, iend, istep)) {
i が istart から iend までの間,実行される文
}
s1 <- 100000
cat("消費支出", as.integer(s1), "円に対するエンゲル係数の値 \n")
for (s2 in seq(40000, 80000, 5000)) {
x1 = calc(s1, s2)
cat(" 飲食費", s2, "円の場合: ", x1, "\n")
}
以下の値を求めるプログラムを作成せよ。
$$\sum_{n = 1}^{10} n^2$$上記の(練習)は,while
または for
を使った繰り返し処理の練習を想定しているが,R ではベクトルを使って以下のように解くことができる。
# ベクトルをつくる
a <- c(1:10)
a
# ベクトルの各成分を2乗して和をとる
sum(a^2)
身長 <- c(168.5, 172.8, 159.0)
体重 <- c(69.5, 75.0, 56.5)
X <- data.frame(身長, 体重)
X
X$性別 <- c("男", "男", "女")
X
X$BMI <- round(X$体重 / (X$身長 / 100) ^ 2)
X
x <- rnorm(1000000)
hist(x)