在 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
。但是你必须小心不要在 id1
和 id2
中包含循环引用。否则,你会得到无穷无尽的递归:
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))
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
。但是你必须小心不要在 id1
和 id2
中包含循环引用。否则,你会得到无穷无尽的递归:
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))