我发现了很多这样的方法。首先,我将设置我的数据和谓词函数:
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
的唯一匹配。它们都返回3
。
which(isFourteen(data))[1]
which.max(isFourteen(data))
match(TRUE,isFourteen(data))
Position(isFourteen,data)
当有一个匹配不是唯一的时,它们都返回第一个匹配的索引。在这些方法中,在这种情况下,唯一可以改变其行为的方法是which
(因为我们可以使用[
来选择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.
是否有任何客观原因——例如性能、文化或安全——可以首选其中一种方法?
对于上面的三个类别,我注意到以下内容:
- 性能:
Position
完全用R编写,讨论中的其他函数大多用C编写 - 文化:
which.max
的文档建议使用match(TRUE,...)
方法,which
的文档建议match
是有效的(毫无疑问,which
找到了所有元素和子集,match
只找到了第一个)。这些针对match
的建议,再加上我从未见过Position
在其文档之外被提及,表明match
更为惯用 - 安全:我已经证明
which.max
有重大危险。至于其他人,which
无法保护自己免受NA
的伤害,但Position
和match
可以
为了避免基于意见的答案,我强烈建议任何答案都包括某种基准测试和证明他们声称使用有风险的任何功能缺乏安全性。
尽管有你的要求,我想很多都是基于意见的;尽管如此,以下是我的看法。
这实际上取决于用例。即使你的问题也可能隐藏着歧义;在这里我看到两个不同的任务:
- 找到符合条件的
list
的第一个元素(的位置) - 在CCD_ 26向量内找到第一个TRUE值(的位置)
当然,第二个任务也解决了第一个任务,但要为列表的每个元素应用谓词。
与R中的矢量化有很大关系:对于许多任务,即使";在算法上";错误,更方便的是评估列表中每个元素的谓词,然后找到TRUE
的位置。这当然是你的例子:毫无疑问,考虑到isFour
和其他元素的定义,match
更喜欢:我们不介意检查data
的每个元素,因为操作非常快,即使可以在结束前停下来得到答案。这是因为,如果我们";devectorize";你的函数,平均来说,我们会慢很多,因为对单个元素进行子集设置和检查要慢得多。考虑一下,我在这里使用的列表不是R的意思(list
对象),而是作为一个值的集合。
另一方面,当您的数据是list
和/或f
函数未向量化且非常昂贵时,会使用Position
。例如,想象一下f
包括训练一个机器学习模型,根据一些数据对其进行评估,并获取一些性能统计数据。我们有一个我们想要训练的算法列表,当我们达到良好的性能时,我们想要停止。在这种情况下,我们不想训练列表中的每一个可能的模型(超级昂贵),但要尽快停止。因此,我们将使用Position
(另请参阅其源代码以了解原因)。
关于我在开头概述的两个任务,您的所有解决方案都处理第二个任务,而只有Position
只解决第一个任务。
所以,总的来说:
- 如果谓词是向量化的且有效的,则使用
match
- 如果谓词非常昂贵,请使用
Position
在任何情况下都没有太多理由使用其他两种解决方案:which
和which.max
主要用于其他任务,而不是确定TRUE值的位置(当然,即使它们可以)。
为了更好地概述match
解决方案和Position
解决方案之间的差异,这里进行了回顾。
- 对于
match
,isFour
函数应用于输入的每个元素,并且只有match
之后的才实际起作用。当然,对于示例的特定任务,更好的方法是match(4, data)
,因为一旦找到4,match
就会在内部停止。但重要的一点是isFour
应用于实现中的整个输入 - 对于
Position
,您传递的是函数,而不是其应用程序的结果。然后,逐个元素应用该函数,当条件满足时,它退出,而不必处理整个输入
现在应该清楚应该选择什么:这取决于";devectorize";针对不处理整个输入的增益的函数。