web-dev-qa-db-ja.com

データフレームからスパース行列を作成する

Netflixの賞金データの協調フィルタリングモデルを構築しようとしている割り当てを行っています。私が使用しているデータはCSVファイルにあり、データフレームに簡単にインポートできます。次に、行としてのユーザーと列としての映画で構成されるスパースマトリックスを作成し、各セルに対応する評価値を入力します。データフレームの値をマップしようとすると、データフレームの各行に対してループを実行する必要があります。これは、Rで多くの時間がかかりますが、誰かがより良いアプローチを提案できますか。サンプルコードとデータは次のとおりです。

buildUserMovieMatrix <- function(trainingData)
{
  UIMatrix <- Matrix(0, nrow = max(trainingData$UserID), ncol = max(trainingData$MovieID), sparse = T);
  for(i in 1:nrow(trainingData))
  {
    UIMatrix[trainingData$UserID[i], trainingData$MovieID[i]] = trainingData$Rating[i];
  }
  return(UIMatrix);
}

スパース行列の作成元のデータフレーム内のデータのサンプル:

    MovieID UserID  Rating
1       1      2       3
2       2      3       3
3       2      4       4
4       2      6       3
5       2      7       3

したがって、最終的には次のようなものが必要です。列は映画IDであり、行はユーザーIDです。

    1   2   3   4   5   6   7
1   0   0   0   0   0   0   0
2   3   0   0   0   0   0   0
3   0   3   0   0   0   0   0
4   0   4   0   0   0   0   0
5   0   0   0   0   0   0   0
6   0   3   0   0   0   0   0
7   0   3   0   0   0   0   0

したがって、解釈は次のようになります。ユーザー2は映画1を3つ星と評価し、ユーザー3は映画2を3つ星と評価し、他のユーザーと映画についても同様です。私のデータフレームには約8500000行があり、コードがこのユーザーアイテムマトリックスを作成するのに約30〜45分かかります。提案があれば教えてください。

15
user37940

Matrixパッケージには、データのタイプ用に特別に作成されたコンストラクターがあります。

library(Matrix)
UIMatrix <- sparseMatrix(i = trainingData$UserID,
                         j = trainingData$MovieID,
                         x = trainingData$Rating)

それ以外の場合は、マトリックスインデックスと呼ばれる[関数の優れた機能について知りたいと思うかもしれません。あなたが試した可能性があります:

buildUserMovieMatrix <- function(trainingData) {
  UIMatrix <- Matrix(0, nrow = max(trainingData$UserID),
                        ncol = max(trainingData$MovieID), sparse = TRUE);
  UIMatrix[cbind(trainingData$UserID,
                 trainingData$MovieID)] <- trainingData$Rating;
  return(UIMatrix);
}

(ただし、これよりもsparseMatrixアプローチを強くお勧めします。)

14
flodel

これはおそらくループよりも高速です。

library(reshape2)
m <- dcast(df,UserID~MovieID,fill=0)[-1]
m
#   1 2
# 1 3 0
# 2 0 3
# 3 0 4
# 4 0 3
# 5 0 3

Data.tablesを使用すると、かなり速くなります:

library(data.table)
DT <- as.data.table(df)
m  <- dcast(DT,UserID~MovieID,fill=0)[-1]

そして、誰かが指摘すると確信しているので、代わりにこれを使用することができます

setDT(df)
m  <- dcast(df,UserID~MovieID,fill=0)[-1]

これにより、dfが(コピーを作成せずに)所定の場所にあるdata.tableに変換されます。データセットが膨大な場合、それが違いを生む可能性があります...

10
jlhoward