R语言 识别链接在一起的链接剧集组

30byixjq  于 2022-12-20  发布在  其他
关注(0)|答案(4)|浏览(159)

以这个链接ID的简单数据框架为例:

test <- data.frame(id1=c(10,10,1,1,24,8),id2=c(1,36,24,45,300,11))

> test
  id1 id2
1  10   1
2  10  36
3   1  24
4   1  45
5  24 300
6   8  11

现在我想把所有链接的id组合在一起。"链接“指的是沿着链接链走下去,这样一个组中的所有id都被标记在一起。这是一种分支结构,即:

Group 1
10 --> 1,   1 --> (24,45)
                   24 --> 300
                          300 --> NULL
                   45 --> NULL
10 --> 36, 36 --> NULL,
Final group members: 10,1,24,36,45,300

Group 2
8 --> 11
      11 --> NULL
Final group members: 8,11

现在我大概知道了我想要的逻辑,但不知道如何优雅地实现它,我正在考虑递归使用match%in%来遍历每个分支,但这次我真的被难住了。
我追求的最终结果是:

result <- data.frame(group=c(1,1,1,1,1,1,2,2),id=c(10,1,24,36,45,300,8,11))

> result
  group  id
1     1  10
2     1   1
3     1  24
4     1  36
5     1  45
6     1 300
7     2   8
8     2  11
l3zydbqr

l3zydbqr1#

Bioconductor包RBGL(BOOST图形库的R接口)包含一个函数connectedComp(),它标识图形中的连接组件--这正是您想要的。
(To使用该函数,您首先需要安装graphRBGL包,可用的有herehere。)

library(RBGL)
test <- data.frame(id1=c(10,10,1,1,24,8),id2=c(1,36,24,45,300,11))

## Convert your 'from-to' data to a 'node and edge-list' representation  
## used by the 'graph' & 'RBGL' packages 
g <- ftM2graphNEL(as.matrix(test))

## Extract the connected components
cc <- connectedComp(g)

## Massage results into the format you're after 
ld <- lapply(seq_along(cc), 
             function(i) data.frame(group = names(cc)[i], id = cc[[i]]))
do.call(rbind, ld)
#   group  id
# 1     1  10
# 2     1   1
# 3     1  24
# 4     1  36
# 5     1  45
# 6     1 300
# 7     2   8
# 8     2  11
sr4lhrrt

sr4lhrrt2#

在Josh的指点下,我找到了另一个答案,这个答案使用了igraph包,对于那些正在搜索并找到这个答案的人来说,我的test数据集在图论中被称为“边列表”或“邻接列表”(http://en.wikipedia.org/wiki/Graph_theory

library(igraph)
test <- data.frame(id1=c(10,10,1,1,24,8 ),id2=c(1,36,24,45,300,11))
gr.test <- graph_from_data_frame(test)
links <- data.frame(id=unique(unlist(test)),group=components(gr.test)$membership)
links[order(links$group),]

#   id group
#1  10     1
#2   1     1
#3  24     1
#5  36     1
#6  45     1
#7 300     1
#4   8     2
#8  11     2
7uhlpewt

7uhlpewt3#

不使用软件包:

# 2 sets of test data
mytest <- data.frame(id1=c(10,10,3,1,1,24,8,11,32,11,45),id2=c(1,36,50,24,45,300,11,8,32,12,49))
test <- data.frame(id1=c(10,10,1,1,24,8),id2=c(1,36,24,45,300,11))

grouppairs <- function(df){

  # from wide to long format; assumes df is 2 columns of related id's
  test <- data.frame(group = 1:nrow(df),val = unlist(df))

  # keep moving to next pair until all same values have same group
  i <- 0
  while(any(duplicated(unique(test)$val))){
    i <- i+1

    # get group of matching values
    matches <- test[test$val == test$val[i],'group']

    # change all groups with matching values to same group
    test[test$group %in% matches,'group'] <- test$group[i]
  }

  # renumber starting from 1 and show only unique values in group order
  test$group <- match(test$group, sort(unique(test$group)))
  unique(test)[order(unique(test)$group), ]
}

# test
grouppairs(test)
grouppairs(mytest)
nue99wik

nue99wik4#

你说递归...我想我会超级简洁,而我在它。
试验数据

mytest <- data.frame(id1=c(10,10,3,1,1,24,8,11,32,11,45),id2=c(1,36,50,24,45,300,11,8,32,12,49))
test <- data.frame(id1=c(10,10,1,1,24,8),id2=c(1,36,24,45,300,11))

用于获取分组的递归函数

aveminrec <- function(v1,v2){
  v2 <- ave(v1,by = v2,FUN = min)
  if(identical(v1,v2)){
    as.numeric(as.factor(v2))
  }else{
    aveminrec(v2,v1)
  }
}

准备数据并在

groupvalues <- function(valuepairs){
  val <- unlist(valuepairs)
  grp <- aveminrec(val,1:nrow(valuepairs))
  unique(data.frame(grp,val)[order(grp,val), ])
}

取得成果

groupvalues(test)
groupvalues(mytest)

aveminrec()可能和你想的一样,但是我打赌有一种方法可以更直接地沿着每个分支向下,而不是重复ave(),ave()本质上是split()和lapply()。也许递归地split和lapply?实际上,它就像重复的部分分支,或者交替地稍微简化2个向量,而不会丢失组信息。
也许这其中的一部分可以用在真实的问题上,但是groupvalues()太密集了,至少在没有注解的情况下无法读取。我也没有检查过与使用ave并以这种方式翻转组的for循环相比的性能。

相关问题