如何从 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
我的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:
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