【问题标题】:How to collapse session path data into from-to paths for visualizing network data?如何将会话路径数据折叠为从到路径以可视化网络数据?
【发布时间】:2015-09-29 06:44:22
【问题描述】:

有哪些方法可以转换会话路径数据,例如:

df
#   Session Link1 Link2 Link3 Link4 Link5
# 1       1     A     B                  
# 2       2     C                        
# 3       3     D     A     B            
# 4       4     C     F     G     H     J
# 5       5     A     B     C            

进入如下所示的数据集:

desired
#    Session From   To
# 1        1    A    B
# 2        2    C <NA>
# 3        3    D    A
# 4        3    A    B
# 5        4    C    F
# 6        4    F    G
# 7        4    G    H
# 8        4    H    J
# 9        5    A    B
# 10       5    B    C

再现性数据:

df <- structure(list(Session = 1:5, Link1 = structure(c(1L, 2L, 3L, 2L, 1L), .Label = c("A", "C", "D"), class = "factor"), Link2 = structure(c(3L, 1L, 2L, 4L, 3L), .Label = c("", "A", "B", "F"), class = "factor"), Link3 = structure(c(1L, 1L, 2L, 4L, 3L), .Label = c("", "B", "C", "G"), class = "factor"), Link4 = structure(c(1L, 1L, 1L, 2L, 1L), .Label = c("", "H"), class = "factor"), Link5 = structure(c(1L, 1L, 1L, 2L, 1L), .Label = c("", "J"), class = "factor")), .Names = c("Session", "Link1", "Link2", "Link3", "Link4", "Link5"), class = "data.frame", row.names = c(NA, -5L))
desired <- structure(list(Session = c(1L, 2L, 3L, 3L, 4L, 4L, 4L, 4L, 5L, 5L), From = structure(c(1L, 3L, 4L, 1L, 3L, 5L, 6L, 7L, 1L, 2L), .Label = c("A", "B", "C", "D", "F", "G", "H"), class = "factor"), To = structure(c(2L, NA, 1L, 2L, 4L, 5L, 6L, 7L, 2L, 3L), .Label = c("A", "B", "C", "F", "G", "H", "J"), class = "factor")), .Names = c("Session", "From", "To"), class = "data.frame", row.names = c(NA, -10L))

【问题讨论】:

    标签: r tidyr data-cleaning network-analysis


    【解决方案1】:

    我们可以使用data.table。将“data.frame”转换为“data.table”(setDT(df))。使用meltid.var 指定为“会话”,从“宽”格式重塑为“长”格式。删除空的“值”元素[value!='']。按“会话”分组,我们在“值”列中为那些只有一行的“会话”(if...else)插入“NA”值,通过删除创建两列(“从”和“到”)按“Session”分组的“V1”的最后一个和第一个元素。

     library(data.table)#v1.9.5+
     melt(setDT(df), id.var='Session')[value!=''][, 
       if(.N==1L) c(value, NA) else value, by = Session][,
          list(From=V1[-.N], To=V1[-1L]), by = Session]
     #   Session From To
     #1:       1    A  B
     #2:       2    C NA
     #3:       3    D  A
     #4:       3    A  B
     #5:       4    C  F
     #6:       4    F  G
     #7:       4    G  H
     #8:       4    H  J
     #9:       5    A  B
     #10:      5    B  C
    

    melt 步骤之后,上述内容可以简化为单个块。出于某种原因,tmp[-.N] 无法正常工作。所以我使用了tmp[1:(.N-1)]

    melt(setDT(df), id.var= 'Session')[value!='', {
                  tmp <- if(.N==1L) c(value, NA) else value
                  list(From= tmp[1:(.N-1)], To= tmp[-1L]) }, by = Session]
    #    Session From To
    #1:       1    A  B
    #2:       2    C NA
    #3:       3    D  A
    #4:       3    A  B
    #5:       4    C  F
    #6:       4    F  G
    #7:       4    G  H
    #8:       4    H  J
    #9:       5    A  B
    #10:      5    B  C
    

    【讨论】:

    • 这很花哨。我的解决方案还差得远。
    • @RomanLuštrik 我(可能还有其他人)也会欣赏一些不那么花哨的版本 - 请注意,我并没有放弃 @akrun 的 data.table 魔法。
    • @akrun 的答案是正确的,但我添加了另一个没有黑魔法的版本:)
    • @PierreLafortune 我不知道已经添加了 dplyr/tidyr 解决方案,因为页面没有更新。
    • 这是由 OP 添加的。我认为data.table 解决方案效果最好。尤其是规模。
    【解决方案2】:

    受@akrun 的启发,这是我个人对这个问题的尝试。当然,结果经过调整以包括每对的终端从到路径:

    library(dplyr)
    library(tidyr)
    
    gather(df, "Link_Num", "Value", -Session) %>%
      group_by(Session) %>%
      mutate(to = Value,
             from = lag(to)) %>%
      filter(Link_Num != "Link1" &
             from != "") %>%
      select(Session, from, to, Link_Num) %>%
      arrange(Session)
    

    产量:

       Session from to Link_Num
    1        1    A  B    Link2
    2        1    B       Link3
    3        2    C       Link2
    4        3    D  A    Link2
    5        3    A  B    Link3
    6        3    B       Link4
    7        4    C  F    Link2
    8        4    F  G    Link3
    9        4    G  H    Link4
    10       4    H  J    Link5
    11       5    A  B    Link2
    12       5    B  C    Link3
    13       5    C       Link4
    

    【讨论】:

      【解决方案3】:

      使用dplyr 函数meltlead 的另一种方法:

      library(dplyr)
      df$spacer <- ""
      df %>% melt(id.var = "Session") %>%
        arrange(Session) %>% 
        mutate(To = lead(value)) %>%
        filter(To !="" & value !="" | To =="" & variable =="Link1") %>%
        mutate(To = ifelse(To == "", NA, To)) %>% select(-variable)
      #    Session value   To
      # 1        1     A    B
      # 2        2     C <NA>
      # 3        3     D    A
      # 4        3     A    B
      # 5        4     C    F
      # 6        4     F    G
      # 7        4     G    H
      # 8        4     H    J
      # 9        5     A    B
      # 10       5     B    C
      

      【讨论】:

      • 我对您的解决方案有疑问。您使用的是lead 还是dplyr 的data.table?此外,看起来您正在使用 base R 方法。这可以翻译成data.table
      • 我正在使用带有dplyr 领导的基本方法。你认为最好不要混合方法?
      • 您可以提及使用的包以便更清楚。
      • @akrun 我尝试将条件放入 dplyr 管道但没有运气。我试过filter(value2 != "" &amp; value ...
      • 好的,我使用了dplyr::filter,它更好。我想知道是否有办法强制在管道中屏蔽哪种类型的过滤器?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-16
      • 1970-01-01
      • 2021-02-12
      • 2014-02-22
      • 2019-06-04
      • 1970-01-01
      相关资源
      最近更新 更多