前回まででRMarkdownファイルの作り方を学習しているので,これ以降はRMarkdownファイルにR(もしくはpython)のコードを書いていくこと.

1 ベクトル

1.1 ベクトルの作成

Rではこれまでの例のように単独の数値や文字列を扱うケースは極めて稀である.通常は複数の数値や文字列を1セットにして様々な処理を行っていく.そうした1セットにしたデータセットの最もシンプルなものがベクトル(1次元配列)である.

例えば,バスケットボールチームのStartingメンバー5名でフリースロー10本勝負をしたときの成績として以下のような成績が出たとする.

名前 点数
赤木 7
桜木 4
三井 10
宮城 7
流川 9

この表には名前のデータセットと得点のデータセットがある.これらがそれぞれベクトルとなる.Rでそれぞれのベクトルを作成するにはc()という関数を使う.cはconcatenate(連結する)の頭文字である.

Starting <- c("赤木","桜木","三井","宮城","流川")
Score<- c(7,  4, 10, 7, 9)
print(Starting) #print()関数を使わず,Startingだけでもよい.
## [1] "赤木" "桜木" "三井" "宮城" "流川"
print(Score)
## [1]  7  4 10  7  9

1.1.1 ベクトルの結合

c()関数を使うと,複数のベクトルを1つのベクトルにまとめることもできる.以下では新たにReserveのメンバーを追加して,フルメンバーのベクトルを作成している.

Reserve <-c("小暮","潮崎","安田","石井","佐々岡","桑田")
Full <- c(Starting, Reserve)
print(Full)
##  [1] "赤木"   "桜木"   "三井"   "宮城"   "流川"   "小暮"   "潮崎"   "安田"  
##  [9] "石井"   "佐々岡" "桑田"

データ上あまり意味はないが,文字列型のデータが収められたベクトルと数値型のデータが収められたベクトルをc()で連結することもできる.この場合,数値型のデータが文字列型に自動的に型変換される.

hoge <- c(Score, Starting)
print(hoge) #Scoreのデータが文字列型として出力される.
##  [1] "7"    "4"    "10"   "7"    "9"    "赤木" "桜木" "三井" "宮城" "流川"

1.1.2 名前付きベクトル

先ほど作成したScoreは単に数値だけが並ぶベクトルであるが,以下のように各数値に「名前」を付けることができる.このようなベクトルを名前付きベクトルと呼ぶ. なお,通常の文字列の扱いでは""で括らなければならないが,名前に対しては""で括らずにそのまま書いてもよいし,""で括ってもよい.

NamedScore <-  c(赤木=7,  桜木=4, 三井=10, 宮城=7, 流川=9)
print(NamedScore)
## 赤木 桜木 三井 宮城 流川 
##    7    4   10    7    9
NamedScore <-  c("赤木"=7,  "桜木"=4, "三井"=10, "宮城"=7, "流川"=9)
print(NamedScore)
## 赤木 桜木 三井 宮城 流川 
##    7    4   10    7    9

名前を付けておくとベクトル内の個々のデータにアクセスする際に,インデックス番号だけでなく,名前でアクセスすることもできる.詳しくは個々のデータへのアクセスへ.

1.2 ベクトルの型

ベクトルオブジェクトの型はそのベクトルが内部に持つデータの型によって決まる.冒頭で作成したStartingScoreの型を調べると以下の通りとなる.

class(Starting)
## [1] "character"
class(Score)
## [1] "numeric"

1.3 個々のデータへのアクセス

ベクトルオブジェクトの内の個別のデータにアクセスする(取り出す)には[]を使って取り出したいデータのインデックス番号を指定する.

Full[1]
## [1] "赤木"
Score[3]
## [1] 10

複数のデータを同時に取り出すには[]の中へ,c()を使って複数の番号を指定する.

Starting[c(3,5)]
## [1] "三井" "流川"
Score[c(3,5)]
## [1] 10  9

1.3.1 シーケンス演算子

例えば2番目から5番目のデータを取り出したいという場合には,いちいちc(2,3,4,5)と打つのは面倒である. そういう場合にはシーケンス演算子:を用いて以下のように書くことができる.

Starting[c(2,3,4,5)] #めんどくさい
## [1] "桜木" "三井" "宮城" "流川"
Starting[c(2:5)]
## [1] "桜木" "三井" "宮城" "流川"

通常の指定とシーケンス演算子での指定は併せて用いることもできる.

Starting[c(1,3,4,5)] #めんどくさい
## [1] "赤木" "三井" "宮城" "流川"
Starting[c(1,3:5)]
## [1] "赤木" "三井" "宮城" "流川"

1.3.2 名前を使ったアクセス

名前付きベクトルの場合には,インデックス番号の代わりに名前を指定してもよい.

NamedScore[5]
## 流川 
##    9
NamedScore["流川"]
## 流川 
##    9
NamedScore[c(1,3,4)]
## 赤木 三井 宮城 
##    7   10    7
NamedScore[c("赤木","三井","宮城")]
## 赤木 三井 宮城 
##    7   10    7

名前付きベクトルの場合には上記の通りに名前とベクトル値がセットになって返されてくる. あくまで数値だけが欲しいという場合には,unname()関数を用いる.あるいは,要素が1つだけの場合には[[]]というように角カッコを重ねることでもよい.ただし,[[]]が使えるのは要素が1つの時だけであり,複数の要素に対して用いるとエラーとなる.

unname(NamedScore[5])
## [1] 9
unname(NamedScore[c(1,3,4)])
## [1]  7 10  7
unname(NamedScore[c("赤木","三井","宮城")])
## [1]  7 10  7
NamedScore[["流川"]]
## [1] 9
NamedScore[[c(1,3,4)]] #これはエラー
## Error in NamedScore[[c(1, 3, 4)]]: attempt to select more than one element in vectorIndex
NamedScore[[c("赤木","三井","宮城")]] #これもエラー
## Error in NamedScore[[c("赤木", "三井", "宮城")]]: attempt to select more than one element in vectorIndex

1.4 個々のデータの書き換え

ベクトル内のデータへのアクセスと同じ要領で書き換えたいデータを指定し,代入演算子を使って値を与えればよい

Starting[1] <- "Akagi"
Starting
## [1] "Akagi" "桜木"  "三井"  "宮城"  "流川"

同時に複数のものを書き換えることもできる.

Starting[c(1,2)] <- c("Akagi", "Sakuragi")
Starting
## [1] "Akagi"    "Sakuragi" "三井"     "宮城"     "流川"

1.5 ベクトルと数値の演算

ベクトルに対して数値を使って演算をすると,ベクトル内のすべてのデータに対してその数値の演算が行われる.

Score + 10
## [1] 17 14 20 17 19
Score - 3
## [1] 4 1 7 4 6
Score * 2
## [1] 14  8 20 14 18
Score / 4
## [1] 1.75 1.00 2.50 1.75 2.25
Score ^ 2
## [1]  49  16 100  49  81

また名前付きベクトルの場合には,名前そのものは演算には影響せず,データだけに演算がされる.演算結果は名前付きベクトルが返ってくる.

NamedScore + 10
## 赤木 桜木 三井 宮城 流川 
##   17   14   20   17   19
NamedScore - 3
## 赤木 桜木 三井 宮城 流川 
##    4    1    7    4    6
NamedScore * 2
## 赤木 桜木 三井 宮城 流川 
##   14    8   20   14   18
NamedScore / 4
## 赤木 桜木 三井 宮城 流川 
## 1.75 1.00 2.50 1.75 2.25
NamedScore ^ 2
## 赤木 桜木 三井 宮城 流川 
##   49   16  100   49   81

1.6 ベクトル同士の演算

同じ長さのベクトルであればベクトル同士の掛け算ができる.

hoge <- c(3,5,0,2,1)
Score + hoge
## [1] 10  9 10  9 10
Score * hoge
## [1] 21 20  0 14  9
Score / hoge #3つ目の分母が0になるので,Infinity,つまり無限大を表すInfが表示される
## [1] 2.333333 0.800000      Inf 3.500000 9.000000

名前付きベクトルの場合も同様.

NamedScore + hoge
## 赤木 桜木 三井 宮城 流川 
##   10    9   10    9   10
NamedScore * hoge
## 赤木 桜木 三井 宮城 流川 
##   21   20    0   14    9
NamedScore / hoge 
##     赤木     桜木     三井     宮城     流川 
## 2.333333 0.800000      Inf 3.500000 9.000000

さらに名前付きベクトル同士を演算させた場合.

namedhoge<- c(A=3,B=5,C=0,D=2,E=1)
NamedScore + namedhoge
## 赤木 桜木 三井 宮城 流川 
##   10    9   10    9   10
namedhoge + NamedScore
##  A  B  C  D  E 
## 10  9 10  9 10
hoge + NamedScore + namedhoge
## 赤木 桜木 三井 宮城 流川 
##   13   14   10   11   11

このように名前付きベクトル同士を演算させた場合には,式の中で最初に出てくる名前付きベクトルの名前だけが出力に反映される.

演算するベクトルの長さが異なっているとWarningが出力される.興味深いことに,Errorではなく,あくまでWarningであって計算結果は出力される.長さが短い方が長い方に合わせて循環していく.また,長い方のベクトルの長さが短い方のベクトルの長さの整数倍の時には,Warningも表示されない.

hoge2 <- c(3,5,0,2,1,4,3)
Score + hoge2 # 長さが合ってないのでWarningが出てくる
## Warning in Score + hoge2:
## 長いオブジェクトの長さが短いオブジェクトの長さの倍数になっていません
## [1] 10  9 10  9 10 11  7
hoge3 <- c(3,5,0,2,1,4,3,3,4,4) # hoge3の長さがScoreの2倍になっているのでWarningはでない
Score + hoge3 
##  [1] 10  9 10  9 10 11  7 13 11 13

1.7 ベクトルの検索

ベクトルの中に指定したデータが含まれているかどうかは==を用いることでしらべられる. 以下の例ではStartingベクトルの中に「流川」が含まれているかどうかを調べている.

Starting== "流川"
## [1] FALSE FALSE FALSE FALSE  TRUE

返り値として,ベクトルの各要素が検索値と一致しているかをFALSE,TRUEのいずれかで示したベクトルが返される. ちなみにこのようなFALSE, TRUEの2値を取る型を論理型と呼ぶ.

1.8 ベクトルへの要素の追加

ベクトルに要素を追加したい場合には,追加されるベクトルと追加したい要素やベクトルをc()で結び付けて,元のベクトルオブジェクトに格納すればよい.もちろん,元のベクトルではなく別のベクトルオブジェクトとして格納することもできる.

木暮を追加してみよう.

print(Starting)
## [1] "Akagi"    "Sakuragi" "三井"     "宮城"     "流川"
Starting <- c(Starting, "小暮")
print(Starting)
## [1] "Akagi"    "Sakuragi" "三井"     "宮城"     "流川"     "小暮"

さらに,リザーブメンバーも加えて,フルメンバのベクトルを作成する.

Reserve <- c("潮崎","安田","角田","石井","佐々岡","桑田")
Full <- c(Starting, Reserve)
print(Full)
##  [1] "Akagi"    "Sakuragi" "三井"     "宮城"     "流川"     "小暮"    
##  [7] "潮崎"     "安田"     "角田"     "石井"     "佐々岡"   "桑田"

実際には「追加」をしているのではなく,元のベクトルと新しいデータを結び付けた新しいベクトルを作成したうえで,元のオブジェクト(箱)に格納しているだけである. したがって,もし末尾ではなく,先頭に追加したり,途中に追加したければ,以下のようにすればよい.

Starting<-c("赤木", "桜木", "三井", "宮城", "流川") #一旦元に戻す
Starting<-c("木暮", Starting) #先頭に追加
print(Starting)
## [1] "木暮" "赤木" "桜木" "三井" "宮城" "流川"
Starting<-c("赤木", "桜木", "三井", "宮城", "流川") #一旦元に戻す
Starting<-c(Starting[1:3], "木暮", Starting[4:5]) #途中に追加
print(Starting)
## [1] "赤木" "桜木" "三井" "木暮" "宮城" "流川"

1.9 ベクトルからの要素の削除

ベクトルから特定の要素を削除したい場合には,残したい要素だけを取り出し,それをもとのベクトルオブジェクトに格納すればよい(もちろん別のオブジェクトとして格納してもよい).

末尾に追加した木暮を削除してみよう.6番目にある木暮を削除するには以下のようにする.

Starting<-c("赤木", "桜木", "三井", "宮城", "流川") #一旦元に戻す
Starting <- c(Starting, "小暮")#木暮を追加
print(Starting) # 小暮が入っている
## [1] "赤木" "桜木" "三井" "宮城" "流川" "小暮"
Starting <- Starting[c(1:5)]
print(Starting) # 小暮が除外された
## [1] "赤木" "桜木" "三井" "宮城" "流川"

あるいは,以下のように-をつけてインデックス番号を与えると,そのインデックスで指定されたデータが除外される.

print(Full)
##  [1] "Akagi"    "Sakuragi" "三井"     "宮城"     "流川"     "小暮"    
##  [7] "潮崎"     "安田"     "角田"     "石井"     "佐々岡"   "桑田"
Full<-Full[-3] #3番目の三井が除かれる
print(Full)
##  [1] "Akagi"    "Sakuragi" "宮城"     "流川"     "小暮"     "潮崎"    
##  [7] "安田"     "角田"     "石井"     "佐々岡"   "桑田"
Full<-Full[c(-4,-6)] # 4番目の流川と6番目の潮崎が除かれる
print(Full)
## [1] "Akagi"    "Sakuragi" "宮城"     "小暮"     "安田"     "角田"     "石井"    
## [8] "佐々岡"   "桑田"

ただし,除外と抽出を同時にはできない.

Full[c(1:5,-3)] #これはエラー.取り出しと除外を同時できない.
## Error in Full[c(1:5, -3)]: 負の添字と混在できるのは 0 という添字だけです

RMarkdownファイルを作成し,以下の課題についてRMarkdown上で実行させ,KnitによってHTML出力させよ.

  1. 以下の3つのベクトルab, Cを作成し,それぞれの内容をprint()を用いて出力させよ.
    • a : 1,2,3,4,5
    • b : 6,7,8,9,10
    • c : 11,12,13,14,15
  2. abを足し合わせてオブジェクトdとし,その内容をprint()を用いて出力させよ.
  3. dcを掛け合わせてオブジェクトeとし,その内容をprint()を用いて出力させよ.
  4. 以下の都道府県名を持つ地方名のベクトル関東近畿を作成し,それぞれの内容をprint()を用いて出力させよ.
    • 関東 : “東京”, “千葉”, “埼玉”, “神奈川”, “茨城”, “栃木”, “群馬”
    • 近畿 : “大阪”, “京都”, “兵庫”, “奈良”, “和歌山”, “滋賀”, “三重”
  5. 関東近畿を合わせて都市とし,その内容をprint()を用いて出力させよ.
  6. 都市から”東京”, “大阪”だけを除外し,その内容をprint()を用いて出力させよ.

2 データフレーム

ベクトルはあくまで1次元配列であるが,通常,データセットは以下のように行と列を持った2次元配列(要するに表)になっている.

名前 背番号 点数
赤木 4 7
桜木 10 4
三井 14 10
宮城 7 7
流川 11 9

このような表としてのデータを一まとめにして扱うのがデータフレームという型のオブジェクトである.

2.1 データフレームの作成

データフレームを作るには以下のようにdata.frame()関数を用いる.

Shohoku <- data.frame(
  name = c("赤木","桜木","三井","宮城","流川"),
  number=c(4,10,13,7,11),
  score= c(7,4,10,7,9)
)
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9

data.frame()関数の中でnamenumberscoreの3つのベクトルが作られている.つまりデータフレームとは同じ長さのベクトルが複数まとまったものと捉えることができる.

関数内での改行について 上の例では分かりやすさのためdata.frame()の中で改行(Enter)を入れているが,改行は入れても入れなくても良い.console上で()""''の中で改行を入れた場合,行頭が>から+にかわり,直近の("'の範囲(スコープと呼ぶ)が閉じられずに続いていることを示す.スコープ閉じられていない限りはどれだけEnterを押してもコマンドは実行されない.適切にこれらが閉じられた場合には,閉じられた行でEnterキーを押すとことで一連の入力が一つながりのコマンドとして実行される.

なお,データフレームにおいては,行のことをobs(observation:観測の略),列のことをvarialbles(変数の意味)と呼ぶ.これは行方向(縦方向)は観察・測定されたサンプルが並べられており,列方向(横方向)は測定項目・測定変数が並べられている,ということである.

2.2 列へのアクセス

データフレームの各列のベクトルにアクセスするには,$もしくは[]を使う.

Shohoku$name # ベクトルとして出力される
## [1] "赤木" "桜木" "三井" "宮城" "流川"
Shohoku["name"] # nameだけを含んだデータフレームとして出力される
##   name
## 1 赤木
## 2 桜木
## 3 三井
## 4 宮城
## 5 流川
Shohoku[1] #[]を使う場合には列の番号を与えても良い
##   name
## 1 赤木
## 2 桜木
## 3 三井
## 4 宮城
## 5 流川

両者の出力結果は一見似ているが,$の方は指定した列をベクトルとして出力されるのに対して,[]の方は指定した列だけを含んだデータフレームとして出力される. それぞれの違いを確認するには,出力の型を確認すればよい.

class(Shohoku$name) # ベクトルなので,文字列型となる
## [1] "character"
class(Shohoku["name"])#データフレームなのでdata.frame型となる
## [1] "data.frame"

複数の列を同時に取り出す場合にはc()関数を使って複数の列を指定してやる.

Shohoku[c("name","score")]
##   name score
## 1 赤木     7
## 2 桜木     4
## 3 三井    10
## 4 宮城     7
## 5 流川     9
Shohoku[c(1,3)] #名前ではなく列番号で指定した場合
##   name score
## 1 赤木     7
## 2 桜木     4
## 3 三井    10
## 4 宮城     7
## 5 流川     9

この場合の出力結果はdata.frame型となる.

2.3 列の書き換え

列にアクセスするのと同じ要領で$または[]で列を指定し,代入演算子によって書き換えたいベクトルを与えてやる.以下では$で指定する方法で名前をローマ字に書き換えた後,[]で指定する方法でローマ字になった名前を漢字に戻している.

Shohoku$name <- c("Akagi","Sakuragi","Mitsui","Miyagi","Rukawa")
Shohoku
##       name number score
## 1    Akagi      4     7
## 2 Sakuragi     10     4
## 3   Mitsui     13    10
## 4   Miyagi      7     7
## 5   Rukawa     11     9
Shohoku[1] <- c("赤木","桜木","三井","宮城","流川")
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9

注意しないといけない点として,あくまで元の列ベクトルに含まれるデータ数(要するに行数)と同じデータ数のベクトルを与えなければならない.異なるデータ数のベクトルを与えた場合,Errorが返される.

Shohoku$name <- c("Akagi","Sakuragi","Mitsui","Miyagi") #データが1つ足りない
## Error in `$<-.data.frame`(`*tmp*`, name, value = c("Akagi", "Sakuragi", : 置換は 4 列ですが、データは 5 列です
Shohoku[1] <- c("Akagi","Sakuragi","Mitsui","Miyagi") #データが1つ足りない
## Error in `[<-.data.frame`(`*tmp*`, 1, value = c("Akagi", "Sakuragi", "Mitsui", : 置換は 4 列ですが、データは 5 列です

与えるベクトルデータが数値の場合には,演算を伴ったものでもよい.

Shohoku$score <- Shohoku$score + 5 # 5を足した
Shohoku
##   name number score
## 1 赤木      4    12
## 2 桜木     10     9
## 3 三井     13    15
## 4 宮城      7    12
## 5 流川     11    14
Shohoku[3] <- Shohoku$score - 5 # 5を引いた
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9
Shohoku$score <- Shohoku$score * 3
Shohoku
##   name number score
## 1 赤木      4    21
## 2 桜木     10    12
## 3 三井     13    30
## 4 宮城      7    21
## 5 流川     11    27
Shohoku[3] <- Shohoku$score / 3
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9

2.4 個々のデータへのアクセス

方法としては$を使ってベクトルを取り出した上で[]で取り出したい値のインデックス番号を指定する方法(これは要するにベクトルでの個々のデータへのアクセスと同じ)と,[]を使って行番号と列番号を指定する方法とがある.

Shohoku$name[1]
## [1] "赤木"
Shohoku[1,1]
## [1] "赤木"

なお[行, 列]である.

Shohoku[1,1]
## [1] "赤木"
Shohoku[1,2]
## [1] 4
Shohoku[1,3]
## [1] 7

列番号は以下のように,列名(ベクトル名)で指定しても良い.行については,番号でしか基本的にアクセスできない.

Shohoku[2,"name"]
## [1] "桜木"
Shohoku[2,"number"]
## [1] 10
Shohoku[2,"score"]
## [1] 4
Shohoku["桜木","score"] # これはNAが返される
## [1] NA

以下のように,ベクトル要素の検索機能を使って行の要素を使ったアクセスは可能であるが,これは5章で触れるデータフレームのフィルタリングを使う方が直観的である.

Shohoku[Shohoku$name=="桜木","score"] 
## [1] 4

$にせよ[]にせよ,複数の要素を同時に取り出すことができる.

Shohoku$name[c(1,3,5)]  # これは単純にベクトルとして取り出した後に[]でベクトル要素をしている
## [1] "赤木" "三井" "流川"
Shohoku[c(1,3,5),1] #これはデータフレームから行番号と列番号に合致するものを直接とりだしている
## [1] "赤木" "三井" "流川"
Shohoku[c(1,3,5),"name"] #列番号をベクトル名で指定した
## [1] "赤木" "三井" "流川"

[]を使う場合で列を1つしか指定しなかった場合には上記のようにベクトルとしてデータが返される.一方,以下のように列を複数指定した場合には,データフレームとしてデータが返される.

Shohoku[c(1,3,5),c(1,3)] #複数の列(1,3列目)から複数の行番号(1,3,5行目)のデータを同時に取り出そうとしている.
##   name score
## 1 赤木     7
## 3 三井    10
## 5 流川     9
Shohoku[c(1,3,5),c("name","score")]#列指定を名前にした
##   name score
## 1 赤木     7
## 3 三井    10
## 5 流川     9

2.5 個々のデータの書き換え

ベクトルの個々のデータの書き換えと同様に,それぞれの箇所にアクセスして代入演算子で書き換えてやる.以下では前と同様に$で指定する方法で名前をローマ字に替えた後,[]で指定する方法で名前を漢字に戻している

Shohoku$name[1] <- "Akagi"
Shohoku
##    name number score
## 1 Akagi      4     7
## 2  桜木     10     4
## 3  三井     13    10
## 4  宮城      7     7
## 5  流川     11     9
Shohoku[1,1] <-"赤木"
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9

複数行を同時に書き換える場合には,ベクトルデータを与えてやる.

Shohoku$name[c(1,3,5)]<-c("Akagi","Mitsui","Rukawa")
Shohoku
##     name number score
## 1  Akagi      4     7
## 2   桜木     10     4
## 3 Mitsui     13    10
## 4   宮城      7     7
## 5 Rukawa     11     9
Shohoku[c(1,3,5),1] <-c("赤木","三井","流川")
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9

複数行,複数列を同時に書き換えたい場合には,以下のようにdata.frame()関数を使ってデータを与える.

# 赤木,三井,流川の名前をローマ字にするとともに,スコアを1にする
# name列とscore列は1列目と3列目にあるので,c(1,3)とインデックス番号で指定している
Shohoku[c(1,3,5),c(1,3)] <-data.frame(c("Akagi","Mitsui","Rukawa"),c(1,1,1))
Shohoku
##     name number score
## 1  Akagi      4     1
## 2   桜木     10     4
## 3 Mitsui     13     1
## 4   宮城      7     7
## 5 Rukawa     11     1
# 赤木,三井,流川の名前を漢字に戻すとともに,スコアも戻す
# name列とscore列は列名で指定している
Shohoku[c(1,3,5),c("name","score")] <-data.frame(c("赤木","三井","流川"),c(7,10,9))
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9

2.6 列の追加

既にあるデータフレームに新しい列(ベクトル)を追加したい場合には以下のように$[]を用いて,新しい列名(ベクトル名)を指定して,その列に入れるデータをベクトルで与えるだけでよい.追加された列はデータフレームの末尾に入れられる.

Shohoku$Initial <- c("T.A.","H.S.","H.M.","R.M.","K.R.")
Shohoku
##   name number score Initial
## 1 赤木      4     7    T.A.
## 2 桜木     10     4    H.S.
## 3 三井     13    10    H.M.
## 4 宮城      7     7    R.M.
## 5 流川     11     9    K.R.
Shohoku["Yomi"] <- c("あかぎたけのり","さくらぎはなみち","みついひさし","みやぎりょうた","るかわかえで")
Shohoku
##   name number score Initial             Yomi
## 1 赤木      4     7    T.A.   あかぎたけのり
## 2 桜木     10     4    H.S. さくらぎはなみち
## 3 三井     13    10    H.M.     みついひさし
## 4 宮城      7     7    R.M.   みやぎりょうた
## 5 流川     11     9    K.R.     るかわかえで

以下の例のように,[]を使って複数の列を同時に追加することもできる.ただし,実用の場面では記述の分かりやすさの観点から,1つ1つ追加していく方が良い.

Shohoku[c("UnderName","Roman")] <-data.frame(
  c("剛憲","花道","寿","亮太","楓"),
  c("Akagi","Sakuragi","Mitsui","Miyagi","Rukawa")
)
Shohoku
##   name number score Initial             Yomi UnderName    Roman
## 1 赤木      4     7    T.A.   あかぎたけのり      剛憲    Akagi
## 2 桜木     10     4    H.S. さくらぎはなみち      花道 Sakuragi
## 3 三井     13    10    H.M.     みついひさし        寿   Mitsui
## 4 宮城      7     7    R.M.   みやぎりょうた      亮太   Miyagi
## 5 流川     11     9    K.R.     るかわかえで        楓   Rukawa

Rの場合,それほど処理速度に敏感になる必要がないので,人から見た分かりやすさを重視した記述を心掛けるようにしよう.一方で,PythonやJavascript,あるいはC言語系などのプログラム言語を使って,動画像処理などリアルタイム性や高速な処理が求められるプログラムを記述する場合には,分かりやすさを犠牲にして,コンピュータ内部での計算処理回数の少ない書き方をすることもある.

2.7 列の削除

列を削除する場合には,削除したい列にアクセスしてNULL(ヌル)を代入すればよい.

Shohoku$Yomi <- NULL
Shohoku
##   name number score Initial UnderName    Roman
## 1 赤木      4     7    T.A.      剛憲    Akagi
## 2 桜木     10     4    H.S.      花道 Sakuragi
## 3 三井     13    10    H.M.        寿   Mitsui
## 4 宮城      7     7    R.M.      亮太   Miyagi
## 5 流川     11     9    K.R.        楓   Rukawa
Shohoku["Initial"] <- NULL
Shohoku
##   name number score UnderName    Roman
## 1 赤木      4     7      剛憲    Akagi
## 2 桜木     10     4      花道 Sakuragi
## 3 三井     13    10        寿   Mitsui
## 4 宮城      7     7      亮太   Miyagi
## 5 流川     11     9        楓   Rukawa
Shohoku[c("UnderName","Roman")] <- data.frame(NULL,NULL)
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9

2.8 行の追加

データフレームへの行の追加にはrbind()関数を使う.以下では同じ列名を持ったkogureというデータフレームを作成し,Shouhokuに追加している.

kogure <- data.frame(name="木暮", number=5, score=6)
Shohoku <- rbind(Shohoku , kogure)
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9
## 6 木暮      5     6

さらに,複数の行を同時に追加する場合には,複数行をもったデータフレームを作成してrbind()で追加する.

Reserve <- data.frame(
  name =c("潮崎","安田","角田","石井","佐々岡","桑田"),
  number=c(8, 6, 9, 12, 13, 15),
  score =c(6, 7, 7,  5,  5,  4)
)
Shohoku <-rbind(Shohoku, Reserve)
Shohoku
##      name number score
## 1    赤木      4     7
## 2    桜木     10     4
## 3    三井     13    10
## 4    宮城      7     7
## 5    流川     11     9
## 6    木暮      5     6
## 7    潮崎      8     6
## 8    安田      6     7
## 9    角田      9     7
## 10   石井     12     5
## 11 佐々岡     13     5
## 12   桑田     15     4

列名が異なると以下の通りにエラーとなる.

Reserve2 <- data.frame(
  name2 =c("潮崎","安田","角田","石井","佐々岡","桑田"),# nameがname2となっている
  number=c(8, 6, 9, 12, 13, 15),
  score =c(6, 7, 7,  5,  5,  4)
)
Shohoku <-rbind(Shohoku, Reserve2)
## Error in match.names(clabs, names(xi)): 名前が以前の名前と一致しません
Shohoku
##      name number score
## 1    赤木      4     7
## 2    桜木     10     4
## 3    三井     13    10
## 4    宮城      7     7
## 5    流川     11     9
## 6    木暮      5     6
## 7    潮崎      8     6
## 8    安田      6     7
## 9    角田      9     7
## 10   石井     12     5
## 11 佐々岡     13     5
## 12   桑田     15     4

2.9 行の削除

特定の行を削除したい場合には,以下のように削除したい行番号をベクトルで与えた上で-をつけてやる.

Shohoku <- Shohoku[-c(6,7,8,9,10,11,12), ]
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9

注意すべき点として,行指定の後に,をつけるのを忘れないようにすること. もし,をつけ忘れた場合,それは列ベクトルへのアクセスを意味するようになる.今回の場合だと列数は3つしかないので,以下の例のように特に何も起こらない.しかし,指定した列番号に対応するだけの列数があった場合には,それらの列が削除されたデータが返ってきてしまい,特にエラーにもならないので間違いに気づきにくくなる.

Shohoku <-rbind(Shohoku, Reserve)#一旦元のデータに戻す
Shohoku <- Shohoku[-c(6,7,8,9,10,11,12) ] # 行番号を指定した後,","をつけ忘れている 
Shohoku
##      name number score
## 1    赤木      4     7
## 2    桜木     10     4
## 3    三井     13    10
## 4    宮城      7     7
## 5    流川     11     9
## 6    潮崎      8     6
## 7    安田      6     7
## 8    角田      9     7
## 9    石井     12     5
## 10 佐々岡     13     5
## 11   桑田     15     4

なお,上記のように連続した番号を指定する場合に,一々すべての番号を記載するのは面倒である.このような場合には,:(シーケンス演算子)を使って始端と終端を記述するとよい.

Shohoku
##      name number score
## 1    赤木      4     7
## 2    桜木     10     4
## 3    三井     13    10
## 4    宮城      7     7
## 5    流川     11     9
## 6    潮崎      8     6
## 7    安田      6     7
## 8    角田      9     7
## 9    石井     12     5
## 10 佐々岡     13     5
## 11   桑田     15     4
Shohoku <- Shohoku[-c(6:12), ]
Shohoku
##   name number score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9

2.10 データフレームに対する演算

今回のデータフレームには,nameのような文字列型やnumberscoreのような数値型など様々な型のベクトル(列)が含まれている.このような複数の型が混在するデータフレームに対しては演算処理を行うことはできない.演算処理を行いたい場合にはあくまで演算処理をしたい数値型の列のみを抜き出して,演算処理を行う.

Shohoku * 2 #これはエラー
## Error in FUN(left, right): 二項演算子の引数が数値ではありません
Shohoku$score*2 #これは数値型のベクトルなので演算処理が可能
## [1] 14  8 20 14 18
Shohoku$name *2 #これは文字列型のベクトルなのでエラー
## Error in Shohoku$name * 2: 二項演算子の引数が数値ではありません
Shohoku[c("number","score")] *2 #データフレーム型だが,両方とも数値型なので演算処理が可能 
##   number score
## 1      8    14
## 2     20     8
## 3     26    20
## 4     14    14
## 5     22    18

2.11 列名へのアクセスと変更

列名を把握したい(アクセスしたい)場合にはcolnames()関数を用いる. また,列名を変更したい場合には,colnames()でアクセスした後に代入演算子を用いて,新しい列名を与えればよい.

colnames(Shohoku)
## [1] "name"   "number" "score"
colnames(Shohoku) <- c("名前", "背番号", "得点") 
Shohoku
##   名前 背番号 得点
## 1 赤木      4    7
## 2 桜木     10    4
## 3 三井     13   10
## 4 宮城      7    7
## 5 流川     11    9

colnames()は列名をベクトルで返してくるので,[]を用いてインデックス番号を指定してやることによって,個別の列名にアクセスしたり,個別の列名を変更することもできる.

Shohoku
##   名前 背番号 得点
## 1 赤木      4    7
## 2 桜木     10    4
## 3 三井     13   10
## 4 宮城      7    7
## 5 流川     11    9
colnames(Shohoku)[3] <- "score"
Shohoku
##   名前 背番号 score
## 1 赤木      4     7
## 2 桜木     10     4
## 3 三井     13    10
## 4 宮城      7     7
## 5 流川     11     9

自分で作れる程度のデータフレームであればあまり使うことは無いが,後で述べるように,外部のファイルからデータを読み込んだ場合には,そのファイルにどのような列が含まれているのかを把握したり,列名を変更したりするケースはよくある.

先の課題で作ったRMarkdownに追記する形で,以下の課題をRMarkdown上で実行させ,Knitでhtmlを出力させよ.

  1. 次の2つの列を持つデータフレームKantoを作成し,print()を用いて出力させよ.
    • 都道府県名 : “東京”, “千葉”, “埼玉”, “神奈川”, “茨城”, “栃木”, “群馬”
    • 県庁所在地 : “新宿”, “千葉”, “さいたま”, “横浜”, “水戸”, “宇都宮”, “前橋”
  2. Kantoに次の列を追加し,print()を用いて出力させよ.
    • 市外局番 : “03”, “043”, “048”, “045”, “029”, “028”, “027”
  3. Kantoから東京の行だけを取り出し,print()を用いて出力させよ.
  4. Kantoから埼玉と神奈川の行の市外局番だけを取り出し,print()を用いて出力させよ.
  5. Kantoの列名をPrefectureCapitalAreaCodeに変更せよ.
  6. Kantoから埼玉と神奈川の行を削除せよ.
  7. KantoからAreaCodeの列を削除せよ.

3 データの読み込み

実際の調査結果のデータを扱うときには,data.frameを毎度自分でちまちま作ってなんていられないので,表計算ソフトで作成されたデータファイルを読み込むことになる. 以下では 【test.csv】を用いるので,ファイル名をクリックしてダウンロードしておくこと.

3.1 データのアップロード

Posit Cloudを利用している場合,Rにデータを読み込ませるには,データをPosit Cloudにアップロードする必要がある.

画面の右下のペインのFileというタブをクリックすると,現在のプロジェクトのフォルダ構成が表示される.

Fileタブ
Fileタブ

このタブの上部の「Upload」をクリックすると,ファイル選択画面が出てきて,データファイルを選択するとファイルがアップロードされる.

Upload
Upload

アップロードしたファイルはFileタブのリストに表示される(今回はtest.csvというファイルをアップロードした).

Upload
Upload

3.2 CSVデータの読み込み

もっともシンプルな方法は表計算ソフトでデータファイルを保存する際にCSVというファイル形式で保存しておき,それをRで読み込む方法である.

CSVファイルとは,行ごとに要素が,(コンマ)で区切られたファイル形式である.例えば,先ほどの表の

名前 背番号 点数
赤木 4 7
桜木 10 4
三井 14 10
宮城 7 7
流川 11 9

の場合,CSVファイルでは以下のようになる.

名前, 背番号, 点数
赤木, 4, 7
桜木, 10,4
三井, 14,10
宮城, 7, 7
流川, 11, 9

CSVファイルを作るには,表計算ソフトでデータを作成(あるいは整理)したのち,保存の際にファイル形式をCSVに指定すればよい(あるいは,Google スプレッドシートの場合には,ファイル->ダウンロード->カンマ区切り形式(CSV)を選択すればよい.

csvとはComma-Separated Valuesの略で,日本語では「カンマ区切り形式」と訳される.

CSV形式のファイルをRで読み込む場合には,read.csv()関数を使う.

1つ目のオプション(引数(ひきすう)と呼ぶ)ではダブルクォーテーションで括った上で読み込むファイル(既にPosit Cloudにアップロードしてある前提)を指定する.

2つ目の引数では,最初の行をヘッダー,つまり各列の名前として読み込むのか,最初の行をデータとして読み込むのかの指定である.TRUEだとヘッダーとして読み込み,FALSEだとデータとして読み込む.

3つ目の引数はファイルのエンコード形式を指定するもので,日本語のデータを読み込む場合には"UTF8"を指定する.

以下の例では,test.csvというファイルを読み込み,その内容をmyDataというオブジェクトに格納している.

myData <- read.csv("test.csv", header = TRUE, fileEncoding = "UTF8")
myData
##   名前 背番号 点数
## 1 赤木      4    7
## 2 桜木     10    4
## 3 三井     14   10
## 4 宮城      7    7
## 5 流川     11    9

header=FALSEだと以下の通りとなる.

myData <- read.csv("test.csv", header = FALSE, fileEncoding = "UTF8") 
myData
##     V1     V2   V3
## 1 名前 背番号 点数
## 2 赤木      4    7
## 3 桜木     10    4
## 4 三井     14   10
## 5 宮城      7    7
## 6 流川     11    9

それぞれの列名がV1, V2, V3となっており(自動的にそういう名前が割り当てられる),もともと列名としていた名前, 背番号, 点数がデータの1行目に含められてしまっているのがわかる.

1行目をヘッダとして読むのか,データとして読むのかは読み込みたいファイルの中身に合わせて設定する.また,1行目をデータとして読み込んだ際には,自分で分かりやすい名前をcolnames()関数を使って設定すること.

なお,ExcelでCSVファイルを作った場合には,上記のコマンドではうまく読まない場合がある.その場合には3つ目のfileEncodingのオプションを以下の通りに”SJIS”と指定する.(上のコマンドでうまく行っている場合には,逆に以下のコマンドだとエラーとなる)

myData <- read.csv("test.csv", header = TRUE, fileEncoding = "SJIS") 
## Warning in read.table(file = file, header = header, sep = sep, quote = quote, :
## 入力コネクション 'test.csv' に不正な入力がありました
## Warning in read.table(file = file, header = header, sep = sep, quote = quote, :
## incomplete final line found by readTableHeader on 'test.csv'
myData
##   蜷榊燕 閭檎分蜿キ 轤ケ謨ー
## 1 襍、譛ィ         4      7
## 2 譯懈惠        10      4
## 3  荳我コ        NA     NA
エンコードとは コンピュータは内部ではあくまで0と1の組み合わせでデータを扱っている.そのため,文字データをコンピュータ内部で扱う際には,各文字と0と1の組み合わせを互いに変換する必要がある.この変換の仕方をエンコードと呼ぶ.アルファベットや数字,記号などの半角文字の場合には,基本的にはASCII(American Standard Code for Information Interchange)というエンコード方式が使われる.一方で,日本語のような全角文字の場合には,伝統的にWindows系はShift-JIS,Unix系はEUC-JPが用いられるなど,様々なエンコード方式が存在している.最近ではすべてのパソコンで共通して使えるようなエンコード方式としてUTF-8という方式が作られ利用が広がってきているが,一部のWindowsアプリではいまだにShift-JISを基本としているものが残ってしまっている.異なるエンコード方式で変換をしてしまうと激しい文字化けが起こるため,エンコードは適切に設定してやる必要がある.

Homeフォルダに別のフォルダを置いて,その中に読み込みたいファイルを置いている場合には,以下のように,フォルダ名を含めたファイル名を指定する.例えばHomeの下にPracticeというフォルダを置き,その中にtest.csvを置いている場合には以下のように入力する.

myData <- read.csv("./Practice/test.csv", header = TRUE, fileEncoding = "UTF8")
Excelデータの読み込み

Excelファイルを直接読み込みたい場合には,Posit Cloudに読み込みたいExcelファイルをアップロードしたうえで,RStudioのFileメニュー->Import Database ->From Excelを選択する.今回は【test.xlsx】を用いて実際にやってみる.

Excelファイルの読み込み
Excelファイルの読み込み

そのプロジェクト内で初めてExcelファイルを読み込む場合には,追加パッケージの読み込み確認の画面が出てくるが,そのまま「OK」をクリックすればよい. すると,パッケージの読み込みが暫く行われたのち,以下のようなウィンドウが表示される.

Excelファイルの読み込み画面
Excelファイルの読み込み画面

この画面の右上部の「Browse」ボタンをクリックすると,現在のプロジェクトにあるファイルリストが表示されるので,アップロードしておいたExcelファイルを選択する.すると,自動でファイルの中身が読み込まれ,プレビューが表示される.

このプレビューの下部にあるオプションを指定することによって,読み込みにあたっての細かな設定をする事が出来る.それぞれ,以下の通りである.

項目 内容
Name 読み込んだデータを格納するオブジェクトの名前の設定.デフォルトでは読み込んだファイル名がそのまま入力されている
Sheet Excelファイルのどのシートのデータを読むのかの設定
Range 読み込む範囲の指定.エクセルの範囲表記の方法で記述する
Max Rows 読み込む最大行数の指定.データの行数よりも大きい数を指定した場合には無視される
Skip 読み込みをスキップする行数.指定した行数分だけデータの読み込みが飛ばされる.なお,ヘッダ部はカウントされない
First Row as Names 読み込むにあたって最初の行をヘッダ(列名)として読むのかデータとして読むのかの指定
Open Data Viewer データの読み込みが終わったあと,自動的にデータ閲覧画面を開くかどうかの指定

以下の例では,オブジェクトの名前をmyDataに変更したものである.

オプション設定
オプション設定

右下部には,設定したオプションでExcelファイルを読み込むための関数一式(スクリプトと呼ぶ)が表示されている(このスクリプトは後で重要になるので,ここに表示されているということは覚えておこう).

この状態で「Import」を押すと,先ほど表示されていたスクリプトが実行され,以下の図のように読み込んだデータの閲覧画面が表示される.

読み込み後
読み込み後

また,以下のようにConcoleにmyDataと入力すると,console中にmyDataの中身が表示される.

myData  # print(myData)でも可
##   蜷榊燕 閭檎分蜿キ 轤ケ謨ー
## 1 襍、譛ィ         4      7
## 2 譯懈惠        10      4
## 3  荳我コ        NA     NA
スクリプトでExcelファイルを読み込む

以上の処理は,GUIを使ってExcelデータを読み込む方法であったが,この方法の場合,Rを立ち上げ直したり,プロジェクトを再読み込みしたりすると,毎回GUIを使ってExcelファイルを読み込む必要がある.

スクリプトにExcelファイルを読みこむコードを記述しておけば,そのスクリプトを実行するだけで,Excelファイルを読み込むことができる.

そのための方法は,先ほどの「Excelファイルの読み込み画面の右下に表示されているCode Previewに記載されているスクリプトをコピーして,スクリプトエディタに貼り付けることである.

もっともシンプルなものとしては,以下のようなコードとなっているので,これをコピぺすればよ.

library(readxl)
myData <- read_excel("test.xlsx")

このスクリプトを実行することで,Excelファイルを読み込むことができる.

読み込むシートを変更したり,読み込む範囲を限定したり,あるいは先頭行をヘッダとして読み込むかどうかなどの設定は,read_excel()関数のオプションで指定することもできるが,このあたりはExcelファイルの読み込み画面のGUI上で設定しておくと,その設定がCode Previewに反映されるので,それをコピーすると良いだろう.

3.3 データのアクセス,加工

読み込んだデータはデータフレーム型となるため,データフレームの中で説明した方法で,以下のようにして各列にアクセスしたり,データを書き換えたり,列を追加したりできる.

myData <- read.csv("test.csv", header = TRUE, fileEncoding = "UTF8") 
myData$名前
## [1] "赤木" "桜木" "三井" "宮城" "流川"
myData[1, "名前"] <- "Akagi"
myData
##    名前 背番号 点数
## 1 Akagi      4    7
## 2  桜木     10    4
## 3  三井     14   10
## 4  宮城      7    7
## 5  流川     11    9
myData$名前[1] <- "赤木"
myData
##   名前 背番号 点数
## 1 赤木      4    7
## 2 桜木     10    4
## 3 三井     14   10
## 4 宮城      7    7
## 5 流川     11    9
myData$Yomi <- c("あかぎ", "さくらぎ", "みつい", "みやぎ", "るかわ")
myData
##   名前 背番号 点数     Yomi
## 1 赤木      4    7   あかぎ
## 2 桜木     10    4 さくらぎ
## 3 三井     14   10   みつい
## 4 宮城      7    7   みやぎ
## 5 流川     11    9   るかわ

先の課題で作ったRMarkdownに追記する形で,以下の課題をRMarkdown上で実行し,Knit出力させよ.

次のファイルをダウンロードし,Posit Cloudに読み込ませたうえで,その読み込ませた内容を表示させよ.なお,読み込ませる際のオブジェクト名は任意のオブジェクト名として構わない.

また,読み込ませたデータのうち,ポジションDFの選手の名前背番号を取り出してprint()で表示させよ.

4 ここまでで用いられていたR関数

  • c()

    • 説明:ベクトルを作成し,複数の値を1つのベクトルとしてまとめる.
    • 引数:要素として含める値(複数の値をコンマで区切って指定する).
  • unname()

    • 説明:名前付きベクトルの名前を取り除き,値だけを返す.
    • 引数:名前を除去したい名前付きベクトル.
  • [](角カッコ)

    • 説明:ベクトルやデータフレームの要素にアクセスしたり選択するためのインデックス操作.
    • 引数:
      • i:行番号または要素番号(ベクトルの場合は1次元,データフレームの場合は2次元).
      • j:列番号または列名(データフレームの場合).
  • :

    • 説明:連続する整数のシーケンスを生成する.
    • 引数:開始値と終了値.
  • -

    • 説明:ベクトルから要素を削除するために使用する.
    • 引数:削除したい要素のインデックス番号.
  • $

    • 説明:データフレームの特定の列にアクセスするための演算子.
    • 引数:アクセスしたい列名.
  • rbind()

    • 説明:データフレームに新しい行を追加するための関数.
    • 引数:結合したいデータフレームやベクトル.
  • colnames()

    • 説明:データフレームの列名を取得または設定するための関数.
    • 引数:
      • x:列名を取得または設定するデータフレーム.
      • value:新しく設定する列名(列名を変更する場合).
  • data.frame()

    • 説明:複数のベクトルをまとめてデータフレームを作成する.
    • 引数:列ごとのベクトル(同じ長さである必要がある).
  • rbind()

    • 説明:データフレームに行を追加するための関数.
    • 引数:既存のデータフレームと追加したい行データ(ベクトルやデータフレーム).
  • read.csv()

    • 説明:CSVファイルを読み込んでデータフレームとしてインポートする.
    • 引数:
      • file:読み込むCSVファイルのパス.
      • header:最初の行を列名として読み込むかどうか.TRUEで列名として読み込み,FALSEでデータとして読み込む.省略するとTRUEに設定される.
      • sep:CSVファイルの区切り文字.省略するとコンマに設定される.
      • fileEncoding:ファイルのエンコーディング(例:“UTF-8”,“SJIS”).省略するとUTF-8に設定される.