【问题标题】:Simultaneous walk over vectors in R同时遍历R中的向量
【发布时间】:2019-04-09 20:02:01
【问题描述】:

我有一个时间相关变量,表示为两个向量:时间向量(已排序)和这些时间的值向量。我想在不同的排序时间向量指定的不同时间重新采样这个变量。

在另一种语言中,我会同时遍历两个排序的时间向量。即从旧时间向量的开始进行线性搜索,直到找到最接近新时间向量中第一个元素的时间,然后从旧向量中的该点继续查找最接近新向量中第二个元素的时间等。这给出了一个 O(n) 的解决方案。

这里的关键是两个时间向量的长度不同,并且元素不是一对一配对的,所以像 map2 或 walk2 这样的东西不是我想要的。

我可以使用 for 循环实现同步行走(参见下面的代码),它可以工作,但速度很慢。我还有另一个更 R 代码的解决方案,但它是 O(n^2) 所以它也很慢。有没有一种 R 方法,它使用内部 R 实现来结束 O(n) 解决方案?

或者,是否有一个 R 函数可以将我的 get_closest() 替换为二进制搜索,所以至少它会是 O(nlogn)?

根据我的搜索,我怀疑答案将是“编写一个从 R 调用的 C 函数”,但我对 R 还很陌生,所以我想检查一下我没有遗漏什么。

编辑:

我应该明确指出 new_times 中的值在 old_times 中可能不存在。我想在 old_times 中找到时间最接近 new_times 中每个条目的索引。在我的实际应用中,我将进行线性插值,但这个问题只是关于搜索最近的邻居。

library(tidyverse)

# input values given
old_times  <- c(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
old_values <- c(3, 7, 6, 7,  8,  9,  7,  6,  4,  6)
new_times  <- c(4.1, 9.6, 12.3, 17.8)

想要的输出是

new_values <- c(7, 8, 9, 4)

我的尝试

new_values <- rep(NA, length(new_times))
old_index  <- 1

for (new_index in 1:length(new_times)) {
  while (old_index < length(old_times) &&
         old_times[old_index] < new_times[new_index]) {
    old_index <- old_index + 1
  }

  # I could now do interpolation if the value of new_times is in between
  # two values in old_times.  The key is I have a correspondence that
  # new_times[new_index] is close in time to old_times[old_index].
  new_values[new_index] <- old_values[old_index]
}


# Here's an alternative way to do it that uses more R internals,
# but winds up being O(n^2).

# Get the index in old_times closest to new_time.
# This is O(n).
get_closest <- function(new_time, old_times) {
  return(which.min(abs(new_time - old_times)))
}

# Call get_closest on each element of new_times.
# This is O(n^2).
new_indices <- unlist(map(new_times, get_closest, old_times))

# Slice the list of old values to get new values.
new_values2 <- old_values[new_indices]

【问题讨论】:

    标签: r loops vector


    【解决方案1】:

    我们可以使用match

    old_values[match(new_times, old_times)]
    # [1] 7 8 9 4
    

    match(new_times, old_times) 返回“第二个参数中第一个参数的(第一个)匹配位置的向量。”,即

    # [1] 2 5 6 9
    

    我们可以使用此结果从old_values 中提取所需的值,使用[


    我们也可以使用%in%,它返回一个布尔向量

    old_values[old_times %in% new_times]
    

    感谢@Andrew

    【讨论】:

    • 好的,这看起来很有希望。如果 new_times 中的值不在 old_times 中,但我只想获取最接近的条目的索引怎么办?我在示例中忽略了这一点,以防止代码过长,但在我的实际应用程序中,它可能会要求时间 2.5 的值,我必须进行插值。
    • 作为“替代品”,old_values[old_times %in% new_times] 在后台做同样的事情。即,参见?match。我发现%in% 通常会稍微 好一点(在很多情况下并不明显)。
    • @BobSteinke 最好创建一个最小示例并显示预期输出。您可以考虑提出一个新问题。
    【解决方案2】:

    看起来最好的方法是使用data.table。我在另一个问题中发现了它:

    Find closest value in a vector with binary search

    如果 data.table 知道 search-for 和 search-in 向量都已排序,它可能会进行 O(n) 搜索而不是 O(nlogn),但 data.table 已经是在我的应用程序中非常快。

    【讨论】:

      猜你喜欢
      • 2020-08-21
      • 2013-04-07
      • 1970-01-01
      • 2022-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多