List 基于Mathematica中的另一个列表值拆分列表
在Mathematica中,我有一个点坐标列表List 基于Mathematica中的另一个列表值拆分列表,list,wolfram-mathematica,List,Wolfram Mathematica,在Mathematica中,我有一个点坐标列表 size = 50; points = Table[{RandomInteger[{0, size}], RandomInteger[{0, size}]}, {i, 1, n}]; 以及这些点所属的聚类索引列表 clusterIndices = {1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1}; 根据ClusterIndications值将点拆分为两个单独列表的最简单方法
size = 50;
points = Table[{RandomInteger[{0, size}], RandomInteger[{0, size}]}, {i, 1, n}];
以及这些点所属的聚类索引列表
clusterIndices = {1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1};
根据ClusterIndications值将点拆分为两个单独列表的最简单方法是什么
编辑:
我提出的解决方案是:
pointIndices =
Map[#[[2]] &,
GatherBy[MapIndexed[{#1, #2[[1]]} &, clusterIndices], First],
{2}];
pointsByCluster = Map[Part[points, #] &, pointIndices];
有更好的方法吗?我不知道“更好”,但函数式语言中更常见的方法不是添加索引来标记每个元素(您的MapIndex),而是沿着每个列表运行:
Map[#1[[2]] &,
Sort[GatherBy[
Thread[ {#1, #2} &[clusterIndices, points]],
#1[[1]] &], #1[[1]][[1]] < #2[[1]][[1]] &], {2}]
Map[#1[[2]]和,
分类[收集][
线程[{1,{2}&[ClusterIndications,points]],
#1[[1]] &], #1[[1]][[1]] < #2[[1]][[1]] &], {2}]
大多数在Lisp/ML/etc中长大的人会立即编写线程
函数,这是实现这些语言的zip思想的方法
我添加了排序
,因为如果clusterIndicates={2[…,2],1,…}
,您的实现可能会遇到问题。另一方面,我仍然需要添加一行来解决这样一个问题,即如果clusterIndices有3但没有2,那么输出索引将是错误的。然而,从你的片段中不清楚你打算如何取回东西
我想如果你有一个爱好项目,比如用Haskell这样的语言构建一个简单的CAS,语法比Mathematica更适合函数式列表处理,你会发现列表处理会容易得多。这个怎么样
points[[
Flatten[Position[clusterIndices, #]]
]] & /@
Union[clusterIndices]
如果我想到更简单的东西,我会把它添加到帖子中
Map[#[[1]] &, GatherBy[Thread[{points, clusterIndices}], #[[2]] &], {2}]
我的第一步是执行
Transpose[{clusterIndices, points}]
我的下一步将取决于你想用它做什么<我想到了代码>选择。正如@High Performance Mark和@Nicholas Wilson所说,我将首先通过
转置
或线程
将这两个列表组合在一起。在这种情况下,
In[1]:= Transpose[{clusterIndices, points}]==Thread[{clusterIndices, points}]
Out[1]:= True
在某一点上,我看了看哪个更快,我认为线程
稍微快一点。但是,只有当您使用很长的列表时,它才真正重要
@高性能标记在建议选择
方面非常重要。但是,它只允许您一次拉出一个集群。选择群集1的代码如下所示:
Select[Transpose[{clusterIndices, points}], #[[1]]==1& ][[All, All, 2]]
SelectEquivalents[x_List,f_:Identity, g_:Identity, h_:(#2&)]:=
Reap[Sow[g[#],{f[#]}]&/@x, _, h][[2]];
由于您似乎希望生成所有集群,我建议您执行以下操作:
GatherBy[Transpose[{clusterIndices, points}], #[[1]]& ][[All, All, 2]]
它的优点是只包含一行,唯一棘手的部分是选择结果列表中正确的部分。确定需要多少个所有术语的诀窍是注意
Transpose[{clusterIndices, points}][[All,2]]
需要将点从转置列表中恢复。但是,“集群”列表有一个附加级别,因此第二个All
需要注意的是,GatherBy
中的第二个参数是一个接受一个参数的函数,它可以与您希望使用的任何函数互换。因此,它非常有用。但是,如果您想在收集数据时转换数据,我会查看eaw
和Sow
编辑:收获
和播种
使用不足,功能相当强大。它们的使用有些混乱,但我怀疑GatherBy
是在内部使用它们实现的。比如说,
Reap[ Sow[#[[2]], #[[1]] ]& /@ Transpose[{clusterIndices, points}], _, #2& ]
执行与我以前的代码相同的操作,而无需从点中剥离索引。本质上,Sow
用索引标记每个点,然后Reap收集所有标记(\uu
用于第二个参数)并仅输出点。就我个人而言,我使用它而不是GathereBy,并将其编码到一个我加载的函数中,如下所示:
Select[Transpose[{clusterIndices, points}], #[[1]]==1& ][[All, All, 2]]
SelectEquivalents[x_List,f_:Identity, g_:Identity, h_:(#2&)]:=
Reap[Sow[g[#],{f[#]}]&/@x, _, h][[2]];
注意:此代码是5.x中帮助文件的修改形式。但是,6.0和7.0帮助文件删除了许多有用的示例,这就是其中之一。使用7.0版中新的SplitBy
函数,可以用一种简洁的方法来实现这一点,它应该非常快:
SplitBy[Transpose[{points, clusterIndices}], Last][[All, All, 1]]
如果您不使用7.0,可以通过以下方式实现:
Split[Transpose[{points, clusterIndices}], Last[#]==Last[#2]& ][[All, All, 1]]
更新
抱歉,我没有看到您只需要两个组,我认为这是集群,而不是拆分。下面是一些代码:
FindClusters[Thread[Rule[clusterIndices, points]]]
有意思,你怎么会想到这个?不知道。我经常使用这种东西(定位列表来提取我想要的东西)。这与其他人的建议非常不同。Thank我怀疑排序(隐含在联合中)和列表遍历的次数(通过定位和部分)会导致效率相当低。然而,对于一个简短的列表,它肯定是一个有趣的使用位置。您将两个列表组合的部分可以简化为线程[{clusterIndicates,points}]
,因为纯函数部分({1,{2}
)在这种情况下只是浪费了按键。+1这是一个比@Mark Fisher更好的答案,还有其他几个。我也会加入@Michael Pilat关于SplitBy的建议。非常详细的解释。谢谢@麦克斯:不客气。eaw
和Sow
的另一个优点是,您可以Sow
多个标记,即,如果您的数据适合多个类别,您可以将数据分组。要执行此操作,请在SelectEquivalents
中删除f
周围的花括号,并让f
返回数据所属标记的列表。对于否决此操作的人,为什么?让对方知道答案是什么,这是一种常见的礼貌。有人会承认这一点吗?在7.0中添加了很多列表实用程序,比如这一个,由于我对eaw
和Sow
的依赖,我从未使用过。但是,这是一个很好的方法,我必须记住。起初我试着自己使用Split,但这不起作用。尝试执行SplitBy[{1,1,1,2,2,1,1,2,2}],您将得到{1,1,1},{2,2},{1,1},{2,2}和len