【问题标题】:How to create vector matrix of movie ratings using R project?如何使用 R 项目创建电影评分的向量矩阵?
【发布时间】:2012-01-17 01:11:01
【问题描述】:

假设我正在使用这个电影评分数据集:http://www.grouplens.org/node/73

它包含格式为的文件中的评级 userID::movieID::rating::timestamp

鉴于此,我想在 R 项目中构建一个特征矩阵,其中每一行对应一个用户,每一列表示用户对电影的评分(如果有的话)。

例如,如果数据文件包含

1::1::1::10 2::2::2::11 1::2::3::12 2::1::5::13 3::3::4::14

那么输出矩阵将如下所示:

用户 ID、电影 1、电影 2、电影 3 1, 1, 3, 不适用 2, 5, 2, 不适用 3,北美,北美,3

那么在 R 项目中是否有一些内置的方法来实现这一点。我写了一个简单的 python 脚本来做同样的事情,但我敢打赌有更有效的方法来完成这个。

【问题讨论】:

标签: r data-mining sparse-matrix


【解决方案1】:

您可以使用reshape2 包中的dcast 函数,但生成的data.frame 可能很大(而且稀疏)。

d <- read.delim(
  "u1.base", 
  col.names = c("user", "film", "rating", "timestamp")
)
library(reshape2)
d <- dcast( d, user ~ film, value.var = "rating" )

如果您的字段用双冒号分隔,则不能使用read.delimsep 参数,它只能是一个字符。 如果您已经在 R 之外进行了一些预处理,那么在此处进行处理会更容易(例如,在 Perl 中,它只是 s/::/\t/g),但您也可以在 R 中进行:将文件作为单列读取,拆分字符串,并连接结果。

d <- read.delim("a")
d <- as.character( d[,1] )   # vector of strings
d <- strsplit( d, "::" )     # List of vectors of strings of characters
d <- lapply( d, as.numeric ) # List of vectors of numbers
d <- do.call( rbind, d )     # Matrix
d <- as.data.frame( d )
colnames( d ) <- c( "user", "movie", "rating", "timestamp" )

【讨论】:

  • 这几乎可以工作!只是一个小问题,我文件上的分隔符是双冒号“::”,但似乎 R 抱怨它们。有没有办法解决这个问题,还是我只需要在文件中执行一个简单的替换?
  • @DanQ:我已经更新了处理你文件格式的答案。
  • 由于矩阵可能非常稀疏,请查看处理备用矩阵的各种包。
  • 我构建这个矩阵的主要原因是使用 R 实现对行向量执行 k-means 聚类。
  • 但是,R 中的 AFAICT k-means 仅适用于密集矩阵。因此,您可能还需要另一个 k-means 实现。 (但无论如何,k-means 都是老废话,你可能也想在这里做球形 k-means 或其他东西)
【解决方案2】:

从上一个问题中指向的网站看来,您想代表

> print(object.size(integer(10000 * 72000)), units="Mb")
2746.6 Mb

您在another question 中引用的 8 GB 应该很“容易”。此外,总长度小于 R 中的最大向量长度,所以这也应该没问题。但是请参阅回复的结尾以了解重要警告!

我在 R 之外创建了一个以制表符分隔的数据文件版本。然后我阅读了我感兴趣的信息

what <- list(User=integer(), Film=integer(), Rating=numeric(), NULL)
x <- scan(fl, what)

“NULL”删除未使用的时间戳数据。 'User' 和 'Film' 条目不是连续的,我平台上的numeric() 占用的内存是integer() 的两倍,所以我将 User 和 Film 转换为因子,并将 Rating 转换为 integer() 通过加倍(原始分数为 1 到 5,增量为 1/2)。

x <- list(User=factor(x$User), Film=factor(x$Film),
          Rating=as.integer(2 * x$Rating))

然后我分配了矩阵

ratings <- matrix(NA_integer_ ,
                 nrow=length(levels(x$User)),
                 ncol=length(levels(x$Film)),
                 dimnames=list(levels(x$User), levels(x$Film)))

并利用两列矩阵可用于索引另一个矩阵的事实

ratings[cbind(x$User, x$Film)] <- x$Rating

这是内存使用量最大的步骤。然后我会删除不需要的变量

rm(x)

gc() 函数告诉我我使用了多少内存...

> gc()
            used   (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells    140609    7.6     407500   21.8    350000   18.7
Vcells 373177663 2847.2  450519582 3437.2 408329775 3115.4

... 3 Gb 多一点,这很好。

这样做之后,您现在会遇到严重的问题。 kmeans(来自您对较早答案的问题的回答)不适用于缺失值

> m = matrix(rnorm(100), 5)
> m[1,1]=NA
> kmeans(m, 2)
Error in do_one(nmeth) : NA/NaN/Inf in foreign function call (arg 1)

作为一个非常粗略的经验法则,我预计现成的 R 解决方案需要的内存是起始数据大小的 3-5 倍。您是否使用较小的数据集完成了分析?

【讨论】:

  • dcast 函数允许选择一个填充值(我选择了 0),以便解决缺失值。但是,您是对的,我担心向量将占用多少内存,以及在它们上执行 k-means 所需的内存......我不知道 8GB 是否足够。 (虽然我能够处理来自 grouplens 的 1M 数据集)
【解决方案3】:

很简单,您可以使用Matrix 包中的sparseMatrix 将其表示为稀疏矩阵。

只需创建一个 3 列坐标对象列表,即以 (i, j, value) 的形式,例如在名为 myDF 的 data.frame 中。然后,执行mySparseMat &lt;- sparseMatrix(i = myDF$i, j = myDF$j, x = myDF$x, dims = c(numRows, numCols) - 您需要确定行数和列数,否则将使用最大索引来确定矩阵的大小。

就是这么简单。将稀疏数据存储在密集矩阵中是不合适的,如果不是怪诞的话。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-04
    相关资源
    最近更新 更多