计算子字符串中字符串的下一次出现

时间:2018-11-13 11:32:06

标签: r statistics

今天,尽管我正在寻找解决方案,但我仍然面临一个无法独自解决的问题-在我看来,我的方法是错误的,还是在问类似问题之前没人问过。

我正在研究Markov归因,因此我得到的列的字符串如下所示:

A > B > B > C > B > A > C > B > A

...它是基于postgresql函数'string_agg'创建的。

我认为对我来说很重要的是分配一定数量的时间,以便每个字符串都出现在整个字符串中。为了明确起见,最终看起来像这样:

A1 > B1 > B2 > C1 > B3 > A2 > C2 > B4 > A3

存在三个主要挑战:

  • 大约有100种不同类型的元素可能会改变时间,因此很难对其进行硬编码,
  • 数据集大约有20万行,
  • 字符串最长可达几百个字符

我想到的唯一的事情就是编写某种循环,但是直到完成为止,这似乎需要花费很多时间。

我还考虑过在PostgreSQL级别上解决它,但也找不到有效且简单的解决方案。

3 个答案:

答案 0 :(得分:2)

以下是使用data.table的粗略示例:

library(data.table)

# Example data:
data <- data.table(
  s = c("A > B > B > C > B > A > C > B > A",
        "A > B > B > C > B > A > C > B > C > D")
)

# Processing steps (can probably be shortened)
n <- strsplit(data[["s"]], " > ")
datal <- melt(n)
setDT(datal)
datal[, original_order := 1:.N
      ][, temp := paste0(value, 1:.N), by = .(L1, value)
        ][order(original_order), paste(temp, collapse = " > "), by = L1]


# Output:
   L1                                              V1
1:  1      A1 > B1 > B2 > C1 > B3 > A2 > C2 > B4 > A3
2:  2 A1 > B1 > B2 > C1 > B3 > A2 > C2 > B4 > C3 > D1

答案 1 :(得分:2)

这里是仅使用基数R的函数。
请注意,如果您使用一组不同的正则表达式元字符,则使用函数参数metachar(在函数体中默认为默认值)应该很容易。

count_seq <- function(x, sep = ">"){
  metachar <- '. \ | ( ) [ { ^ $ * + ?'
  sep2 <- if(grepl(sep, metachar)) paste0("\\", sep) else sep
  y <- unlist(strsplit(x, sep2))
  y <- trimws(y)
  z <- ave(y, y, FUN = seq_along)
  paste(paste0(y, z), collapse = sep)
}

x <- "A > B > B > C > B > A > C > B > A"

count_seq(x)
#[1] "A1>B1>B2>C1>B3>A2>C2>B4>A3"
count_seq(x, sep = " > ")
#[1] "A1 > B1 > B2 > C1 > B3 > A2 > C2 > B4 > A3"

y <- "A | B | B | C | B | A | C | B | A"
count_seq(y, sep = "|")
#[1] "A1|B1|B2|C1|B3|A2|C2|B4|A3"

答案 2 :(得分:1)

gsubfn vignette中描述了如何执行此操作。首先使用那里的代码,使用方法pwordpre定义原型对象funpre初始化单词列表(存储遇到的每个单词的当前计数),fun每次遇到新单词时都会对其进行更新,并且还会在单词后缀后加上返回后缀单词的计数。

已经定义了前面的内容,使用gsubfn运行pword。对于输入gsubfn的每个组成部分,将首先运行pre,然后对于正则表达式\\w+的每个匹配项,gsubfn将匹配项输入到fun,运行fun并将匹配项替换为fun的输出。

我们假设要加一个后缀的单词由\w+匹配,这是问题示例的情况,但是如果实际数据不同,则可能需要更改模式。

library(gsubfn)
s <- rep("A > B > B > C > B > A > C > B > A", 3) # sample input

pwords <- proto(
  pre = function(this) { this$words <- list() },
  fun = function(this, x) {
    if (is.null(words[[x]])) this$words[[x]] <- 0
    this$words[[x]] <- this$words[[x]] + 1
    paste0(x, words[[x]])
  }
)

gsubfn("\\w+", pwords, s)

给予:

[1] "A1 > B1 > B2 > C1 > B3 > A2 > C2 > B4 > A3"
[2] "A1 > B1 > B2 > C1 > B3 > A2 > C2 > B4 > A3"
[3] "A1 > B1 > B2 > C1 > B3 > A2 > C2 > B4 > A3"