Rの行列と配列:2次元および多次元のデータ構造
前回のレッスンでは、「1次元」ベクトルについて学びました。今回のレッスンでは、「2次元」および「多次元」の概念、すなわち行列と配列について取り上げます。行列はデータ分析の基礎となるものです(Excelのスプレッドシート、画像のピクセル、ニューラルネットワークの重みなどはすべて行列です)。ですから、今回のレッスンでしっかりと理解しておきましょう。
行列の「核心」となるのが apply() 関数群です。これを使えば、ループを記述することなく、行、列、あるいは次元ごとに演算を行うことができます。この点において、RはPythonよりも簡潔です。
1. 学習内容
- matrix() は行列を作成します(行単位または列単位で値を埋めます)
- 行列のプロパティ(dim、nrow、ncol、rownames、colnames)
- rbind/cbind:行列の結合
- ファミリー関数(apply/lapply/sapply/tapply/mapply)を適用する
arrayデータ型の多次元拡張- 行列演算(転置
%*%、逆行列solve()) - 実践編:トランスクリプトの統計
2. 成績証明書の物語
(1) 課題:複数の教科にわたる成績の集計
シャオ・ジャオは学務担当官です。3つの科目における5人の学生の成績証明書は以下の通りです:
Mathematics Chinese Language English
Alice 85 78 92 Bob 72 88 80 Charlie 90 85 87 Diana 65 70 75 Eve 95 92 88
以下の計算を行ってください:① 各生徒の合計得点、② 各教科の平均得点、③ 数学で最高得点を記録した生徒を特定すること。
これをExcelの数式で記述しようとすると、とてつもなく時間がかかってしまいます。Pythonで記述する場合、ネストされたループを使わなければなりません――
(2) Rを用いた解決策
# 5x3 Matrix
scores <- matrix(c(85, 78, 92,
72, 88, 80,
90, 85, 87,
65, 70, 75,
95, 92, 88),
nrow = 5, byrow = TRUE)
colnames(scores) <- c("Mathematics", "Chinese Language", "English")
rownames(scores) <- c("Alice", "Bob", "Charlie", "Diana", "Eve")
# 1. Each Student's Total Score(Sum in One Line)
row_sums <- apply(scores, 1, sum)
# 2. Average per subject(Calculate the average for a column)
col_means <- apply(scores, 2, mean)
# 3. Find the highest score in math
top_math <- which.max(scores[, "Mathematics"])
たった5行のコードで3つの課題を解決。 これこそが行列とapply関数の威力の証です。
3. 行列の本質:2次元ベクトル
(1) ベクトルから行列への変換
graph LR A["One-dimensional vector c 1,2,3,4,5,6"] --> B["reshape into 2x3 Matrix"] B --> C["1 2 3 / 4 5 6"] B --> D["1 4 / 2 5 / 3 6"]
style A fill:#cce5ff
style B fill:#fff3cd
# One-dimensional vector
v <- 1:6
v
# [1] 1 2 3 4 5 6
# Convert to 2 row 3 List of Matrices
m <- matrix(v, nrow = 2, ncol = 3)
m
# [,1] [,2] [,3]
# [1,] 1 3 5
# [2,] 2 4 6
(2) 行列の4つの主要な性質
| 項目 | 意味 | 例 |
|---|---|---|
dim(m) |
次元ベクトル | dim(m) → c(2, 3) |
nrow(m) |
行番号 | nrow(m) → 2 |
ncol(m) |
行数 | ncol(m) → 3 |
length(m) |
要素の総数 | length(m) → 6 |
m <- matrix(1:6, nrow = 2)
dim(m) # [1] 2 3 nrow(m) # [1] 2 ncol(m) # [1] 3
length(m) # [1] 6 ← Total Number of Elements
4. matrix(): 行列を作成する
(1) 基本的な構文
matrix(data, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL)
(2) 創作のための4つの方法
# 1. Provide the data directly + Number of rows and columns
m1 <- matrix(1:6, nrow = 2)
# [,1] [,2] [,3]
# [1,] 1 3 5 ← Fill by column by default
# [2,] 2 4 6
# 2. byrow = TRUE(Fill by Row)
m2 <- matrix(1:6, nrow = 2, byrow = TRUE)
# [,1] [,2] [,3]
# [1,] 1 2 3
# [2,] 4 5 6
# 3. Add row and column names
m3 <- matrix(1:6, nrow = 2, byrow = TRUE,
dimnames = list(c("row1", "row2"), c("colA", "colB", "colC")))
# colA colB colC
# row1 1 2 3
# row2 4 5 6
# 4. Specify only nrow,ncol Automatic Inference
m4 <- matrix(1:6, nrow = 3) # 3 row 2 col
# [,1] [,2]
# [1,] 1 4
# [2,] 2 5
# [3,] 3 6
byrow = FALSE はデフォルトの設定(列単位で埋める)です。ほとんどの場合、行単位で埋める(1行につき1人の学生/1レコード)ことが望ましいため、byrow = TRUE を明示的に指定する必要があります。
(3) 列ラベルと行ラベルを追加する(読みやすさを高めるため)
m <- matrix(1:6, nrow = 2, byrow = TRUE)
rownames(m) <- c("Alice", "Bob")
colnames(m) <- c("Mathematics", "Chinese Language", "English")
m
# Mathematics Chinese Language English
# Alice 1 2 3
# Bob 4 5 6
5. 行列の要素へのアクセス
(1) アクセス方法 3 つ
| メソッド | 構文 | 目的 |
|---|---|---|
[i, j] |
行 i、列 j | 単一要素 |
[i, ] |
行 i | 行全体 |
[, j] |
列 j | 列全体 |
[i, "col_name"] |
i行目の列 | 名前別 |
m <- matrix(1:9, nrow = 3, byrow = TRUE,
dimnames = list(c("Alice", "Bob", "Charlie"),
c("Mathematics", "Chinese Language", "English")))
m
# Mathematics Chinese Language English
# Alice 1 2 3
# Bob 4 5 6
# Charlie 7 8 9
# A single element
m[2, 3] # [1] 6
m["Bob", "English"] # [1] 6
# Entire row
m[1, ] # Mathematics 1 Chinese Language 2 English 3
m["Alice", ] # Ibid.
# Align
m[, 1] # Alice 1 Bob 4 Charlie 7
m[, "Mathematics"] # Ibid.
(2) 論理インデックス
# Find the math scores > 5 students
m[m[, "Mathematics"] > 5, ]
# Mathematics Chinese Language English
# Bob 4 ... ← Will not be selected
# Charlie 7 8 9
6. rbind/cbind:行列の結合
graph TB A["Matrix A 3x2"] --> C["rbind Concatenate by row"] B["Matrix B 2x2"] --> C C --> D["New Matrix 5x2"]
E["Matrix A 3x2"] --> F["cbind Concatenate by Column"]
G["Matrix B 3x2"] --> F
F --> H["New Matrix 3x4"]
style A fill:#cce5ff
style B fill:#cce5ff
style E fill:#d4edda
style G fill:#d4edda
a <- matrix(1:6, nrow = 3, byrow = TRUE)
b <- matrix(7:12, nrow = 3, byrow = TRUE)
# Concatenate by row(Sum of Rows)
rbind(a, b)
# [,1] [,2]
# [1,] 1 2
# [2,] 3 4
# [3,] 5 6
# [4,] 7 8
# [5,] 9 10
# [6,] 11 12
# Concatenate by Column(Sum of a Series)
cbind(a, b)
# [,1] [,2] [,3] [,4]
# [1,] 1 2 7 8
# [2,] 3 4 9 10
# [3,] 5 6 11 12
rbind(a, b) には ncol(a) == ncol(b) が必要であり、cbind(a, b) には nrow(a) == nrow(b) が必要です。これらが満たされていない場合、エラーが発生します。
7. apply 関数シリーズ(その本質)
(1) なぜ apply が必要なのでしょうか?
Rでのループは非常に遅いですが、applyを使えば、ループを記述することなく、行ごとや列ごとに演算を実行することができます:
m <- matrix(1:9, nrow = 3)
# Find the sum of each row(No need for a loop)
apply(m, 1, sum)
# [1] 12 15 18
# Find the sum of each column
apply(m, 2, sum)
# [1] 12 15 18
(2) apply()の核心
apply(X, MARGIN, FUN)
| パラメータ | 意味 | 取り得る値 |
|---|---|---|
X |
行列/配列 | 行列/配列 |
MARGIN |
次元 | 1=行, 2=列, c(1,2)=行と列 |
# 1=row(Process by row),2=col(Process by Column)
apply(m, 1, mean) # Average per line
apply(m, 2, max) # Maximum per column
# Custom Functions
apply(m, 1, function(x) max(x) - min(x)) # Range per row
(3) apply シリーズの 5 つの機能
| 機能 | 入力 | 出力 | 代表的な用途 |
|---|---|---|---|
apply() |
行列・配列 | ベクトル・行列 | 行・列の演算 |
lapply() |
リスト/ベクトル | リスト | リストの処理 |
sapply() |
リスト/ベクトル | ベクトル/行列 | 簡略化された lapply |
tapply() |
ベクトルと群 | 配列 | 群の統計 |
mapply() |
マルチベクトル | リスト/ベクトル | 多引数関数 |
(4) lapply() 対 sapply()
# lapply Back to List
numbers <- list(a = 1:3, b = 4:6, c = 7:9)
result_l <- lapply(numbers, sum)
# $a 6
# $b 15
# $c 24
# sapply Return Vector(More commonly used)
result_s <- sapply(numbers, sum)
# a b c
# 6 15 24
sapply() を使用してください—ベクトルを返す際に便利です。lapply() は関数型プログラミングのパイプラインでより一般的に使用されます。
(5) tapply() によるグループ別統計
# 5 Students 3 Course Grades, grouped by "Gender"
scores <- c(85, 78, 92, 72, 88, 80, 90, 85, 87, 65, 70, 75, 95, 92, 88)
gender <- c("M", "F", "M", "M", "F", "F", "M", "M", "F", "M", "F", "M", "F", "M", "F")
# Calculate the average by gender
tapply(scores, gender, mean)
# F M
# 84.6 81.5
tapply()が非常に頻繁に使われます—しかし、次の段階ではdplyr::group_by() | summarise()を使ったほうがより洗練された表現になります。
(6) mapply()—多引数関数
# Sum the corresponding elements of two vectors
mapply(function(a, b) a + b, 1:3, 10:12)
# [1] 11 13 15
8. 配列:多次元への拡張
# 2x3x4 a three-dimensional array
arr <- array(1:24, dim = c(2, 3, 4))
# 1st 2x3 Matrix
arr[, , 1]
# [,1] [,2] [,3]
# [1,] 1 3 5
# [2,] 2 4 6
# apply Supports multidimensional operations
apply(arr, c(1, 2), mean) # Regarding No. 3 Find the average
data.frame(Next Stage)とarray(画像・物理)が主流のアプローチです。
9. 行列演算(線形代数)
| 操作 | 構文 | 説明 |
|---|---|---|
| 転置 | t(m) |
行から列へ |
| 行列の乗算 | m1 %*% m2 |
線形代数の乗算 |
| 要素ごとの乗算 | m1 * m2 |
対応する要素ごとの乗算 |
| 逆行列 | solve(m) |
逆行列 |
| 合計(行/列) | rowSums(m) / colSums(m) |
クイック合計 |
m <- matrix(1:4, nrow = 2)
# [,1] [,2]
# [1,] 1 3
# [2,] 2 4
# Transpose
t(m)
# [,1] [,2]
# [1,] 1 2
# [2,] 3 4
# Matrix Multiplication (use m %*% m)
m %*% m
# [,1] [,2]
# [1,] 7 15
# [2,] 10 22
# Inverse
solve(m)
# [,1] [,2]
# [1,] -2 1.5
# [2,] 1 -0.5
10. 完全な例:トランスクリプトの包括的な分析
以下は、このレッスンで学んだすべての行列とapply関数を組み合わせた完全なワークフローの例です。
▶ サンプル:クラスの成績の包括的な分析
# ============================================
# Comprehensive Analysis of Class Performance
# Features:5 Student 3 A Comprehensive Analysis of the Course Grade Matrix
# ============================================
# 1. Create a Grade Matrix(Fill by Row:One student per line)
scores <- matrix(c(
85, 78, 92, # Alice
72, 88, 80, # Bob
90, 85, 87, # Charlie
65, 70, 75, # Diana
95, 92, 88 # Eve
), nrow = 5, byrow = TRUE)
# Add row and column names
rownames(scores) <- c("Alice", "Bob", "Charlie", "Diana", "Eve")
colnames(scores) <- c("Mathematics", "Chinese Language", "English")
cat("=== Grade Matrix ===\n") print(scores)
# 2. Each Student's Total Score(Sum by Row)
cat("\n=== Student's Total Score ===\n")
row_totals <- apply(scores, 1, sum)
print(row_totals)
# 3. Average per subject/Highest/Lowest(Tally by Column)
cat("\n=== Statistics by Subject ===\n")
col_stats <- apply(scores, 2, function(x) {
c(mean = round(mean(x), 2),
max = max(x),
min = min(x),
sd = round(sd(x), 2))
})
print(col_stats)
# 4. Average score per student(Calculate the average by row)
cat("\n=== Average Student Score ===\n")
row_means <- apply(scores, 1, mean)
print(round(row_means, 2))
# 5. Identify the student with the highest math score
top_math <- which.max(scores[, "Mathematics"])
cat("\nHighest Score in Math:", rownames(scores)[top_math], "(", max(scores[, "Mathematics"]), "min)\n")
# 6. Identify the student with the highest total score
top_total <- which.max(row_totals)
cat("Highest Total Score:", rownames(scores)[top_total], "(", max(row_totals), "min)\n")
# 7. Find a single subject < 70 students(Using Logical Indexes)
fail <- scores < 70
cat("\nFailed Courses(< 70):\n")
print(scores)
cat("\nDid I fail?(TRUE = Fail):\n")
print(fail)
# 8. Overall Ranking
cat("\n=== Overall Ranking(Sort by total score in descending order)===\n")
ranking <- order(row_totals, decreasing = TRUE)
result <- data.frame(
Ranking = 1:5,
Name = rownames(scores)[ranking],
Total Score = row_totals[ranking],
Average = round(row_totals[ranking] / 3, 2)
)
print(result)
期待される出力(抜粋):
=== Grade Matrix === Mathematics Chinese Language English Alice 85 78 92 Bob 72 88 80 Charlie 90 85 87 Diana 65 70 75 Eve 95 92 88
=== Student's Total Score === Alice Bob Charlie Diana Eve 255 240 262 210 275
=== Average Student Score === Alice Bob Charlie Diana Eve 85.00 80.00 87.33 70.00 91.67
=== Overall Ranking(Sort by total score in descending order)===
Ranking Name Total Score Average
1 1 Eve 275 91.67
2 2 Charlie 262 87.33
3 3 Alice 255 85.00
4 4 Bob 240 80.00
5 5 Diana 210 70.00
❓ よくある質問
byrow = TRUE と FALSE の違いは何ですか?matrix(1:6, nrow=2, byrow=FALSE)(デフォルト)は列単位で埋められます:1 3 5 / 2 4 6;byrow=TRUE は行単位で埋められます:1 2 3 / 4 5 6。データサイエンスの場面では、データはほぼ常に行単位で埋められます(サンプルごとに1行)。apply() と for ループのどちらを選べばよいですか?apply() を使用してください。R のループは 10 倍から 100 倍も遅くなります。「行単位でループする」場合は apply(m, 1, fun) を、「列単位でループする」場合は apply(m, 2, fun) を使用してください。tapply() 実際のプロジェクトでは、これはどのように使われるのですか?tapply(x, group, fun) 性別、地域、月などによるグループ分けを行い、「グループ別統計」を素早く算出するためです。ただし、次の段階では、dplyr::group_by() \| summarise() を使用する方がより洗練されたアプローチとなります。その基礎となるのが tapply です。📖 まとめ
- 行列は2次元ベクトルであるのに対し、配列は多次元ベクトルである;
matrix()作成、array()多次元への拡張 byrow = TRUE行単位で埋める(データサイエンスの標準)、FALSE(デフォルト) 列単位で埋める- アクセス方法
m[i, j]/m[i, ]/m[, j]/m["row", "col"] rbind()行ごとに並べ替え、cbind()列ごとに並べ替え- 適用ファミリー:
apply()次元別、lapply()リスト → リスト、sapply()リスト → ベクトル、tapply()グループ別統計、mapply()複数パラメータ - 行列演算:
t()転置、%*%行列積、solve()行列の逆行列、rowSums()colSums()高速和計算 - ループの代わりに
applyを使用する:R でのループは 10~100 倍遅くなります。applyを使用できる場合は、ループを書かないでください
📝 練習問題
-
基本問題:1 から 16 までの要素を持つ 4×4 の行列を作成し、行ごとに埋めていき、行ラベルと列ラベルをそれぞれ
c("A","B","C","D")およびc("X","Y","Z","W")とする。行列を出力し、行ラベルと列ラベルが正しいことを確認する。 -
基本問題:
apply()を使用して、前の問題の行列について、行の合計、列の合計、行の平均、および列の最大値を計算しなさい。 -
基本演習:
rbind()とcbind()を使用して、自分で作成した 2 つの 3×3 行列を合成し、行数と列数がどのように変化するかを確認してください。 -
応用問題:4つの科目における6人の学生の成績をシミュレートしてください。①
apply()を使用して、各学生の合計得点を計算してください。②apply()を使用して、各科目の平均得点を計算してください。③which.max()を使用して、各科目で最高得点を記録した学生の名前を特定してください。④order()を使用して、学生を順位付けする。 -
課題:5つの科目における100人の学生の成績について「階層別分析」を行うスクリプトを作成してください。①
tapply()を使用して、「性別」ごとにグループ分けし、総合平均を算出してください。② 数学で90点以上を取得したが、英語で不合格(60点未満)となった学生の人数を特定してください。③ 各学生の5科目の標準偏差を計算する(apply()とカスタム関数を使用)。



