【问题标题】:Search string sequentially in R在R中按顺序搜索字符串
【发布时间】:2021-07-09 08:24:53
【问题描述】:
id1   id2    date

101   NA      01.1.2021     
102   101     12.1.2021
103   102     17.1.2021
104   103     18.1.2021
105   NA      25.1.2021
106   NA      03.1.2021
107   NA      10.1.2021
108   107     11.1.2021
109   NA      09.1.2021 

我在一个数据中有两个 id 变量。我需要按顺序搜索字符串。

id2 中搜索 101 (id1[1]),如果 id2 中存在 101,则继续并返回 102 (id1)。它将再次在 id2 中搜索 102,如果 id2 中存在 102,则继续并返回 103。该过程将继续并在 id1 中不存在 id2 时停止。

所以输出将是:

[[1]] 01.1.2021, 12.1.2021, 17.1.2021, 18.1.2021

同样,id 107 的第二个输出将是:

[[2]] 10.1.2021, 11.1.2021

【问题讨论】:

  • 您可以添加一个包含所需输出的表格吗?我不确定你是否在问。
  • 输出将是一个日期向量。检查输出 [[1]] 和 [[2]]
  • 您可以查看igraph::components。参见例如identify groups of linked episodes which chain together 并在其中链接。
  • 您是在寻找给定 id 返回日期字符串的函数,还是在输入中添加一列此类日期字符串,或两者兼而有之?请具体并编辑问题以澄清它的要求。

标签: r string stringr


【解决方案1】:

您可以使用一个简单的递归函数来执行此操作,该函数为每个条目跳转到下一个id2。但是你必须小心不要在id1id2 中包含循环引用。否则,你会得到无限递归:

dscan = function(df,init=101){
  ni = (1:dim(df)[1])[df$id2==init & !is.na(df$id2)][1] ## Get the next line of df that fulfills the condition that id2 is the current id1
  nv = c(df$date[df$id1==init]) ## Current date
  if(!is.na(ni)>0){
    nx = df$id1[ni[1]]          ## Next index
    return(c(nv,dscan(df,nx)))  ## Recursion step
  } else {return(c(nv))}        ## Abort recursion if there is no next ni
}

输出将是:

> dscan(df,101)
[1] "01.1.2021" "12.1.2021" "17.1.2021" "18.1.2021"
> dscan(df,107)
[1] "10.1.2021" "11.1.2021"
> dscan(df,108)
[1] "11.1.2021"

【讨论】:

    【解决方案2】:

    它并不完美,但它完成了工作:

    library(zoo)
    
    df %>%
      subset(id1 %in% id2 | id2 %in% id1) %>%
      mutate(id1 = na.locf(ifelse(is.na(id2), id1, NA))) %>%
      group_by(id1) %>%
      summarise_all(funs(toString(unique(.)))) %>%
      select(date)
    

    返回:

      date                                      
      <chr>                                     
    1 01.1.2021, 12.1.2021, 17.1.2021, 18.1.2021
    2 10.1.2021, 11.1.2021  
    

    【讨论】:

      【解决方案3】:

      1) 我们假设需要的是一个附加列,它给出了一个逗号分隔的日期字符串。为此,我们在 SQL 中形成了一个递归公用表表达式 (CTE)。

      library(sqldf)
      sqldf("with recursive R(id1, id2, date) as (
          select * from DF a where a.id1 = id1
          union all
          select a.id1, a.id2, R.date from DF a join R on a.id1 = R.id2
      )
        select a.*, group_concat(r.date) dates 
        from DF a 
        left join R on a.id1 = R.id1
        group by a.rowid")
      

      给予:

        id1 id2      date                                   dates
      1 101  NA 01.1.2021 01.1.2021,12.1.2021,17.1.2021,18.1.2021
      2 102 101 12.1.2021           12.1.2021,17.1.2021,18.1.2021
      3 103 102 17.1.2021                     17.1.2021,18.1.2021
      4 104 103 18.1.2021                               18.1.2021
      5 105  NA 25.1.2021                               25.1.2021
      6 106  NA 03.1.2021                               03.1.2021
      7 107  NA 10.1.2021                     10.1.2021,11.1.2021
      8 108 107 11.1.2021                               11.1.2021
      9 109  NA 09.1.2021                               09.1.2021
      

      2) 如果需要的是一个获取数据框和 id 并生成日期字符串的函数,则使用以下内容。 (请注意,如果 id 是字符而不是数字,则第一选择行末尾的 $id 应替换为 '$id' 。)

      library(sqldf)
      
      get_dates <- function(data, id) {
        fn$sqldf("with recursive R(id1, id2, date) as (
          select * from DF where id1 = $id
          union all
          select a.id1, a.id2, a.date from DF a join R on a.id2 = R.id1
      )
        select group_concat(date) dates from R")$dates
      }
      
      get_dates(DF, 101)
      ## [1] "01.1.2021,12.1.2021,17.1.2021,18.1.2021"
      
      get_dates(DF, 107)
      ## [1] "10.1.2021,11.1.2021"
      

      我们可以使用这个函数来生成 (1) 中的输出:

      transform(DF, dates = sapply(id1, get_dates, data = DF))
      

      注意

      DF <- structure(list(id1 = 101:109, id2 = c(NA, 101L, 102L, 103L, NA, 
      NA, NA, 107L, NA), date = c("01.1.2021", "12.1.2021", "17.1.2021", 
      "18.1.2021", "25.1.2021", "03.1.2021", "10.1.2021", "11.1.2021", 
      "09.1.2021")), class = "data.frame", row.names = c(NA, -9L))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-13
        • 1970-01-01
        • 2018-07-12
        相关资源
        最近更新 更多