代码之家  ›  专栏  ›  技术社区  ›  Ratnanil

通过多个部分匹配联接表

  •  -1
  • Ratnanil  · 技术社区  · 8 年前

    我有一张表描述了一条列车轨道,每条线路都是轨道的一段,其中 from to 车站以及 trackID segment -站名是完全随机的,不像这里显示的那样有结构。

    tracks <- data.frame(
      trackID = c(rep("A",4),rep("B",4)),
      segment = letters[1:8],
      from = paste0("station_1",1:8),
      to = paste0("station_2",1:8)
      )
    
    tracks 
    
      trackID segment       from         to
    1       A       a station_11 station_21
    2       A       b station_12 station_22
    3       A       c station_13 station_23
    4       A       d station_14 station_24
    5       B       e station_15 station_25
    6       B       f station_16 station_26
    7       B       g station_17 station_27
    8       B       h station_18 station_28
    

    我在这列火车上又订了一张有目击证人的桌子,我想知道发生了什么事 跟踪ID 每次目击。表格如下:

    sightings <- data.frame(from = c("station_24","station_28","station_14"),
                        to = c("station_14","station_16","station_25"))
    
    sightings 
    
            from         to
    1 station_24 station_14
    2 station_28 station_16
    3 station_14 station_25
    

    能够 收集有关 跟踪ID 来自 目击表中提供的信息。但是, sightings -表不符合 track -表: 可以在不同的部分 可以互换( - )在一些有问题的情况下, 是不同的 跟踪ID ,然后将不返回匹配项。本例所需的输出为:

            from         to trackID
    1 station_24 station_14       A
    2 station_28 station_16       B
    3 station_14 station_25    <NA> # no match since station_14 and 25 are from two different trackIDs
    

    在我看来,解决办法是 tracks 表格依据 跟踪ID 然后对字符串进行双部分匹配(使用 grepl() ?)下一行将处理崩溃,但我不知道从这里到哪里去。有人能给我指个方向吗?

    解决方案 R / dplyr 非常喜欢,但我什么都要!

    library(dplyr)
    tracks %>%
      group_by(trackID) %>%
      summarise(
        from_to = paste(paste(from,collapse = ","),paste(to,collapse = ","),sep = ",")
        )
    
    tracks
    
    trackID from_to                                                                                
      <fct>   <chr>                                                                                  
    1 A       station_11,station_12,station_13,station_14,station_21,station_22,station_23,station_24
    2 B       station_15,station_16,station_17,station_18,station_25,station_26,station_27,station_28
    

    编辑: 在我的极小例子中,我似乎过于简单化了我的问题。主要问题是车站( )在表中不是唯一的,甚至不是唯一的 跟踪ID . 只有一个 结合 属于 是唯一的 跟踪ID . 我接受了这个答案,因为它解决了上述问题,但我也将提供我自己的解决方案,同时我已经提出了。

    2 回复  |  直到 8 年前
        1
  •  1
  •   r2evans    8 年前

    双重联接可以工作。

    注意:您似乎没有使用 segment ,所以我在这里放弃它,但如果需要的话,这可能会被改编。另外,我补充道 stringsAsFactors=FALSE 到您的数据,因为另外组合了 factor S可能有问题。)

    library(dplyr)
    
    tracksmod <- bind_rows(
      select(tracks, trackID, sta=from),
      select(tracks, trackID, sta=to)
    )
    head(tracksmod)
    #   trackID        sta
    # 1       A station_11
    # 2       A station_12
    # 3       A station_13
    # 4       A station_14
    # 5       B station_15
    # 6       B station_16
    
    sightings %>%
      left_join(select(tracksmod, trackID, from=sta), by="from") %>%
      left_join(select(tracksmod, trackID2=trackID, to=sta), by="to") %>%
      mutate(trackID = if_else(trackID == trackID2, trackID, NA_character_)) %>%
      select(-trackID2)
    #         from         to trackID
    # 1 station_24 station_14       A
    # 2 station_28 station_16       B
    # 3 station_14 station_25    <NA>
    

    我不认为方向性很重要。也就是说,我不认为 from 必须始终在 列。这就是我改变信仰的原因 tracks tracksmod ,以便用ID标识一个站,而不管方向如何。

        2
  •  0
  •   Ratnanil    8 年前

    正如我在问题编辑中所说,我在最简单的例子中过于简单化了我的问题。 这里是数据的更新版本,更准确地类似于我的数据。我还添加了 stringsAsFactor = F 正如@r2evans所评论的。

    tracks <- data.frame(
      trackID = c(rep("A",4),rep("B",4)),
      segment = letters[1:8],
      from = paste0("station_1",c(1:4,1,2,5,6)),
      to = paste0("station_2",1:8),
      stringsAsFactors = F
      )
    
    sightings <- data.frame(
      from = c("station_24","station_28","station_14"),
      to = c("station_14","station_11","station_25"),
      trackID = c("A","B",NA),
      stringsAsFactors = F
    )
    

    我把这个问题解决了 tracks 表的基础 trackID 然后使用 purrr 包以嵌套方式使用循环函数。

    library(dplyr)
    
    # Collapsing the tracks-dataframe
    tracks_collapse <- tracks %>%
      group_by(trackID) %>%
      summarise(
        from_to = paste(paste(from,collapse = ","),paste(to,collapse = ","),sep = ",")
        # from = list(from),
        # to = list(to),
        # stas = list(c(from,to))
        )
    
    # a helper function to remove NAs when looking for matches
    remove_na <- function(x){x[!is.na(x)]}
    
    library(purrr)
    
    
    pmap_dfr(sightings, function(from,to,trackID){                         # pmap_dfr runs over a data.frame and returns a data.frame
      data.frame(
        from = from,                                                       # recreates the sightings data.frame
        to = to,                                                           # dito
        trackID = paste(                                                   # collapses the resulting vector
          remove_na(                                                       # removes the NA values
            pmap_chr(                                                      # matches every row from the sightings-data.frame with the tracks-data.frame
              tracks_collapse,
              function(trackID,from_to){
                ifelse(grepl(from,from_to) & grepl(to,from_to),trackID,NA) # does partial string matching and returns the trackID if both strings match
                }
              )
            ),collapse = ","
          )
        )
      }) 
    

    输出:

            from         to trackID
    1 station_24 station_14       A
    2 station_28 station_11       B
    3 station_14 station_25    <NA>
    
    推荐文章