从数据框创建稀疏矩阵

16

我正在完成一个作业,尝试为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分钟才能创建此用户项目矩阵,我希望得到任何建议。
2个回答

15

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 方法。)

稀疏矩阵的方法比第二种方法更快,谢谢。 :) - user37940

10

这可能比循环更快。

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.table,速度会快得多:很多

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。如果您的数据集非常大,那么这可能会产生影响...


1
然而,这种方法存在一个小问题,即该方法未正确映射USERIDs和MOVIEIDs,例如,训练数据中缺少USER 11,因此现在在第11行中,我有用户12的用户ID和电影ID评分,随后所有行都向上移动了1个位置。我的训练集中有10916个用户,并且我希望将它们全部保留在我的用户项目矩阵中。如果训练数据中缺少某个用户,我可以将整个行向量标记为零,这将防止训练数据框架和我的矩阵之间出现任何不匹配。您能否建议其他方法?谢谢。 - user37940

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接