这四种查找与谓词匹配的向量的第一个元素的方法如何比较?

How do these four methods for finding the first element of a vector that matches a predicate compare?

我发现了很多这样的方法。首先,我将设置我的数据和谓词函数:

set.seed(123)
data<-sample(66,20)
print(data)
#31 51 14  3 42 50 54 43 37 52 64 60 25 26 27  5 57 28  9 29
isFour<-function(x) x==4 #Not in our data
isFourteen<-function(x) x==14 #Element 3 of our data

我知道有四种方法可以找到与我们的谓词函数匹配的 data 的第一个元素所在的索引。以下情况都有 data,其中与 isFourteen 的唯一匹配出现。他们都是return3.

which(isFourteen(data))[1]
which.max(isFourteen(data))
match(TRUE,isFourteen(data))
Position(isFourteen,data)

当有不唯一的匹配时,它们都是return第一个匹配的索引。在这些方法中,在这种情况下唯一可以改变其行为的方法是 which(因为我们可以使用 [ 到 select 除了 1 以外的元素)和 Position(传递 right=TRUE 它将找到最后一个匹配索引而不是第一个)。

最有趣的情况是没有匹配项:

which(isFour(data))[1]
#Returns NA because we're subsetting integer(0). No argument can customize this output.
which.max(isFour(data))
#Returns 1 because the only value is FALSE. This is a dangerous answer.
match(TRUE,isFour(data))
#Returns NA, but can be customised by the nomatch argument e.g. nomatch = stop("IDIOT!")
#match() also has the incomparables argument, but I've never found a use for it.
Position(isFour,data)
#Same as match, but doesn't have an incomparables argument.

是否有任何 objective 原因 - 例如绩效、文化或安全 - 这些方法中哪一种是首选?

对于以上三个类别,我注意到以下几点:

为了避免基于意见的答案,我强烈建议任何答案都包括某种基准测试和证明他们声称使用有风险的任何功能缺乏安全性。

尽管有您的要求,但我想很多都是基于意见;尽管如此,这是我的看法。

这真的取决于用例。甚至您的问题也可能隐藏歧义;在这里我看到两个不同的任务:

  1. 找到 list 的第一个符合条件
  2. 的元素(的位置)
  3. logical 向量中找到第一个 TRUE 值(的位置)。

当然,第二个任务也解决了第一个任务,但是需要为列表的每个元素应用谓词。

很多与 R 中的矢量化有关:对于许多任务,即使“算法上”错误,评估列表中每个元素的谓词然后找到 TRUE 位置也会更方便。这当然是你的例子的情况:毫无疑问,鉴于 isFour 和另一个的定义方式 match 更喜欢:我们不介意检查 [=15 的每个元素=] 因为操作非常快,即使在结束之前可以停下来得到答案。这是因为,如果我们“去向量化”你的函数,平均而言我们会减慢很多事情,因为子集和检查单个元素要慢得多。考虑到我在这里使用的列表不是 R 含义(list 对象),而是作为值的集合。

另一方面,Position 被认为在您的数据为 list and/or 时使用 f 函数未矢量化且非常昂贵。想象一下,例如 f 包括训练机器学习模型,根据一些数据对其进行评估并获取一些性能统计数据。我们有一个我们想要训练的算法列表,我们想要在达到不错的性能时停止。在这种情况下,我们不想训练列表中的每个可能模型(超级昂贵),而是尽快停止。因此,我们将使用 Position(另请参阅其源代码以了解原因)。

关于我在开头概述的两个任务,您的所有解决方案都处理第二个任务,而只有 Position 只解决第一个任务。

所以,一般来说:

  • 如果谓词是向量化的且高效,则选择 match;
  • 如果谓词非常昂贵,请使用 Position

在任何情况下都没有理由使用其他两个解决方案:whichwhich.max 主要用于其他任务而不是确定 TRUE 值的位置(当然,即使他们可以)。

为了更好地概述 match 解决方案与 Position 解决方案之间的区别,这里是一个回顾。

  • 对于 matchisFour 函数应用于输入的 每个元素,并且仅在 [之后] match实际行动。当然,对于示例的特定任务,更好的方法是 match(4, data),因为一旦找到 4,match 就会在内部停止。但重要的一点是 isFour 应用于您实施中的整个输入。
  • 对于 Position,您传递的是函数,而不是其应用程序的结果。然后,该函数逐个元素地应用,当满足条件时退出,而不必处理整个输入。

现在应该清楚什么是首选:它取决于“去向量化”函数的成本与不处理整个输入的收益。