如何从 R 中的数据框创建不同格式的矩阵?

How to create a matrix of different format from a data frame in R?

我的data.frame如下:

group_id  user_id
1000       26
1236       29
1236       46
3767       26
3767       46
5614       29
5614       45
5614       46

我需要如下输出:

User-1   User-2  #of-common-groups
26       26       2
26       46       1
29       29       2
29       45       1
29       46       2
45       29       1
45       45       1
45       46       1
46       26       1
46       29       2    
46       45       1
46       46       3

有没有快速实现的方法?我实际上有 137 个不同的组和大约 81000 个用户。

用户26属于2个组,他也与用户46共享同一个组3767。因此

26 26 2
26 46 1
46 26 1
46 46 3  (user 46 belongs to 3 groups) etc
# your data
dat <- read.table(text="group_id  user_id
1000       26
1236       29
1236       46
3767       26
3767       46
5614       29
5614       45
5614       46", header=T)

# convert to matrix
m <- as.matrix(table(dat))

#calculate and rehape
mm <- crossprod(m,m)
r <- reshape2::melt(mm)

# remove where zero counts
r[r$value !=0 ,]
# user_id user_id value
# 1       26      26     2
# 4       46      26     1
# 6       29      29     2
# 7       45      29     1
# 8       46      29     2
# 10      29      45     1
# 11      45      45     1
# 12      46      45     1
# 13      26      46     1
# 14      29      46     2
# 15      45      46     1
# 16      46      46     3

编辑:想法来自 Network: Making Graph Object from Event-Node Data Using igraph

g <- graph.data.frame(dat, directed = FALSE)

V(g)$type <- V(g)$name %in% unique(as.character(dat$group_id))

b <- bipartite.projection(g)$proj1

ad <- get.adjacency(b, sparse=F, attr="weight")
ad <- ad[sort(colnames(ad)), sort(colnames(ad))]

diag(ad) <- colSums(table(dat))

then continue as before

怎么样:

df <- read.table(text="group_id  user_id
1000       26
1236       29
1236       46
3767       26
3767       46
5614       29
5614       45
5614       46", header=T)

df <- merge(df, df, by = "group_id")[,-1]
library(plyr)
ddply(df,.(user_id.x, user_id.y),nrow)

   user_id.x user_id.y V1
1         26        26  2
2         26        46  1
3         29        29  2
4         29        45  1
5         29        46  2
6         45        29  1
7         45        45  1
8         45        46  1
9         46        26  1
10        46        29  2
11        46        45  1
12        46        46  3

编辑: 我担心在这种情况下这太简单了,因为 merge 有 "large" 数量的用户和少量的组。当然,根据最终用途,我会考虑 user20650 已经建议的图结构,并可能保持原样。在许多情况下,可以快速查找顶点的无向加权图 (user.id) 似乎是一个很好的解决方案。

如果数据集较小(或重叠较少),我将保留此简单方法。

所以这里有两种方法,一种使用 data.table...

library(data.table)
setkey(setDT(df),group_id)
df[df,allow.cartesian=TRUE][,.N,by=list(user_id,i.user_id)][order(user_id,i.user_id)]
#     user_id i.user_id N
#  1:      26        26 2
#  2:      26        46 1
#  3:      29        29 2
#  4:      29        45 1
#  5:      29        46 2
#  6:      45        29 1
#  7:      45        45 1
#  8:      45        46 1
#  9:      46        26 1
# 10:      46        29 2
# 11:      46        45 1
# 12:      46        46 3

还有一个使用 sqldf...

library(sqldf)
sqldf("select a.user_id as user1, b.user_id as user2, count(*) as groups
      from df a inner join df b on a.group_id=b.group_id
      group by 1,2 order by 1,2")
#    user1 user2 groups
# 1     26    26      2
# 2     26    46      1
# 3     29    29      2
# 4     29    45      1
# 5     29    46      2
# 6     45    29      1
# 7     45    45      1
# 8     45    46      1
# 9     46    26      1
# 10    46    29      2
# 11    46    45      1
# 12    46    46      3

data.table 方法可能会更快,但您的数据集不是很大,因此可能不会产生太大影响。

这是使用 Matrix 包的尝试 - 只是复制来自 here:

的@nograpes 的回答
require(Matrix)
sm = sparseMatrix(dat$group_id, dat$user_id, x = TRUE)
cp = t(sm) %*% sm 
as.data.frame(summary(cp))
#     i  j x
# 1  26 26 2
# 2  46 26 1
# 3  29 29 2
# 4  45 29 1
# 5  46 29 2
# 6  29 45 1
# 7  45 45 1
# 8  46 45 1
# 9  26 46 1
# 10 29 46 2
# 11 45 46 1
# 12 46 46 3