Wolfram mathematica 计算匹配谓词的元素的最快方法

Wolfram mathematica 计算匹配谓词的元素的最快方法,wolfram-mathematica,Wolfram Mathematica,今天早些时候,我问Mathematica中是否有函数,因为我关心的是性能 我对给定谓词pred的初始方法如下: PredCount1[lst_, pred_] := Length@Select[lst, pred]; 我得到了一个建议,可以用 PredCount2[lst_, pred_] := Count[lst, x_/;pred@x]; 我开始分析这些函数,使用不同的lst大小和pred函数,并添加了另外两个定义: PredCount3[lst_, pred_] := Count[Th

今天早些时候,我问Mathematica中是否有函数,因为我关心的是性能

我对给定谓词
pred
的初始方法如下:

PredCount1[lst_, pred_] := Length@Select[lst, pred];
我得到了一个建议,可以用

PredCount2[lst_, pred_] := Count[lst, x_/;pred@x];
我开始分析这些函数,使用不同的
lst
大小和
pred
函数,并添加了另外两个定义:

PredCount3[lst_, pred_] := Count[Thread@pred@lst, True];
PredCount4[lst_, pred_] := Total[If[pred@#, 1, 0] & /@ lst];

我的数据样本范围在100万到1000万个元素之间,我的测试函数是
EvenQ
#,您可以看到自动编译的结果

首先,对于
Listable
函数,例如
EvenQ
PrimeQ
不需要使用
Thread

EvenQ[{1, 2, 3}]
这也解释了为什么
PredCount3
在这些函数上表现良好。(它们经过内部优化,可在列表上执行线程操作。)

现在让我们看看时间安排

dat = RandomInteger[1*^6, 1*^6];

test = # < 5 &;

First@Timing[#[dat, test]] & /@ {PredCount1, PredCount2, PredCount3, PredCount4}
如果我们更改系统选项以防止在
Map
中自动编译并再次运行测试:

SetSystemOptions["CompileOptions" -> {"MapCompileLength" -> Infinity}]

First@Timing[#[dat, test]] & /@ {PredCount1, PredCount2, PredCount3, PredCount4}
您可以清楚地看到,没有编译,
PredCount4
的速度要慢得多。简而言之,如果您的测试函数可以由Mathematica编译,这是一个很好的选择


列表中整数的性质会对可实现的计时产生重大影响。如果整数的范围受到限制,则使用
计数
可以提高性能

(* Count items in the list matching predicate, pred *)

PredCountID[lst_, pred_] := 
Select[Tally@lst, pred@First@# &]\[Transpose] // Last // Total

(* Define the values over which to check timings  *)
ranges = {100, 1000, 10000, 100000, 1000000};
sizes = {100, 1000, 10000, 100000, 1000000, 10000000,100000000};
对于PrimeQ,此函数提供以下计时:

表明即使在一个10^8大小的列表中,如果素数来自{0,…,100000}的整数集合,并且如果它们在一个小范围内(如1到100),则小于
计时的分辨率,则可以在不到十分之一秒的时间内计数素数


由于谓词只需应用于
计数
值集,因此这种方法对精确的谓词函数相对不敏感。

您使用的是计时[]还是绝对时间[]?请发布你的计时功能!您想对列表中包含的元素类型进行计数,实数/整数可能会有不同的执行方式。我使用//计时,列表是用Range@num,并包含整数。谢谢,这很有意义;我希望有一个简单的通用方法来做这件事,因为我肯定你同意PredCount4不是很直观。
SetSystemOptions["CompileOptions" -> {"MapCompileLength" -> Infinity}]

First@Timing[#[dat, test]] & /@ {PredCount1, PredCount2, PredCount3, PredCount4}
{0.343, 0.452, 0.234, 0.765}
(* Count items in the list matching predicate, pred *)

PredCountID[lst_, pred_] := 
Select[Tally@lst, pred@First@# &]\[Transpose] // Last // Total

(* Define the values over which to check timings  *)
ranges = {100, 1000, 10000, 100000, 1000000};
sizes = {100, 1000, 10000, 100000, 1000000, 10000000,100000000};