我想在一列中对“行”进行平均。这是在另一列中具有相同值的行。
例如:
e= {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
{69, 7, 30, 38, 16, 70, 97, 50, 97, 31, 81, 96, 60, 52, 35, 6,
24, 65, 76, 100}}
我想平均第二列中所有在第一列中具有相同值的值。
所以这里:Col 1的平均值= 1& Col 1 = 2
然后使用此操作的结果创建第三列。因此,对于前10行和下10行,该列中的值应该相同。
非常感谢您提供的任何帮助!
LA
输出理想格式:
答案 0 :(得分:5)
有趣的问题。这是我想到的第一件事:
e[[All, {1}]] /. Reap[Sow[#2, #] & @@@ e, _, # -> Mean@#2 &][[2]];
ArrayFlatten[{{e, %}}] // TableForm
要进行四舍五入,您只需在Round@
之前的代码中添加Mean
: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}]
。
答案 1 :(得分:4)
到底是什么,我会加入聚会。这是我的版本:
Flatten/@Flatten[Thread/@Transpose@{#,Mean/@#[[All,All,2]]}&@GatherBy[e,First],1]
我猜应该足够快。
修改强>
为了回应@ Mr.Wizard的批评(我的第一个解决方案是重新排序列表),并探讨问题的高性能角落,这里有两个替代解决方案:
getMeans[e_] :=
Module[{temp = ConstantArray[0, Max[#[[All, 1, 1]]]]},
temp[[#[[All, 1, 1]]]] = Mean /@ #[[All, All, 2]];
List /@ temp[[e[[All, 1]]]]] &[GatherBy[e, First]];
getMeansSparse[e_] :=
Module[{temp = SparseArray[{Max[#[[All, 1, 1]]] -> 0}]},
temp[[#[[All, 1, 1]]]] = Mean /@ #[[All, All, 2]];
List /@ Normal@temp[[e[[All, 1]]]]] &[GatherBy[e, First]];
第一个是速度最快的交易记忆,可以在键全部为整数时应用,和你的最大“键”值(在你的例子中为2)不是太大。第二种解决方案没有后一种限制,但速度较慢。这是一个很大的对列表:
In[303]:=
tst = RandomSample[#, Length[#]] &@
Flatten[Map[Thread[{#, RandomInteger[{1, 100}, 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, 81}, {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, #] & @@@ tst, _, # -> Mean@#2 &][[2]]]); // Timing
Out[319]= {0.391, Null}
In[320]:= res0 === res1 === res2 === res3
Out[320]= True
我们可以看到getMeans
是最快的,getMeansSparse
是第二快的,@ Mr.Wizard的解决方案有点慢,但只有当我们使用Dispatch
时,否则它会慢得多。我和@ Mr.Wizard的解决方案(使用Dispatch)在精神上是相似的,速度差异是由于(稀疏)数组索引比散列查找更有效。当然,只有当你的清单真的很大时,这一切才有意义。
编辑2
这是getMeans
的一个版本,它使用带有C目标的Compile
并返回数值(而不是有理数)。它比getMeans
快两倍,是我解决方案中最快的。
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];
代码1 - Unitize[lengths]
可防止未使用的密钥除以零。我们需要单独的子列表中的每个数字,因此我们应该直接调用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倍的速度,对于后一种简洁的解决方案说得非常好,所以,除非你想要挤出每微秒,我会坚持@ Mr.Wizard的一个(Dispatch
)。但重要的是要知道如何优化代码,以及优化代码的程度(您可以期待什么)。
答案 2 :(得分:3)
一种天真的方法可能是:
Table[
Join[ i, {Select[Mean /@ SplitBy[e, First], First@# == First@i &][[1, 2]]}]
, {i, 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], RandomInteger[{1, 100}]} &, {20}]
修改强>
回答@ Mr.先生的评论
如果列表未按其第一个元素排序,您可以执行以下操作:
Table[Join[
i, {Select[
Mean /@ SplitBy[SortBy[e, First], First], First@# == First@i &][[1,2]]}],
{i, e}] //TableForm
但是在你的例子中没有必要
答案 3 :(得分:2)
为什么不坚持下去?
我认为这是最直接/易于阅读的答案,但不一定是最快的。但是,在Mathematica中你能想到多少种类似问题的方法真是太神奇了。
先生。正如其他人指出的那样,巫师显然非常酷。
@Nasser,你的解决方案并没有推广到n-class,尽管很容易修改它。
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]
答案 4 :(得分:1)
这是我的答案,我仍然是矩阵/矢量/ 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]
显然不是功能性的解决方案。
好的,我现在就去隐藏功能程序员:)
- 纳赛尔