radjacency-list

Divide the number into different groups according to the adjacency relationship


I have a dataframe that stores adjacency relations. I want to divide numbers into different groups according to this dataframe. The dataframe are as follows:

df = data.frame(from=c(1,1,2,2,2,3,3,3,4,4,4,5,5), to=c(1,3,2,3,4,1,2,3,2,4,5,4,5))
df
   from to
1     1  1
2     1  3
3     2  2
4     2  3
5     2  4
6     3  1
7     3  2
8     3  3
9     4  2
10    4  4
11    4  5
12    5  4
13    5  5

In above dataframe, number 1 has links with number 1 and 3, number 2 has links with number 2, 3, 4, so number 1 can not be in same group with number 3 and number 2 can not be in same group with number 3 and number 4. In the end, groups can be c(1, 2, 5) and c(3, 4).

I wonder how to program it?


Solution

  • First replace the values of to with NA when from and to are equal.

    df2 <- transform(df, to = replace(to, from == to, NA))
    

    Then recursively bind each row of the data if from of the latter row has not appeared in to of the former rows.

    Reduce(function(x, y) {
      if(y$from %in% x$to) x else rbind(x, y)
    }, split(df2, 1:nrow(df2)))
    
    #    from to
    # 1     1 NA
    # 2     1  3
    # 3     2 NA
    # 4     2  3
    # 5     2  4
    # 12    5  4
    # 13    5 NA
    

    Finally, you could extract unique elements for the both columns to get the two groups.


    The overall pipeline should be

    df |>
      transform(to = replace(to, from == to, NA)) |>
      (\(dat) split(dat, 1:nrow(dat)))() |>
      Reduce(f = \(x, y) if(y$from %in% x$to) x else rbind(x, y))