Rの関数:sparseMatrix {Matrix}

Rの関数から sparseMatrix {Matrix} を確認します。

関数 sparseMatrix とは

sparseMatrix は、疎行列(成分の多くが 0 である行列)を効率的に生成するための関数です。

疎行列を通常の行列として全ての 0 を保持するとメモリを大量に消費しますが、この関数を用いることで、非ゼロの要素の位置と値のみを記録する形式(疎行列形式)のオブジェクトを作成できます。

主に以下の2つの入力形式をサポートしています。

  1. Coordinate List (COO) / Triplet 形式:

    • 行番号 i、列番号 j、そして値 x の3つのベクトルを用いて定義する方法です。「(i, j) の位置に x という値がある」という情報を羅列します。
  2. Compressed Sparse Column (CSC) / Row (CSR) 形式:

    • ポインタベクトル p を用いる方法です。これは内部表現に近く、メモリ効率や計算効率が高い形式です。p は、各列(または行)の非ゼロ要素が、値のベクトル x や インデックスベクトル i(または j)のどこから始まりどこで終わるかを示します。

関数 sparseMatrixの引数

library(Matrix)
args(sparseMatrix)
function (i, j, p, x, dims, dimnames, symmetric = FALSE, triangular = FALSE, 
    index1 = TRUE, repr = c("C", "R", "T"), giveCsparse, check = TRUE, 
    use.last.ij = FALSE) 
NULL
  • i:

    • 非ゼロ要素の行インデックス(行番号)を指定する整数ベクトルです。
    • p が指定されている場合、i は省略されることがあります(CSR形式の場合)。index1 = TRUE の場合は 1 から始まるインデックス、FALSE の場合は 0 から始まるインデックスとして扱われます。
  • j:

    • 非ゼロ要素の列インデックス(列番号)を指定する整数ベクトルです。
    • p が指定されている場合、通常 j は省略されます(CSC形式の場合)。sparseMatrix の内部ロジックでは、p から j(または i)を復元する処理が含まれています。
  • p:

    • 圧縮形式のためのポインタベクトルです。
    • p は常に 0 から始まり、非減少の整数ベクトルである必要があります。長さは「列数 + 1」(CSCの場合)となります。p[k] から p[k+1]-1 までの要素が、k 番目の列に属することを示します。ソースコードでは、p が与えられると diff(p) を利用して対応するインデックス列を生成しています。
  • x:

    • 非ゼロ要素のを指定するベクトルです。
    • 数値(double)、整数(integer)、論理値(logical)などが指定可能です。省略された場合、値を持たない「パターン行列」(成分が存在するか否かのみを示す行列、nMatrix)が生成されます。
  • dims:

    • 生成する行列の次元を指定する長さ2の整数ベクトル c(nrow, ncol) です。
    • 省略された場合、ij の最大値から自動的に次元が計算されます。指定する場合は、全ての非ゼロ要素が含まれる十分な大きさである必要があります。
  • dimnames:

    • 行名と列名のリスト list(row_names, col_names) です。
    • 生成される疎行列に名前を付与します。
  • symmetric:

    • 行列が対称行列であるか否かを指定する論理値です。
    • TRUE の場合、正方行列である必要があります。対称行列として格納されるため、通常は上三角または下三角の要素のみを指定すれば十分です。メモリ節約になります。
  • triangular:

    • 行列が三角行列であるか否かを指定する論理値です。
    • TRUE の場合、上三角または下三角の構造を持つ行列として作成されます。
  • index1:

    • ij1始まり(1-based indexing)か否かを指定する論理値です。
    • Rの標準は1始まりですが、C言語等のライブラリ由来のデータは0始まりの場合があります。デフォルトは TRUE(1始まり)で、内部で0始まりに変換処理が行われます。
  • repr:

    • 出力される行列の内部表現形式を指定する文字コードです。
    • "C": Compressed Sparse Column (CSC)。デフォルトであり、演算効率が良い形式です。
    • "T": Triplet (COO)。(i, j, x) の形式で保持します。
    • "R": Compressed Sparse Row (CSR)。行方向に圧縮する形式です。
  • giveCsparse:

    • 関数のマニュアルによりますと、「**deprecated**, replaced by repr」(非推奨、repr に置き換えられました)との事です。
  • check:

    • 生成されたオブジェクトの整合性チェックを行うか否かを指定する論理値です。
    • TRUE の場合、validObject(r) が呼び出されます。
  • use.last.ij:

    • 同じ (i, j) のペアが複数回現れた場合の処理方法を指定します。
    • FALSE (デフォルト): 同じ位置にある値は加算されます。
    • TRUE: データセット内で最後に現れた (i, j) の値が採用され、前の値は上書きされます。

シミュレーション用サンプルデータ

sparseMatrix を確認するために、「オンラインストアにおけるユーザーの商品購入履歴」をサンプルデータとして作成します。

  • 状況:

    • 大量のユーザーと大量の商品が存在しますが、1人のユーザーが購入する商品はごく一部です。それゆえ、このデータは典型的な疎行列となります。
  • データ構成:

    • 行 (i): ユーザーID
    • 列 (j): 商品ID
    • 値 (x): 購入個数

Rによるシミュレーションコード

サンプルデータの作成 (Coordinate List形式用)

# 設定: 5人のユーザー、4つの商品
# ユーザーID (行): 1, 2, 3, 5 (4番目のユーザーは購入なし)
# 商品ID (列): 1, 2, 3, 4
# 購入個数 (値): ランダムな整数

i_user <- c(1, 1, 2, 3, 3, 3, 5) # 行インデックス
j_item <- c(1, 2, 3, 1, 3, 4, 2) # 列インデックス
x_qty <- c(2, 5, 1, 3, 2, 1, 4) # 値 (購入数)

# 次元名の定義
user_names <- paste0("User_", 1:5)
item_names <- paste0("Item_", 1:4)

cat("--- 元データ (Coordinate形式) ---\n")
print(data.frame(User = i_user, Item = j_item, Qty = x_qty))
--- 元データ (Coordinate形式) ---
  User Item Qty
1    1    1   2
2    1    2   5
3    2    3   1
4    3    1   3
5    3    3   2
6    3    4   1
7    5    2   4

基本的な sparseMatrix の生成

# i, j, x を使用した最も標準的な生成方法
cat("--- 基本的な疎行列の生成 (dgCMatrix) ---\n")
sp_mat_basic <- Matrix::sparseMatrix(
  i = i_user,
  j = j_item,
  x = x_qty,
  dims = c(5, 4), # 次元を明示的に指定 (User 4も含むため)
  dimnames = list(user_names, item_names)
)

print(sp_mat_basic)
cat("\nクラス:", class(sp_mat_basic), "\n")
--- 基本的な疎行列の生成 (dgCMatrix) ---
5 x 4 sparse Matrix of class "dgCMatrix"
       Item_1 Item_2 Item_3 Item_4
User_1      2      5      .      .
User_2      .      .      1      .
User_3      3      .      2      1
User_4      .      .      .      .
User_5      .      4      .      .

クラス: dgCMatrix 

User_4 はデータに含まれていませんが、dims指定により行が存在し、全要素がゼロとなっています。

重複インデックスの処理 (use.last.ij の挙動)

# 同じ位置 (User_1, Item_1) に新たなデータを追加してみます
i_dup <- c(i_user, 1)
j_dup <- c(j_item, 1)
x_dup <- c(x_qty, 10) # 最後に 10 を追加

cat("--- 重複データの処理 ---\n")

# デフォルト: 加算される
cat("A) デフォルト (use.last.ij = FALSE): 値は加算されます\n")
sp_sum <- Matrix::sparseMatrix(i = i_dup, j = j_dup, x = x_dup, dims = c(5, 4))
print(sp_sum[1, 1]) # 元の2 + 追加の10 = 12 になるはず
cat("  (User_1, Item_1) の値: ", sp_sum[1, 1], "\n")

# 上書きモード
cat("B) 上書き (use.last.ij = TRUE): 最後の値が採用されます\n")
sp_last <- Matrix::sparseMatrix(i = i_dup, j = j_dup, x = x_dup, dims = c(5, 4), use.last.ij = TRUE)
print(sp_last[1, 1]) # 追加の10 になるはず
cat("  (User_1, Item_1) の値: ", sp_last[1, 1], "\n\n")
--- 重複データの処理 ---
A) デフォルト (use.last.ij = FALSE): 値は加算されます
[1] 12
  (User_1, Item_1) の値:  12 
B) 上書き (use.last.ij = TRUE): 最後の値が採用されます
[1] 10
  (User_1, Item_1) の値:  10 

対称行列 (symmetric = TRUE)

# ユーザー間の「つながり」を表す隣接行列を想定します。
# 対称行列なので、正方行列である必要があります。
cat("--- 対称行列の生成 ---\n")
i_sym <- c(1, 2)
j_sym <- c(2, 3)
x_sym <- c(1, 1)
# (1,2) と (2,3) のみ指定。symmetric=TRUEにより (2,1) と (3,2) も補完して解釈されます。

sp_sym <- Matrix::sparseMatrix(
  i = i_sym,
  j = j_sym,
  x = x_sym,
  dims = c(3, 3),
  symmetric = TRUE,
  dimnames = list(c("A", "B", "C"), c("A", "B", "C"))
)
print(sp_sym)
--- 対称行列の生成 ---
3 x 3 sparse Matrix of class "dsCMatrix"
  A B C
A . 1 .
B 1 . 1
C . 1 .

上三角成分のみの指定から、対称な下三角成分が構成されています。

ポインタベクトル p を用いた生成

# ソースコードにある通り、p が指定された場合、j (列インデックス) は不要になります。
# CSC形式では、データは「列ごと」に格納されます。
#
# 前述の sp_mat_basic と同じ行列を p を使って作ります。
# 行列の構造:
#        Item_1 Item_2 Item_3 Item_4
# User_1      2      5      .      .
# User_2      .      .      1      .
# User_3      3      .      2      1
# User_4      .      .      .      .
# User_5      .      4      .      .
#
# 列ごとの非ゼロ要素の行インデックス (0始まりに変換して考えます):
# Col 1 (Item_1): User_1(0), User_3(2) -> 値: 2, 3
# Col 2 (Item_2): User_1(0), User_5(4) -> 値: 5, 4
# Col 3 (Item_3): User_2(1), User_3(2) -> 値: 1, 2
# Col 4 (Item_4): User_3(2)            -> 値: 1
#
# ベクトル x (値) の並び順 (列優先): c(2, 3, 5, 4, 1, 2, 1)
# ベクトル i (行) の並び順 (列優先): c(0, 2, 0, 4, 1, 2, 2)  ※0-based index
#
# ベクトル p (ポインタ):
# [1] 0 (開始)
# [2] 2 (Col 1は2個要素がある。0+2=2)
# [3] 4 (Col 2は2個要素がある。2+2=4)
# [4] 6 (Col 3は2個要素がある。4+2=6)
# [5] 7 (Col 4は1個要素がある。6+1=7)
# よって p = c(0, 2, 4, 6, 7)

cat("--- ポインタベクトル p を使用した生成 (CSC形式) ---\n")

x_csc <- c(2, 3, 5, 4, 1, 2, 1) # 列優先で並べ替えた値
i_csc <- c(0, 2, 0, 4, 1, 2, 2) # 列優先で並べ替えた行番号(0-based)
p_csc <- c(0, 2, 4, 6, 7) # 各列の開始位置を示すポインタ

sp_p_based <- Matrix::sparseMatrix(
  i = i_csc,
  p = p_csc,
  x = x_csc,
  dims = c(5, 4),
  index1 = FALSE # ここではiを0始まりで用意したためFALSE
)

print(sp_p_based)
--- ポインタベクトル p を使用した生成 (CSC形式) ---
5 x 4 sparse Matrix of class "dgCMatrix"
            
[1,] 2 5 . .
[2,] . . 1 .
[3,] 3 . 2 1
[4,] . . . .
[5,] . 4 . .

i, j 形式で作成した行列と一致しています。

以上です。