使用两个分组名称来创建一个“组合”分组变量
给定一个data.frame:
df <- data.frame(grp1 = c(1,1,1,2,2,2,3,3,3,4,4,4), grp2 = c(1,2,3,3,4,5,6,7,8,6,9,10))
#> df
# grp1 grp2
#1 1 1
#2 1 2
#3 1 3
#4 2 3
#5 2 4
#6 2 5
#7 3 6
#8 3 7
#9 3 8
#10 4 6
#11 4 9
#12 4 10
两个colun都是分组变量,因此grp1
已知列中的所有1 都被分组在一起,依此类推,所有2都以此类推,依此类推grp2
。已知所有1相同,所有2相同。
因此,如果我们看第3行和第4行,则基于第1列,我们知道前3行可以分组在一起,而后3行可以分组在一起。然后,由于第3行和第4行共享相同的grp2
值,因此我们知道实际上所有6行都可以分组在一起。
基于相同的逻辑,我们可以看到最后六行也可以分组在一起(因为第7行和第10行共享相同的grp2
)。
除了编写一组相当for()
复杂的循环之外,还有其他更直接的方法吗?我还没想到一个呢。
我希望获得的最终输出如下所示:
# > df# grp1 grp2 combinedGrp
# 1 1 1 1
# 2 1 2 1
# 3 1 3 1
# 4 2 3 1
# 5 2 4 1
# 6 2 5 1
# 7 3 6 2
# 8 3 7 2
# 9 3 8 2
# 10 4 6 2
# 11 4 9 2
# 12 4 10 2
感谢您对本主题的任何指导!
回答:
一种实现方法是通过矩阵,该矩阵根据组成员身份定义行之间的链接。
这种方法与 的图答案有关,但是使用邻接矩阵而不是使用边来定义图。这种方法的优点是可以立即使用相同的代码处理多个>
2个分组列。(只要编写可灵活确定链接的函数即可。)一个缺点是您需要在行之间进行所有成对比较以构造矩阵,因此对于很长的向量,它可能很慢。 ,
的答案对于较长的数据或只有两列的情况会更好。
步骤是
- 根据组比较行,并将这些行定义为链接的(即,创建图形)
- 确定图1中的链接定义的图的连接组件。
您可以通过两种方法进行操作。下面我展示了一种蛮力方式,其中2a)折叠链接,直到使用矩阵乘法达到稳定的链接结构为止;
2b)使用hclust
和将链接结构转换为因子cutree
。您也可以igraph::clusters
在根据矩阵创建的图形上使用。
在行之间构造一个邻接矩阵(成对链接矩阵)(即,如果它们在同一组中,则矩阵入口为1,否则为0)。首先创建一个辅助函数,该函数确定是否链接了两行
linked_rows <- function(data){ ## helper function
## returns a _function_ to compare two rows of data
## based on group membership.
## Use Vectorize so it works even on vectors of indices
Vectorize(function(i, j) {
## numeric: 1= i and j have overlapping group membership
common <- vapply(names(data), function(name)
data[i, name] == data[j, name],
FUN.VALUE=FALSE)
as.numeric(any(common))
})
}
我用它outer
来构造一个矩阵,
rows <- 1:nrow(df)A <- outer(rows, rows, linked_rows(df))
将2度链接折叠为1度链接。也就是说,如果行是由中间节点链接而不是直接链接的,则可以通过在行之间定义链接来将它们放在同一组中。
一个迭代涉及:i)矩阵相乘以获得A的平方,以及ii)将平方矩阵中的任何非零条目设置为1(好像它是第一个度,成对链接)
## define as a function to use belowlump_links <- function(A) {
A <- A %*% A
A[A > 0] <- 1
A
}
重复此操作直到链接稳定
oldA <- 0i <- 0
while (any(oldA != A)) {
oldA <- A
A <- lump_links(A)
}
使用稳定链接结构A
定义组(图形的连接组件)。您可以通过多种方式执行此操作。
一种方法是,首先定义一个距离对象,然后使用hclust
和cutree
。如果您考虑一下,我们想将链接(A[i,j] ==
1)定义为距离0。因此,步骤如下: a) 在dist对象中将链接定义为距离0; b) 从dist对象构造一棵树; c)
将树切零。高度(即零距离):
df$combinedGrp <- cutree(hclust(as.dist(1 - A)), h = 0)df
,你可以编码步骤 - 在使用辅助功能单一lump_links
和linked_rows
:
lump <- function(df) { rows <- 1:nrow(df)
A <- outer(rows, rows, linked_rows(df))
oldA <- 0
while (any(oldA != A)) {
oldA <- A
A <- lump_links(A)
}
df$combinedGrp <- cutree(hclust(as.dist(1 - A)), h = 0)
df
}
这适用于原始版本df
,也适用于 答案中的结构
df <- data.frame(grp1 = c(1,1,1,2,2,2,3,3,3,4,4,4,5,5,6,7,8,9), grp2 = c(1,2,3,3,4,5,6,7,8,6,9,10,11,3,12,3,6,12))
lump(df)
grp1 grp2 combinedGrp
1 1 1 1
2 1 2 1
3 1 3 1
4 2 3 1
5 2 4 1
6 2 5 1
7 3 6 2
8 3 7 2
9 3 8 2
10 4 6 2
11 4 9 2
12 4 10 2
13 5 11 1
14 5 3 1
15 6 12 3
16 7 3 1
17 8 6 2
18 9 12 3
这是using的版本igraph
,它使与 的答案的连接更加清晰:
lump2 <- function(df) { rows <- 1:nrow(df)
A <- outer(rows, rows, linked_rows(df))
cluster_A <- igraph::clusters(igraph::graph.adjacency(A))
df$combinedGrp <- cluster_A$membership
df
}
以上是 使用两个分组名称来创建一个“组合”分组变量 的全部内容, 来源链接: utcz.com/qa/401204.html