製薬企業研究者がRのデータ構造についてまとめてみた

# はじめに

ここでは、Rの初心者向けに「データ構造」について解説します。
Rというプログラミング言語の特徴が凝縮されているところですが、基本的な部分にしぼって解説します。


# ベクトル（vector）

ベクトルは、同じデータ型の1つ以上の要素をまとめたものになります。

## ベクトルの作成

```r:vector_1.R
vec.int <- c(1, 3, 8) #数値
print(vec.int)

vec.str <- c("a", "b", "c") # 文字列
print(vec.str)

vec.bool <- c(TRUE, FALSE, TRUE) # 真偽値
print(vec.bool)

vec.seq1 <- 1:10 # 連続した数値
print(vec.seq1)

vec.seq2 <- seq(1, 11, 2) # 2刻みの数値
print(vec.seq2)

vec.rep1 <- rep(1, 10) # 同じ値の繰り返し
print(vec.rep1)
```

## ベクトルの要素へのアクセス

```r:vector_2.R
vec.seq <- seq(1, 10)

print(vec.seq[1]) # 1番目の値を参照する。
print(vec.seq[3:7]) # 3番目から7番目の値を参照する。
print(vec.seq[-1]) # 1番目の値を取り除いて返される。
print(vec.seq[c(-7, -10)]) # 7番目と10番目の値を取り除いて返される。
print(vec.seq[vec.seq %% 2 == 1]) # 奇数の要素だけ返す。
```

## ベクトルの要素の更新

```r:vector_3.R
vec.seq <- seq(1, 10)
vec.seq[10] <- 100
print(vec.seq)
```

## ベクトルの要素の追加

```r:vector_4.R
vec.seq <- seq(1, 10)
vec.seq[11] <- 11
print(vec.seq)
```


## ベクトルの演算

```r:vector_5.R
vec <- seq(1, 10)

print(sum(vec)) # 合計
print(length(vec)) # 要素の数
print(mean(vec)) # 平均値
print(median(vec)) # 中央値
print(max(vec)) # 最大値
print(min(vec)) # 最小値
print(var(vec)) # 不偏分散
print(sd(vec)) # 標準偏差
print(vec%%2==1) # 各要素が奇数かどうか
print(sum(vec%%2==1)) # 奇数の要素の数


vec.minus = c(-1, -2)

print(abs(vec.minus)) # 絶対値


vec.a <- c(1, 2)
vec.b <- c(3, 4)

print(vec.a + vec.b) # 要素同士の足し算
print(vec.a - vec.b) # 要素同士の引き算
print(vec.a * vec.b) # 要素同士の掛け算
print(vec.a / vec.b) # 要素同士の割り算
```

今回の`vec`に対しては、不偏分散や標準偏差を求める意味はあまりありませんが、計算上はできるということで載せています。
`sum(条件)`とした場合は、真偽値のベクトルが生成され、`TRUE`が`1`、`FALSE`が`0`となって、足し算すると`TRUE`の数、つまり条件を満たす要素の数が得られる、というイメージです。


# リスト（list）

リストは、異なるデータ構造をまとめたものになります。

## リストの作成

```r:list_1.R
list.1 <- list(c(TRUE, FALSE, TRUE), 'R', matrix(1:6, 2, 3))
print(list.1)

list.2 <- list(vec=c(TRUE, FALSE, TRUE), str='R', mat=matrix(1:6, 2, 3)) # 要素に名前をつけることも可能。
print(list.2)
```


## リストの要素へのアクセス

```r:list_2.R
list.1 <- list(c(TRUE, FALSE, TRUE), 'R', matrix(1:6, 2, 3))

print(list.1[[1]])
print(list.1[[1]][2])
print(list.1[[2]])
print(list.1[[3]])
print(list.1[[3]][2,])
print(list.1[[3]][2, 3])

list.2 <- list(vec=c(TRUE, FALSE, TRUE), str='R', mat=matrix(1:6, 2, 3))

print(list.2$vec)
print(list.2$vec[2])
print(list.2$str)
print(list.2$mat)
print(list.2$mat[2, 3])
```


# 行列（matrix）

行列は2次元のデータになります。

## 行列の作成

```r:matrix_1.R
mat.1 <- matrix(seq(1, 6), nrow = 2) # 行数を指定
print(mat.1)

mat.2 <- matrix(seq(1, 6), ncol = 3) # 列数を指定
print(mat.2)

mat.3 <- matrix(seq(1, 6), nrow = 2, byrow = TRUE) # 行ごとに値を並べる。
print(mat.3)
```

以下のように、ベクトルを結合して行列を作ることもできます。

```r:matrix_2.R
vec.1 <- seq(1, 3)
vec.2 <- seq(4, 6)
vec.3 <- seq(7, 9)

mat.c <- cbind(vec.1, vec.2) # 列ごとに値を並べる。
print(mat.c)
print(cbind(mat.c, vec.3)) # 行列とベクトルを結合することも可能。

mat.r <- rbind(vec.1, vec.2) # 行ごとに値を並べる。
print(mat.r)
print(rbind(mat.r, vec.3)) # 行列とベクトルを結合することも可能。
```

## 行列の要素へのアクセス

```r:matrix_3.R
mat <- matrix(1:6, 2, 3)

print(mat[2, 3])
print(mat[2,])
print(mat[, 3])
print(mat[2, c(1, 3)])
print(mat[1:2, 2:3])
```


## 行列の演算

```r:matrix_5.R
mat.a <- matrix(1:4, 2, 2)
mat.b <- matrix(5:8, 2, 2)

print(mat.a + mat.b) # 行列和
print(mat.a * mat.b) # 要素ごとの掛け算
print(mat.a %*% mat.b) #行列積

print(det(mat.a)) # 行列式
print(eigen(mat.b)) # 固有値
```


# データフレーム（dataframe）

データフレームはリストの行列版というイメージです。

## データフレームの作成

```r:dataframe_1.R
gender <- c("M", "F", "M")
height <- c(180, 155, 170)
weight <- c(100, 50, 75)

humans <- data.frame(性別=gender, 身長=height, 体重=weight)
print(humans)
```

## データフレームの要素へのアクセス

```r:dataframe_2.R
gender <- c("M", "F", "M")
height <- c(180, 155, 170)
weight <- c(100, 50, 75)

humans <- data.frame(性別=gender, 身長=height, 体重=weight)

print(humans[2, 3]) # 行、列の番号を指定。
print(humans$身長) # 列名を指定。
print(humans$体重[3]) #列名と番号を指定。
```


## データフレームへの行、列の追加、削除

```r:dataframe_3.R
gender <- c("M", "F", "M")
height <- c(180, 155, 170)
weight <- c(100, 50, 75)

humans <- data.frame(性別=gender, 身長=height, 体重=weight)

humans$血液型 <- c("A", "B", "O") # 新しく列名を指定して追加。
print(humans)

humans$血液型 <- NULL #列名を指定して削除
print(humans)

blood.type <- c("A", "B", "O")
print(cbind(humans, blood.type))

woman <- c("F", 165, 55)
print(rbind(humans, woman))
```

# 行、列ごとの計算

```r:dataframe_4.R
height <- c(180, 155, 170)
weight <- c(100, 50, 75)

humans <- data.frame(身長=height, 体重=weight)

print(apply(humans, 2, mean)) #列ごとの平均が求められる。
```

`apply()`関数の第二引数が1の場合は行ごとに計算することになりますが、今回のデータの場合は意味がないので省略しています。


# 配列（array）

配列は3次元以上のデータになります。

## 配列の作成

```r:array_1.R
arr <- array(c(10:15, 20:25, 30:35, 40:45), dim = c(2, 3, 4))
print(arr)
```


## 配列の要素へのアクセス

```r:array_2.R
arr <- array(c(10:15, 20:25, 30:35, 40:45), dim = c(2, 3, 4))

print(arr[1, , ])
print(arr[1, 2, ])
print(arr[1, 2, 3])
```

# まとめ

ここでは、「ベクトル」「リスト」「行列」「データフレーム」「配列」について解説しました。
中でも「データフレーム」は、Rでプログラミングをしていく中でよく使うデータ構造なので、理解を深めておきたいところです。


# 参考資料・リンク

[プログラミング言語Rとは？統計分析に強い？](https://pharma-engineer.com/basic-programming/r-summary/)