聚合Tally计数器

时间:2011-02-28 14:57:55

标签: wolfram-mathematica

我很多时候发现自己用Tally[ ]计算出现次数,然后,一旦我放弃原始列表,必须添加(和加入)到该计数器列出来自另一个列表的结果。

这通常发生在我计算配置,事件,执行某些离散统计等时。

所以我为Tally聚合定义了一个非常简单但方便的函数:

aggTally[listUnTallied__List:{}, 
         listUnTallied1_List,
         listTallied_List] := 
 Join[Tally@Join[listUnTallied, listUnTallied1], listTallied] //. 
     {a___, {x_, p_}, b___, {x_, q_}, c___} -> {a, {x, p + q}, b, c};

这样

l = {x, y, z}; lt = Tally@l;
n = {x};
m = {x, y, t};

aggTally[n, {}]
  {{x, 1}}

aggTally[m, n, {}]
  {{x, 2}, {y, 1}, {t, 1}}

aggTally[m, n, lt]
  {{x, 3}, {y, 2}, {t, 1}, {z, 1}}

此功能有两个问题:

1)表现

Timing[Fold[aggTally[Range@#2, #1] &, {}, Range[100]];]
  {23.656, Null}
(* functional equivalent to *)
Timing[s = {}; j = 1; While[j < 100, s = aggTally[Range@j, s]; j++]]
  {23.047, Null}

2)它不验证最后一个参数是真实的 Tallied列表还是null(尽管对我来说不那么重要)

是否有简单,优雅,快捷和有效的解决方案? (我知道这些要求太多,但希望是免费的)

4 个答案:

答案 0 :(得分:9)

或许,这会满足您的需求吗?

aggTallyAlt[listUnTallied__List : {}, listUnTallied1_List, listTallied : {{_, _Integer} ...}] :=
{#[[1, 1]], Total@#[[All, 2]]} & /@ 
       GatherBy[Join[Tally@Join[listUnTallied, listUnTallied1], listTallied], First]

时间要好得多,并且对最后一个arg进行了基于模式的检查。

编辑:

这是一个更快的版本:

aggTallyAlt1[listUnTallied__List : {}, listUnTallied1_List, listTallied : {{_, _Integer} ...}] :=
Transpose[{#[[All, 1, 1]], Total[#[[All, All, 2]], {2}]}] &@
   GatherBy[Join[Tally@Join[listUnTallied, listUnTallied1], listTallied], First]

时间安排:

In[39]:= Timing[Fold[aggTallyAlt1[Range@#2, #1] &, {}, Range[100]];]
Timing[s = {}; j = 1; While[j < 100, s = aggTallyAlt1[Range@j, s]; j++]]

Out[39]= {0.015, Null}

Out[40]= {0.016, Null}

答案 1 :(得分:5)

以下解决方案只是对原始功能的一个小修改。它在使用Sort之前应用ReplaceRepeated,因此可以使用较不通用的替换模式,从而使其更快:

aggTally[listUnTallied__List : {}, listUnTallied1_List, 
   listTallied : {{_, _Integer} ...}] := 
  Sort[Join[Tally@Join[listUnTallied, listUnTallied1], 
     listTallied]] //. {a___, {x_, p_}, {x_, q_}, c___} -> {a, {x, p + q}, c};

答案 2 :(得分:4)

这是我提出的最快的事情,(ab)使用SowReap提供的标记:

aggTally5[untallied___List, tallied_List: {}] :=
  Last[Reap[
    Scan[((Sow[#2, #] &) @@@ Tally[#]) &, {untallied}];
    Sow[#2, #] & @@@ tallied;
    , _, {#, Total[#2]} &]]

不会赢得任何选美比赛,但这都与速度有关,对吗? =)

答案 3 :(得分:2)

如果你保持纯粹的象征意义,你可以尝试一下

(Plus @@ Times @@@ Join[#1, #2] /. Plus -> List /. Times -> List) &

用于加入计数列表。这是愚蠢的快速但返回不是计数列表的东西,所以它需要一些工作(之后它可能不会那么快;)。)。

编辑:所以我有一个工作版本:

aggT = Replace[(Plus @@ Times @@@ Join[#1, #2] 
                  /. Plus -> List 
                  /. Times[a_, b_] :> List[b, a]), 
                k_Symbol -> List[k, 1], {1}] &;

使用几个随机符号表我得到了

a := Tally@b;
b := Table[f[RandomInteger@99 + 1], {i, 100}];

Timing[Fold[aggT[#1, #2] &, a, Table[a, {i, 100}]];]
--> {0.104954, Null}

此版本仅添加计数列表,不检查任何内容,仍返回一些整数,并与Leonid的函数进行比较:

Timing[Fold[aggTallyAlt1[#2, #1] &, a, Table[b, {i, 100}]];]
--> {0.087039, Null}

已慢了几秒钟: - (。

哦,好的尝试。

相关问题