在 R 中按顺序搜索字符串

Search string sequentially in R

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,则继续 return 102 (id1)。它将再次在 id2 中搜索 102,如果 id2 中存在 102,则继续并 return 103。该过程将继续并在 [=14= 中不存在 id1 时停止].

所以输出将是:

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

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

[[2]] 10.1.2021, 11.1.2021

您可以使用一个简单的递归函数来完成此操作,该函数针对每个条目跳转到下一个 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"

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

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)

哪个returns:

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

1) 我们假设需要的是一个额外的列,它给出一个逗号分隔的日期字符串。为此,我们在 SQL.

中形成一个递归通用 table 表达式 (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 是字符而不是数字,则第一行 select 末尾的 $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))