【问题标题】:inter-group (between groups) combination of column A grouped by column B组间(组间)A 列按 B 列分组的组合
【发布时间】:2015-10-28 02:44:47
【问题描述】:

我认为这是一个图形理论问题:我们可以在两组点之间画多少条线......我不熟悉......

例如

df = data.frame(city = c('Boston', 'Cambridge', 'Long Island', 'NYC'),
                state = c('MA', 'MA', 'NY', 'NY'))

         city state
1      Boston    MA
2   Cambridge    MA
3 Long Island    NY
4         NYC    NY

城市按州划分/分组。如何获得

Boston - Long Island
Boston - NYC
Cambridge - Long Island
Cambridge - NYC

换句话说,我想生成两个城市位于不同州的每个城市对。

一个更一般的例子:

set.seed(123)
df = data.frame(value = 1:100,
                group = letters[sample(1:26, 100, replace=T)])

> df
    value group
1       1     e
2       2     m
3       3     g
4       4     o
5       5     p
6       6     a
7       7     i
8       8     o
9       9     i
10     10     h
11     11     p
12     12     h
...    ...    ...

我想要所有组合 (value1, value2) 或等效的 (index1, index2),其中 value1 和 value2 具有不同的组标签。

【问题讨论】:

  • 你想创建一个网络?
  • 嗨,谢谢@Pascal,我不确定网络的定义,但是是的,它听起来像一个网络:与除您自己团队中的人之外的任何人进行比赛
  • 为什么蒂姆的回答消失了...:(
  • 嗨@TimBiegeleisen 好像我不...你的答案很酷 - $A$A, $A$B 的东西在这里和其他情况下也很有用。你能把它放在这里吗?你是怎么得到它的?

标签: r combinations


【解决方案1】:

扩展@mso 答案,如果您:

  1. 只想计算可能的对数
  2. a->b 与 b->a 相同(无向图)。

    > set.seed(123)
    > n<-10 # number of value
    > k<-3  # number of groups
    > df = data.frame(value = 1:n,  group = letters[sample(1:k, n, replace=T)])
    > df
       value group
    1      1     a
    2      2     c
    3      3     b
    4      4     c
    5      5     c
    6      6     a
    7      7     b
    8      8     c
    9      9     b
    10    10     b
    
    > tbl<-table(df$group) # Tabulate number within each group
    > tbl
    a b c
    2 4 4
    > sum(outer(tbl,tbl)[upper.tri(outer(tbl,tbl))]) # Count number of pairs
    [1] 32
    > sum(apply(combn(1:length(tbl),2),2,function(x) prod(tbl[x]) )) # Another way
    [1] 32
    
    >for(i in 1:n){
      tempdf = df[df$group!=df[i,2] & c(rep(F,i),rep(T,n-i)),]
      cat(df[i,1],': ',tempdf[,1], '\n')
    }
    
    1 :  2 3 4 5 7 8 9 10
    2 :  3 6 7 9 10
    3 :  4 5 6 8
    4 :  6 7 9 10
    5 :  6 7 9 10
    6 :  7 8 9 10
    7 :  8
    8 :  9 10
    9 :
    10 :
    
    >count<-0
    >for(i in 1:n){
      tempdf = df[df$group!=df[i,2] & c(rep(F,i),rep(T,n-i)),]
      if (nrow(tempdf)>0){
        for(j in 1:nrow(tempdf)){
          cat(df[i,1], tempdf[j,1], '\n')
          count<-count+1
        }
      }
    }
    
     1 2
     1 3
     1 4
     1 5
     1 7
     1 8
    ...
    
    > count
    [1] 32
    

【讨论】:

    【解决方案2】:

    尽管在 R 中不鼓励使用 For 循环,但可以使用它来获得所需的结果:

    ddf = data.frame(value = 1:20,  group = letters[sample(1:3, 20, replace=T)])
    head(ddf)
      value group
    1     1     b
    2     2     b
    3     3     b
    4     4     c
    5     5     a
    6     6     a
    
    for(i in 1:20){
        tempdf = ddf[ddf$group!=ddf[i,2],]
        cat(ddf[i,1],': ',tempdf[,1], '\n')
    }
    
    1 :  4 5 6 8 9 10 13 15 17 19 20 
    2 :  4 5 6 8 9 10 13 15 17 19 20 
    3 :  4 5 6 8 9 10 13 15 17 19 20 
    4 :  1 2 3 5 6 7 8 11 12 13 14 16 18 19 
    5 :  1 2 3 4 7 9 10 11 12 14 15 16 17 18 20 
    6 :  1 2 3 4 7 9 10 11 12 14 15 16 17 18 20 
    7 :  4 5 6 8 9 10 13 15 17 19 20 
    8 :  1 2 3 4 7 9 10 11 12 14 15 16 17 18 20 
    9 :  1 2 3 5 6 7 8 11 12 13 14 16 18 19 
    10 :  1 2 3 5 6 7 8 11 12 13 14 16 18 19 
    11 :  4 5 6 8 9 10 13 15 17 19 20 
    12 :  4 5 6 8 9 10 13 15 17 19 20 
    13 :  1 2 3 4 7 9 10 11 12 14 15 16 17 18 20 
    14 :  4 5 6 8 9 10 13 15 17 19 20 
    15 :  1 2 3 5 6 7 8 11 12 13 14 16 18 19 
    16 :  4 5 6 8 9 10 13 15 17 19 20 
    17 :  1 2 3 5 6 7 8 11 12 13 14 16 18 19 
    18 :  4 5 6 8 9 10 13 15 17 19 20 
    19 :  1 2 3 4 7 9 10 11 12 14 15 16 17 18 20 
    20 :  1 2 3 5 6 7 8 11 12 13 14 16 18 19 
    

    可以列出每一对:

    for(i in 1:20){
        tempdf = ddf[ddf$group!=ddf[i,2],]
        for(j in 1:nrow(tempdf)){
            cat(ddf[i,1], tempdf[j,1], '\n') 
        }
    }
    
    }
    1 4 
    1 5 
    1 6 
    1 8 
    1 9 
    1 10 
    1 13 
    1 15 
    1 17 
    1 19 
    1 20 
    2 4 
    2 5 
    2 6 
    2 8 
    2 9 
    2 10 
    2 13 
    2 15 
    2 17 
    ....
    

    这些对可以很容易地在另一个 data.frame 中获得。

    创建另一个data.frame:

    outdf = data.frame(first=numeric(), second=numeric())
    
    for(i in 1:20){
        tempdf = ddf[ddf$group!=ddf[i,2],]
        for(j in 1:nrow(tempdf)){
            outdf[nrow(outdf)+1,] = c(ddf[i,1], tempdf[j,1])
        }
    }
    head(outdf)
      first second
    1     1      3
    2     1      4
    3     1      5
    4     1      7
    5     1      8
    6     1      9
    

    要删除重复项,首先对每一对进行排序:

    for(i in 1:nrow(outdf)){
        if(outdf[i,2] < outdf[i,1])
            outdf[i,] = c(outdf[i,2], outdf[i,1])
    }
    outdf
    

    为了对每一行进行排序,可能首选以下 R 代码:

    outdf = data.frame(t(apply(outdf, 1, sort)))
    

    然后删除重复项:

    outdf = outdf[!duplicated(outdf),]
    

    唯一对的数量为:

    nrow(outdf)
    

    【讨论】:

    • 修改了你的答案以避免重复对:)
    【解决方案3】:

    你可以使用 cross_join

    library(dplyr)
    
    df = data.frame(city = c('Boston', 'Cambridge', 'Long Island', 'NYC'),
                    state = c('MA', 'MA', 'NY', 'NY'))
    
    prefix = function(df, prefix)
      df %>%
      setNames(names(.) %>%
                 paste(prefix, ., sep = "_") )
    
    df %>% prefix("from") %>%
      merge(df %>% prefix("to")) %>%
      filter(!(from_city == to_city & from_state == to_state))
    

    【讨论】:

    • 这不会过滤掉重复的对。例如。你的结果有NYC - Boston Boston - NYC。这不是 OP 想要的,AFAIK。
    【解决方案4】:

    对于您的问题,如果我们有 k 个包含 m1、m2、...、mk 分量的组,那么不同组之间唯一对的总数为:

    (m1*m2 + m1*m3 +...+ m1*mk)+(m2*m3+m2*m4+...+m2*mk)+...+(m(k-1)* mk)

    我有一个解决方案:

    library(data.table)
    df = data.table(city = 1:10,
    state = c(rep(1,3),rep(2,4),rep(3,3)))
    
    res=NULL
    df[,{tt=combn(.SD[,city],2)
    res<<-cbind(res,tt)},by=state]
    
    res.all <- combn(df[,city],2)
    res <- paste(res[1,],res[2,])
    res.all <- paste(res.all[1,],res.all[2,])
    res.all[!(res.all %in% res)]
    
    > df
    city state
     1:    1     1
     2:    2     1
     3:    3     1
     4:    4     2
     5:    5     2
     6:    6     2
     7:    7     2
     8:    8     3
     9:    9     3
    10:   10     3
    > as.matrix(res.all[!(res.all %in% res)])
          [,1]  
     [1,] "1 4" 
     [2,] "1 5" 
     [3,] "1 6" 
     [4,] "1 7" 
     [5,] "1 8" 
     [6,] "1 9" 
     [7,] "1 10"
     [8,] "2 4" 
     [9,] "2 5" 
    [10,] "2 6" 
    [11,] "2 7" 
    [12,] "2 8" 
    [13,] "2 9" 
    [14,] "2 10"
    [15,] "3 4" 
    [16,] "3 5" 
    [17,] "3 6" 
    [18,] "3 7" 
    [19,] "3 8" 
    [20,] "3 9" 
    [21,] "3 10"
    [22,] "4 8" 
    [23,] "4 9" 
    [24,] "4 10"
    [25,] "5 8" 
    [26,] "5 9" 
    [27,] "5 10"
    [28,] "6 8" 
    [29,] "6 9" 
    [30,] "6 10"
    [31,] "7 8" 
    [32,] "7 9"
    [33,] "7 10"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-14
      • 2021-11-24
      • 1970-01-01
      • 2011-11-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多