我正在研究协同过滤问题,我在将原始数据重塑为用户评级矩阵时遇到了问题。我获得了一个评级数据库,其中包含“电影”,“用户”和“评级”列。从这个数据库中,我想获得一个大小为#users x #movies的矩阵,其中每行表示用户的评级。
这是一个最小的工作示例:
# given this:
ratingDB <- data.frame(rbind(c(1,1,1),c(1,2,NA),c(1,3,0), c(2,1,1), c(2,2,1), c(2,3,0),
c(3,1,NA), c(3,2,NA), c(3,3,1)))
names(ratingDB) <- c('user', 'movie', 'liked')
#how do I get this?
userRating <- matrix(data = rbind(c(1,NA,0), c(1,1,0), c(NA,NA,1)), nrow=3)
我可以使用两个for循环解决问题,但这当然不能很好地扩展。任何人都可以通过矢量化解决方案帮助我吗?
答案 0 :(得分:3)
这可以在没有任何循环的情况下完成。它适用于函数matrix
:
# sort the 'liked' values (this is not neccessary for the example data)
vec <- with(ratingDB, liked[order(user, movie)])
# create a matrix
matrix(vec, nrow = length(unique(ratingDB$user)), byrow = TRUE)
[,1] [,2] [,3]
[1,] 1 NA 0
[2,] 1 1 0
[3,] NA NA 1
这会将存储在ratingDB$liked
中的向量转换为矩阵。参数byrow = TRUE
允许按行排列数据(默认是按列)。
更新:如果NA
案例不在数据框中,该怎么办?
(见@steffen的评论)
首先,删除包含NA
:
subDB <- ratingDB[complete.cases(ratingDB), ]
user movie liked
1 1 1 1
3 1 3 0
4 2 1 1
5 2 2 1
6 2 3 0
9 3 3 1
可以重建完整的数据框。函数expand.grid
用于生成user
和movie
的所有组合:
full <- setNames(with(subDB, expand.grid(sort(unique(user)), sort(unique(movie)))),
c("user", "movie"))
movie user
1 1 1
2 2 1
3 3 1
4 1 2
5 2 2
6 3 2
7 1 3
8 2 3
9 3 3
现在,子数据框subDB
和完整组合数据框full
的信息可以与merge
函数结合使用:
ratingDB_2 <- merge(full, subDB, all = TRUE)
user movie liked
1 1 1 1
2 1 2 NA
3 1 3 0
4 2 1 1
5 2 2 1
6 2 3 0
7 3 1 NA
8 3 2 NA
9 3 3 1
结果与原始矩阵相同。因此,可以应用相同的过程将其转换为liked
值的矩阵:
matrix(ratingDB_2$liked, nrow = length(unique(ratingDB_2$user)), byrow = TRUE)
[,1] [,2] [,3]
[1,] 1 NA 0
[2,] 1 1 0
[3,] NA NA 1