我有一个user_id表 - 类别对。用户可以分为多个类别。我试图为每个可能的结果计算跨类别。即属于A类和C类的用户数量等。
我的原始数据结构如下:
我希望看起来像这样的结果,显示跨类别的计数:
如何在R或MySQL中完成?数据非常大。
以下是样本数据:
data <- structure(list(category = structure(c(1L, 2L, 2L, 1L, 3L, 3L,
2L, 1L, 3L, 2L, 2L, 2L, 3L, 1L, 1L, 3L), .Label = c("A", "B",
"C"), class = "factor"), user_id = c(464L, 345L, 342L, 312L,
345L, 234L, 423L, 464L, 756L, 756L, 345L, 345L, 464L, 345L, 234L,
312L)), .Names = c("category", "user_id"), class = "data.frame", row.names = c(NA,
-16L))
任何代码片段,关于方法,功能或包装建议的想法都将受到赞赏。谢谢! -John
答案 0 :(得分:2)
在R中,我会首先通过用户分割数据,为该用户计算所有唯一的类别对然后分组在一起来实现这一点:
data$category <- as.character(data$category)
(combos <- do.call(rbind, tapply(data$category, data$user_id, function(x) {
u <- unique(x)
if (length(u) > 1) t(combn(u, 2))
else NULL
})))
# [,1] [,2]
# [1,] "C" "A"
# [2,] "A" "C"
# [3,] "B" "C"
# [4,] "B" "A"
# [5,] "C" "A"
# [6,] "A" "C"
# [7,] "C" "B"
最后一步是将对列表制表,这可以通过R中的table
函数来完成。我们实际上会使用table
两次来捕获(a,b)和(b,a )对于类别a和b的每个配对:
table(combos[,1], combos[,2]) + table(combos[,2], combos[,1])
# A B C
# A 0 1 4
# B 1 0 2
# C 4 2 0
答案 1 :(得分:1)
基于提供的示例数据,我实际上并不认为@josilber提供的R解决方案是正确的,但是由于缺少所需的示例解决方案,我可能会错。我认为您可以使用igraph
及其数据的二分网络表示来实现此目的,但这对于较大的数据/类别集可能效率低下。作为替代方案,可以使用数据的稀疏矩阵表示在R中进行相对有效的计算,如下所示:
library('Matrix')
mat <- spMatrix(nrow=length(unique(data$category)),
ncol=length(unique(data$user_id)),
i = as.numeric(factor(data$category)),
j = as.numeric(factor(data$user_id)),
x = rep(1, length(as.numeric(data$category)))
)
rownames(mat) <- levels(factor(data$category))
colnames(mat) <- levels(factor(data$user_id))
mat
#mat_row <- mat %*% t(mat)
## Based on @user20650's comment this is even more efficient than
## the multiplication above:
mat_row <- tcrossprod(mat)
我认为根据上面的示例数据得出以下正确的输出:
> mat_row
3 x 3 sparse Matrix of class "dgCMatrix"
A B C
A 7 3 5
B 3 12 4
C 5 4 5
答案 2 :(得分:0)
在MySQL中,您可以使用三列格式轻松完成此操作:
select a.category, b.category, count(*)
from pairs a join
pairs b
on a.user_id = b.user_id
group by a.category, b.category;
在SQL中生成表作为矩阵具有挑战性,除非您知道所有列名称。否则,您需要一个动态数据透视(谷歌:“mysql动态数据透视”)。对于数据库中的大多数用途,最好采用三列格式。
答案 3 :(得分:0)
您可以使用dplyr
创建所有唯一对的列表,使用crossprod
来计算一对类别共有的用户数。
> library(dplyr)
> data <- data %>% group_by(user_id, category) %>% summarize(records = sign(n()))
> crossprod(table(data$user_id, data$category))
A B C
A 4 1 4
B 1 4 2
C 4 2 5