使用两个分组名称来创建一个“组合”分组变量

给定一个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. 根据组比较行,并将这些行定义为链接的(即,创建图形)
  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 below

lump_links <- function(A) {

A <- A %*% A

A[A > 0] <- 1

A

}

重复此操作直到链接稳定

oldA <- 0

i <- 0

while (any(oldA != A)) {

oldA <- A

A <- lump_links(A)

}

使用稳定链接结构A定义组(图形的连接组件)。您可以通过多种方式执行此操作。

一种方法是,首先定义一个距离对象,然后使用hclustcutree。如果您考虑一下,我们想将链接(A[i,j] ==

1)定义为距离0。因此,步骤如下: a) 在dist对象中将链接定义为距离0; b) 从dist对象构造一棵树; c)

将树切零。高度(即零距离):

df$combinedGrp <- cutree(hclust(as.dist(1 - A)), h = 0)

df

,你可以编码步骤 - 在使用辅助功能单一lump_linkslinked_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

回到顶部