【问题标题】:Expanding all unique combinations of author-author by group, in tidyr在 tidyr 中按组扩展作者-作者的所有独特组合
【发布时间】:2018-05-19 00:53:35
【问题描述】:

我有一个数据框,其中包含来自留言板的信息。数据如下所示:

    require(dplyr)
    require(tidyr)
    df <- data.frame(author = c(2,4,8,16,32,64,128,256,512,1024),
             topic = c(101,101,101,101,301,301,501,501,501,501),
             time = c("2014-08-16 20:20:11", "2014-08-16 21:10:00", "2014-08-17 06:30:10",
                        "2014-08-17 10:08:32", "2014-08-20 22:23:01","2014-08-20 23:03:03",
                        "2014-08-25 17:05:01", "2014-08-25 19:15:10",  "2014-08-25 20:07:11",
                        "2014-08-25 23:59:59"))

我想按主题查找作者的所有独特组合。我的目标是创建一个边缘按主题和时间范围分类的无向图。我使用下面的代码来得到这个:

test <- df %>% group_by(topic) %>% expand(nesting(author), author)
print(test, n = 20)

# A tibble: 36 x 3
# Groups:   topic [3]
topic author author1
    <dbl>  <dbl>   <dbl>
 1  101.     2.      2.
 2  101.     2.      4.
 3  101.     2.      8.
 4  101.     2.     16.
 5  101.     4.      2.
 6  101.     4.      4.
 7  101.     4.      8.
 8  101.     4.     16.
 9  101.     8.      2.
10  101.     8.      4.
11  101.     8.      8.
12  101.     8.     16.
13  101.    16.      2.
14  101.    16.      4.
15  101.    16.      8.
16  101.    16.     16.
17  301.    32.     32.
18  301.    32.     64.
19  301.    64.     32.
20  301.    64.     64.

我在两件事上需要帮助:

  1. 如何删除交换的组合(例如第 2 行和第 5 行)?
  2. 对于每种组合,我都希望拥有以下属性:
    • start = 最早的主题帖子(使用 mutate,min = min(time))
    • duration of topic(上一篇关于主题的时间减去第一篇关于主题的时间,使用 mutate duration = max(time) - min(time))
    • posts 的计数(使用汇总)?

【问题讨论】:

  • 您到底想得到什么?按主题分组,然后生成每个不同的 author1-author2 组合?即使在哪里 author1==author2?
  • 我不明白第二个问题"2。对于每个组合,我想有属性...",你想生成那些新列吗?第二个(汇总)表,还是在同一个组合扩展表中?但无论如何,您应该向我们展示您的代码尝试,或者至少是输出示例。
  • 顺便说一句,没有 “交换组合” 这样的东西,它们是“排列”(因为它们依赖于顺序)。名为 expand/expand.grid... 的函数和 SQL 连接通常会为您提供排列,而不是组合。
  • 好的,你能接受一些答案吗? combn(x, m=2) 对于长度为 1000 或更长的长 x 的 big-O 运行时(/内存)性能是一个单独的问题,请询问。我怀疑限制因素是你的内存使用而不是 CPU,正如我提到的,解决方案是使用文件支持的对象,或者根据需要将你的大 groupby(datetime) 拆分成尽可能多的不相交的 datetime 块。没有理由将整个结果同时保存在内存中。但无论如何,这些都是单独的问题。
  • 至于内存使用情况,您将日期时间存储为字符串(120 字节); POSIXct 将占用大约 520 字节,POSIXlt 大约 1816 字节,但 object.size(as.integer(as.POSIXct("2014-08-16 20:20:11"))) 仅占用 48 字节(自纪元以来的秒数)。

标签: r dplyr combinations tidyr


【解决方案1】:

你不一定想使用tidyr::expand()(它似乎是左连接)来尝试生成组合,你似乎得到了所有排列 strong> 相反:特别是不需要的 self-self 组合,以及与 author1,author2 的组合交换(即排列)。同样,内置的base::expand.grid() 是排列而不是组合。

使用内置的combn()(在utils::combn())。

dplyrgroupbycombn已有很多问题,简单搜索即可找到。

一直在尝试发布工作代码,但我不太了解tidyr,我尝试的一切都不起作用或语法错误。 expand 想要一个数据框,然后它引用变量。所以%&gt;% expand(author, author) 再次为您提供所有排列,而不仅仅是组合。 %&gt;% complete(...) 似乎没用。我认为您需要 tidyr 语法才能在该分组级别在 author 上调用 combn。这可能需要是每个分组级别的嵌套子调用,无论 tidyr 的 do.call 是什么。

【讨论】:

  • 是的,我确实经历过。我会给这个狂欢!谢谢。
  • 区分排列和组合是有帮助的。我唯一的问题是 combn 是我需要放弃我的管道方法(我喜欢 tidyverse 方法)并运行一个循环来按组进行独特的组合。对于像我这样的初学者来说,combn 函数不是很直观。
  • 请记住您想要combn 而不是expand/expand.grid,请参阅stackoverflow.com/questions/42910553/… 之类的重复项以了解改进的 tidyr 方法。正如我所说,您可能必须将作者-作者组合的数据框/列表生成为嵌套子调用。
  • 另一种方法是将结果吸入 igraph 并简化无向图(删除重复边)。这是一个黑客。
  • 我的管道命令转置了它。我在 400 个讨论(主题)中有 1000 位作者的 6000 条记录。我的脚本产生了 400 个无向网络(每个主题一个)。这相当于 8000 万条边!
【解决方案2】:

最终解决方案:

time <- df %>% group_by(topic) %>% mutate(posts = n(), start = min(time), duration = (max(time) - min(time))/3600) %>% distinct(topic,start,duration)
combo <- df %>% group_by(topic) %>% do(data.frame(t(combn(.$author,2))))
edges <- right_join(combo, time)
edges

# A tibble: 13 x 5
# Groups:   topic [?]
   topic    X1    X2 start               duration         
   <dbl> <dbl> <dbl> <dttm>              <time>           
 1  101.    2.    4. 2014-08-16 20:20:11 13.8058333333333 
 2  101.    2.    8. 2014-08-16 20:20:11 13.8058333333333 
 3  101.    2.   16. 2014-08-16 20:20:11 13.8058333333333 
 4  101.    4.    8. 2014-08-16 20:20:11 13.8058333333333 
 5  101.    4.   16. 2014-08-16 20:20:11 13.8058333333333 
 6  101.    8.   16. 2014-08-16 20:20:11 13.8058333333333 
 7  301.   32.   64. 2014-08-20 22:23:01 0.667222222222222
 8  501.  128.  256. 2014-08-25 17:05:01 6.91611111111111 
 9  501.  128.  512. 2014-08-25 17:05:01 6.91611111111111 
10  501.  128. 1024. 2014-08-25 17:05:01 6.91611111111111 
11  501.  256.  512. 2014-08-25 17:05:01 6.91611111111111 
12  501.  256. 1024. 2014-08-25 17:05:01 6.91611111111111 
13  501.  512. 1024. 2014-08-25 17:05:01 6.91611111111111

【讨论】:

    【解决方案3】:

    我通过这种方式部分解决了我的问题:

    test <- df %>% group_by(topic) %>%
                mutate(posts=n(), start=min(time), duration=(max(time)-min(time))/3600) %>%
                expand(nesting(author), author, posts, start, duration) %>% filter(author != author1)
    test
    # A tibble: 36 x 6
    # Groups:   topic [3]
       topic author author1 posts start               duration
       <dbl>  <dbl>   <dbl> <int> <dttm>                 <dbl>
     2  101.     2.      4.     4 2014-08-16 20:20:11     13.8
     3  101.     2.      8.     4 2014-08-16 20:20:11     13.8
     4  101.     2.     16.     4 2014-08-16 20:20:11     13.8
     5  101.     4.      2.     4 2014-08-16 20:20:11     13.8
     7  101.     4.      8.     4 2014-08-16 20:20:11     13.8
     8  101.     4.     16.     4 2014-08-16 20:20:11     13.8
     9  101.     8.      2.     4 2014-08-16 20:20:11     13.8
    10  101.     8.      4.     4 2014-08-16 20:20:11     13.8
    # ... with 26 more rows
    

    仍然需要找出交换的组合!

    【讨论】:

      【解决方案4】:

      我发现了 iterpc 包。它速度快并且可以组合。这是我的示例代码:

      df <- data.frame(author_id = c(2,4,8,16,32,16,128,256,512,8),
                   topic_id = c(101,101,101,101,301,301,501,501,501,501),
                   time = as.POSIXct(c("2014-08-16 20:20:11", "2014-08-16 21:10:00", "2014-08-17 06:30:10",
                                       "2014-08-17 10:08:32", "2014-08-20 22:23:01","2014-08-20 23:03:03",
                                       "2014-08-25 17:05:01", "2014-08-25 19:15:10",  "2014-08-25 20:07:11",
                                       "2014-08-25 23:59:59")))
      

      首先我创建一个唯一的节点列表(图顶点)

      node <- df %>% distinct(author_id, vendor) %>% rename(id = author_id) 
      

      然后我使用 iterpc 创建我的边缘列表,如下所示:

      library(iterpc)
      edge <- df %>% group_by(topic_id) %>% do(data.frame(getall(iterpc(table(.$author_id), 2, replace =TRUE)))) %>%
       filter(X1 != X2) %>% rename(from = X1, to = X2) %>% select(to, from, topic_id)
      

      完成后我构建了我的图表:

      library(igraph)
      test_net <- graph_from_data_frame(d = edge, directed = F, vertices = node)
      plot(test_net)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-23
        相关资源
        最近更新 更多