【问题标题】:Approximate pattern matching in a sequence of integer data and extraction using R整数数据序列中的近似模式匹配和使用 R 提取
【发布时间】:2016-03-11 14:49:23
【问题描述】:

我有一个整数模式为c(1,2,3,4,5),需要在数据中近似匹配为c(1,10,1,6,3,4,5,1,2,3,4,5,9,10,1,2,3,4,6)

我试过了:

  • pmatch()
  • all.equal()
  • grepl()

但他们似乎不支持这种情况。

pattern <- c(1,2,3,4,5)

data <- c(1,10,1,6,3,4,5,1,2,3,4,5,9,10,1,2,3,4,6)

对于上面的例子,我需要产生以下输出:

1,6,3,4,5

1,2,3,4,5

1,2,3,4,6

感谢您对此的任何想法。

谢谢

【问题讨论】:

  • 您如何获得这些输出尚不清楚。请解释您从输入到输出的过程。
  • @RichardScriven - 非常不清楚,但它似乎在集合中匹配,即 - 删除第一批最接近的匹配,然后重新开始。 1:5 匹配 1,6,3,4,5 非常接近,然后是 1,2,3,4,5,然后是 1,2,3,4,6
  • 类似这个的近似版本:stackoverflow.com/questions/33027611/…
  • 你想如何处理重叠序列,例如:c(1,2,3,4,1,2,3,4,5)

标签: r sequence matching extraction approximate


【解决方案1】:

我认为您是在说“在另一个整数序列中匹配一个整数序列,其中至少 N-1 个整数匹配”。目前还不清楚在重叠匹配的情况下应该采取什么行为,因此以下将选择重叠的序列。

# helper function to test "match" at a threshold of 4 matches
is_almost <- function(s1, s2, thresh = 4) {
   sum(s1 == s2) >= thresh }

# function to lookup and return sequences
extract_seq <- function(pattern, data) {
   res <- lapply(1:(length(data) - length(pattern) + 1), function(s) {
   subseq <- data[s:(s+length(pattern)-1)]
   if (is_almost(pattern, subseq)) { 
      subseq}
   })
   Filter(Negate(is.null),res)
}

# let's test it out
pattern <- c(1,2,3,4,5)
data <- c(1,10,1,6,3,4,5,1,2,3,4,5,9,10,1,2,3,4,6)

extract_seq(pattern,data)

[[1]]
[1] 1 6 3 4 5

[[2]]
[1] 1 2 3 4 5

[[3]]
[1] 1 2 3 4 6

【讨论】:

  • 谢谢 Gary,你提供的正是我想要的。
  • 我用大小为 50 万的数字向量(数据)尝试了 Gary 的解决方案。结果只用了 6 秒。
【解决方案2】:

如果您想在一个向量中找到与给定向量匹配的唯一元素,您可以使用%Iin% 来测试您的“模式”是否存在于较大的向量中。运算符%in% 返回一个逻辑向量。将该输出传递给which() 返回每​​个TRUE 值的索引,该索引可用于对较大的向量进行子集化,以返回与“模式”匹配的所有元素,而不管顺序如何。将子集向量传递给unique() 会消除重复项,因此较大向量中的每个元素只有一次出现,与“模式”向量的元素和长度相匹配。

例如:

> num.data <- c(1, 10, 1, 6, 3, 4, 5, 1, 2, 3, 4, 5, 9, 10, 1, 2, 3, 4, 5, 6)
> num.pattern.1 <- c(1,6,3,4,5)
> num.pattern.2 <- c(1,2,3,4,5)
> num.pattern.3 <- c(1,2,3,4,6)
> unique(num.data[which(num.data %in% num.pattern.1)])
[1] 1 6 3 4 5
> unique(num.data[which(num.data %in% num.pattern.2)])
[1] 1 3 4 5 2
> unique(num.data[which(num.data %in% num.pattern.3)])
[1] 1 6 3 4 2

请注意,第一个结果巧合地与num.pattern.1 的顺序匹配。其他两个向量与模式向量的顺序不匹配。

要在num.data 中找到与模式匹配的确切序列,您可以使用类似于以下函数的内容:

set.seed(12102015)
test.data <- sample(c(1:99), size = 500, replace = TRUE)
test.pattern.1 <- test.data[90:94]

find_vector <- function(test.data, test.pattern.1) {
   # List of all the vectors from test.data with length = length(test.pattern.1), currently empty
   lst <- vector(mode = "list")
   # List of vectors that meet condition 1, currently empty
   lst2 <- vector(mode = "list")
   # List of vectors that meet condition 2, currently empty
   lst3 <- vector(mode = "list")
   # A modifier to the iteration variable used to build 'lst'
   a <- length(test.pattern.1) - 1
   # The loop to iterate through 'test.data' testing for conditions and building lists to return a match
   for(i in 1:length(test.data)) {
     # The list is build incrementally as 'i' increases
     lst[[i]] <- test.data[c(i:(i+a))]
     # Conditon 1
     if(sum(lst[[i]] %in% test.pattern.1) == length(test.pattern.1)) {lst2[[i]] <- lst[[i]]}
     # Condition 2
     if(identical(lst[[i]], test.pattern.1)) {lst3[[i]] <- lst[[i]]}
   }
   # Remove nulls from 'lst2' and 'lst3'
   lst2 <- lst2[!sapply(lst2, is.null)]
   lst3 <- lst3[!sapply(lst3, is.null)]
# Return the intersection of 'lst2' and 'lst3' which should be a match to the pattern vector.
return(intersect(lst2, lst3))
}

为了重现性,我使用了set.seed(),然后创建了一个测试数据集和模式。函数find_vector() 有两个参数:首先,test.data 是您希望检查模式向量的较大数值向量,其次是test.pattern.1,这是您希望在test.data 中找到的较短数值向量。首先,创建三个列表:lst 保存 test.data 被划分为长度等于模式向量长度的较小向量,lst2 保存来自lst 的满足第一个条件的模式向量,以及 @ 987654339@ 保存来自lst 的满足第二个条件的向量。第一个条件测试lst 中的向量元素是否在模式向量中。第二个条件测试来自lst 的向量是否按顺序和按元素匹配模式向量。

这种方法的一个问题是,当条件不满足时,NULL 值被引入到每个列表中,但是当条件满足时进程停止。作为参考,您可以打印列表以查看所有测试的向量、满足第一个条件的向量以及满足第二个条件的向量。可以删除空值。删除空值后,找到lst2lst3 的交集将显示在test.data 中相同匹配的模式。

要使用该函数,请确保明确定义test.data &lt;- 'a numeric vector'test.pattern.1 &lt;- 'a numeric vector'。不需要特殊的包装。我没有进行任何基准测试,但该功能似乎运行得很快。我也没有寻找函数会失败的场景。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-08
    • 1970-01-01
    • 2015-10-07
    • 2011-01-14
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    • 2020-07-30
    相关资源
    最近更新 更多