Mathematica:列表上的条件运算

问题描述

| 我想对列中的“行”进行平均。那就是在另一列中具有相同值的行。 例如 :
e= {{1,1,2,2},{69,7,30,38,16,70,97,50,31,81,96,60,52,35,6,24,65,76,100}}
我想对第二列中所有具有相同值的第一列取平均值。 所以这里:Col 1 = 1&Col 1 = 2的平均值 然后使用此操作的结果创建第三列。因此,该列中的值对于前10行和后10行应该相同。 非常感谢您提供的任何帮助! 洛杉矶 输出理想格式:     

解决方法

有趣的问题。这是我想到的第一件事:
e[[All,{1}]] /. Reap[Sow[#2,#] & @@@ e,_,# -> Mean@#2 &][[2]];

ArrayFlatten[{{e,%}}] // TableForm
要四舍五入,您可以在上面的代码中,在
Mean
之前添加
Round@
Round@Mean@#2
这是一种稍快的方法,但是我实际上更喜欢上面的
Sow
/
Reap
#[[1,1]] -> Round@Mean@#[[All,2]] & /@ GatherBy[e,First];

ArrayFlatten[{{e,e[[All,{1}]] /. %}}] // TableForm
如果第一列中有许多不同的元素,则可以在替换(
/.
)之前,对生成的规则列表应用
Dispatch
,以加快上述两种解决方案的速度。该命令告诉Mathematica为规则列表构建并使用优化的内部格式。 这是一个变慢的变体,但无论如何我还是很喜欢分享:
Module[{q},Reap[{#,Sow[#2,#],q@#} & @@@ e,(q@# = Mean@#2) &][[1]]
]
另外,一般性提示可以替换为:
Table[RandomInteger[{1,100}],{20}]
RandomInteger[{1,100},20]
Join[{c},{d}] // Transpose
Transpose[{c,d}]
。     ,哎呀,我要参加聚会。这是我的版本:
Flatten/@Flatten[Thread/@Transpose@{#,Mean/@#[[All,All,2]]}&@GatherBy[e,First],1]
我猜应该足够快。 编辑 为了回应对@ Mr.Wizard的批评(我的第一个解决方案是重新排序列表),并且为了探讨该问题的高性能方面,这里有2个替代解决方案:
getMeans[e_] := 
Module[{temp = ConstantArray[0,Max[#[[All,1,1]]]]},temp[[#[[All,1]]]] = Mean /@ #[[All,2]];
  List /@ temp[[e[[All,1]]]]] &[GatherBy[e,First]];

getMeansSparse[e_] := 
Module[{temp = SparseArray[{Max[#[[All,1]]] -> 0}]},2]];
  List /@ Normal@temp[[e[[All,First]];
第一个是最快的,以速度为代价的内存,可以在键都是整数并且您的最大“键”值(在您的示例中为2)不太大的情况下应用。第二种解决方案不受后者的限制,但速度较慢。这是一个很大的对列表:
In[303]:= 
tst = RandomSample[#,Length[#]] &@
   Flatten[Map[Thread[{#,RandomInteger[{1,300]}] &,RandomSample[Range[1000],500]],1];

In[310]:= Length[tst]

Out[310]= 150000

In[311]:= tst[[;; 10]]

Out[311]= {{947,52},{597,81},{508,20},{891,{414,47},{849,45},{659,69},{841,29},{700,98},{858,35}}
这里的密钥可以是1到1000,其中500个,每个密钥有300个随机数。现在,一些基准:
In[314]:= (res0 = getMeans[tst]); // Timing

Out[314]= {0.109,Null}

In[317]:= (res1 = getMeansSparse[tst]); // Timing

Out[317]= {0.219,Null}

In[318]:= (res2 =  tst[[All,{1}]] /. 
 Reap[Sow[#2,#] & @@@ tst,# -> Mean@#2 &][[2]]); // Timing

Out[318]= {5.687,Null}

In[319]:= (res3 = tst[[All,{1}]] /. 
 Dispatch[
  Reap[Sow[#2,# -> Mean@#2 &][[2]]]); // Timing

Out[319]= {0.391,Null}

In[320]:= res0 === res1 === res2 === res3

Out[320]= True
我们可以看到
getMeans
是最快的,,20ѭ是第二快的,@ Mr.Wizard的解决方案稍慢一些,但是只有当我们使用
Dispatch
时,否则它要慢得多。 Mine和@ Mr.Wizard的解决方案(带有Dispatch)在本质上是相似的,速度差异是由于(稀疏)数组索引比哈希查找更有效。当然,这仅在您的列表很大时才重要。 编辑2 这是
getMeans
的版本,它使用带有C目标的
Compile
并返回数值(而不是有理数)。它比ѭ19快大约两倍,是我的解决方案中最快的。
getMeansComp = 
 Compile[{{e,_Integer,2}},Module[{keys = e[[All,1]],values = e[[All,2]],sums = {0.},lengths = {0},i = 1,means = {0.},max = 0,key = -1,len = Length[e]},max = Max[keys];
    sums = Table[0.,{max}];
    lengths = Table[0,{max}];
    means = sums;
    Do[key = keys[[i]];
      sums[[key]] += values[[i]];
      lengths[[key]]++,{i,len}];
    means = sums/(lengths + (1 - Unitize[lengths]));
    means[[keys]]],CompilationTarget -> \"C\",RuntimeOptions -> \"Speed\"]

getMeansC[e_] := List /@ getMeansComp[e];
代码“ 26”可防止未使用的键被零除。我们需要一个单独的子列表中的每个数字,因此我们应该直接叫
getMeansC
,而不是
getMeansComp
。以下是一些测量:
In[180]:= (res1 = getMeans[tst]); // Timing

Out[180]= {0.11,Null}

In[181]:= (res2 = getMeansC[tst]); // Timing

Out[181]= {0.062,Null}

In[182]:= N@res1 == res2

Out[182]= True
这可能被认为是高度优化的数值解决方案。 @ Mr.Wizard的完全通用,简短而美观的解决方案仅慢了6-8倍,这对于后者的通用简洁解决方案来说是很好的事实,因此,除非您想从中挤出每一微秒的时间,否则我\' d坚持使用@ Mr.Wizard的那个(with8ѭ)。但是了解如何优化代码以及在多大程度上可以优化代码(您能期望什么)非常重要。     ,天真的方法可能是:
Table[
  Join[ i,{Select[Mean /@ SplitBy[e,First@# == First@i &][[1,2]]}],e}] // TableForm

(*
1   59  297/5
1   72  297/5
1   90  297/5
1   63  297/5
1   77  297/5
1   98  297/5
1   3   297/5
1   99  297/5
1   28  297/5
1   5   297/5
2   87  127/2
2   80  127/2
2   29  127/2
2   70  127/2
2   83  127/2
2   75  127/2
2   68  127/2
2   65  127/2
2   1   127/2
2   77  127/2
*)
您还可以使用以下示例创建原始列表:
e = Array[{Ceiling[#/10],100}]} &,{20}]
编辑 回答@先生的评论 如果列表未按其第一个元素排序,则可以执行以下操作:
Table[Join[
  i,{Select[
     Mean /@ SplitBy[SortBy[e,e}] //TableForm
但这在您的示例中不是必需的     ,为什么不堆积呢? 我认为这是最直接/最易读的答案,尽管不一定是最快的答案。但这真是令人惊讶,您可以在Mathematica中以多种方式想到这样的问题。 正如其他人指出的那样,巫师先生显然很酷。 @Nasser,您的解决方案不会泛化为n类,尽管可以很容易地对其进行修改。
meanbygroup[table_] := Join @@ Table[
   Module[
     {sublistmean},sublistmean = Mean[sublist[[All,2]]];
     Table[Append[item,sublistmean],{item,sublist}]
   ],{sublist,GatherBy[table,#[[1]] &]}
       ]
(* On this dataset: *) 
meanbygroup[e] 
    ,哇,这里的答案太高级了,很酷,需要更多时间来学习它们。 这是我的答案,我仍然在恢复和过渡中处于矩阵/向量/ Matlab的状态,所以我的解决方案无法像此处的专家解决方案那样起作用,我将数据视为矩阵和向量(比看它们更容易作为列表等的列表...)所以在这里
sizeOfList=10; (*given from the problem,along with e vector*)
m1 = Mean[e[[1;;sizeOfList,2]]];
m2 = Mean[e[[sizeOfList+1;;2 sizeOfList,2]]];
r  = {Flatten[{a,b}],d,Flatten[{Table[m1,{sizeOfList}],Table[m2,{sizeOfList}]}]} //Transpose;

MatrixForm[r]
显然,不如功能解决方案好。 好的,我现在就去躲避功能程序员:) -纳赛尔     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...