Prolog中的层次凝聚聚类
我试图重新熟悉Prolog,我认为这可能是Prolog中优雅解决方案的问题类型 我将遵循以下示例: 我尝试了多种数据格式:Prolog中的层次凝聚聚类,prolog,hierarchical-clustering,Prolog,Hierarchical Clustering,我试图重新熟悉Prolog,我认为这可能是Prolog中优雅解决方案的问题类型 我将遵循以下示例: 我尝试了多种数据格式: dist('BA','FI',662). dist(0,'BA','FI',662). dist(['BA'],['FI'],662). 但我还没有找到最合适的 以下是第一种格式的所有数据: %% Graph distances dist('BA','FI',662). dist('BA','MI',877). dist('BA','NA',255). dist('BA
dist('BA','FI',662).
dist(0,'BA','FI',662).
dist(['BA'],['FI'],662).
但我还没有找到最合适的
以下是第一种格式的所有数据:
%% Graph distances
dist('BA','FI',662).
dist('BA','MI',877).
dist('BA','NA',255).
dist('BA','RM',412).
dist('BA','TO',996).
dist('FI','MI',295).
dist('FI','NA',468).
dist('FI','RM',268).
dist('FI','TO',400).
dist('MI','NA',754).
dist('MI','RM',564).
dist('MI','TO',138).
dist('NA','RM',219).
dist('NA','TO',869).
dist('RM','TO',669).
现在,这个问题似乎有一些很棒的结构可以利用,但我真的很难掌握它。我想我在这里得到了第一个集群(虽然这可能不是最优雅的方式;)
mindsist(A,B,D):-dist(A,B,D),dist(X,Y,Z),A\=X,A\=Y,B\=X,B\=Y,D
我这里的问题是用集群“替换”涉及A和B的dist
语句的概念
这很快就成了我的脑筋急转弯,我被卡住了。有没有关于如何表述这一点的想法?或者这可能不是用Prolog优雅地解决的问题吗?您的表格实际上是完美的!问题是您没有中间数据结构。我猜您会发现下面的代码非常令人惊讶。在Prolog中,您可以简单地使用您想要的任何结构,它将实际工作。首先,让我们获得在不考虑参数顺序的情况下计算距离所需的初步信息:
distance(X, Y, Dist) :- dist(X, Y, Dist) ; dist(Y, X, Dist).
如果在第一次尝试时没有获得距离,那么这只是交换订单
我们需要的另一个实用程序:城市列表:
all_cities(['BA','FI','MI','NA','RM','TO']).
这很有帮助;我们可以计算它,但它看起来会很乏味和奇怪
好的,链接文章的结尾清楚地表明,实际创建的是一个树结构。这篇文章在你结束之前根本不会向你展示这棵树,所以合并中发生的事情并不明显。在Prolog中,我们可以简单地使用我们想要的结构,它就在那里,并且它会工作。为了演示,让我们用类似列表的member/2
来枚举树中的项目:
% Our clustering forms a tree. So we need to be able to do some basic
% operations on the tree, like get all of the cities in the tree. This
% predicate shows how that is done, and shows what the structure of
% the cluster is going to look like.
cluster_member(X, leaf(X)).
cluster_member(X, cluster(Left, Right)) :-
cluster_member(X, Left) ; cluster_member(X, Right).
您可以看到,我们将使用树,例如,使用leaf('FI')
来表示一个叶节点,一个N=1的簇,以及cluster(X,Y)
来表示一个具有两个分支的簇树。上面的代码允许您枚举集群中的所有城市,我们需要计算它们之间的最小距离
% To calculate the minimum distance between two cluster positions we
% need to basically pair up each city from each side of the cluster
% and find the minimum.
cluster_distance(X, Y, Distance) :-
setof(D,
XCity^YCity^(
cluster_member(XCity, X),
cluster_member(YCity, Y),
distance(XCity, YCity, D)),
[Distance|_]).
这可能看起来很奇怪。我在这里作弊。setof/3
元谓词为特定目标找到解决方案。调用模式类似于setof(模板、目标、结果)
,其中Result
将成为每个Goal
成功的Template
列表。这与bagof/3
类似,不同之处在于setof/3
提供了独特的结果。它是怎么做到的?通过分类!我的第三个参数是[Distance |!]
,表示只需给我结果列表中的第一项。由于结果已排序,因此列表中的第一项将是最小的。这是个大骗局
XCity^YCity^
符号表示setof/3
:我不在乎这些变量实际上是什么。它将它们标记为“存在变量”。这意味着Prolog不会为每个城市组合提供多个解决方案;它们将被放在一起,并被分类一次
这就是我们执行集群所需的全部
从本文中可以看出,基本情况是剩下两个集群时:只需将它们组合起来:
% OK, the base case for clustering is that we have two items left, so
% we cluster them together.
cluster([Left,Right], cluster(Left,Right)).
归纳案例获取结果列表,找到最接近的两个结果并将它们合并。坚持住
% The inductive case is: pair up each cluster and find the minimum distance.
cluster(CityClusters, FinalCityClusters) :-
CityClusters = [_,_,_|_], % ensure we have >2 clusters
setof(result(D, cluster(N1,N2), CC2),
CC1^(select(N1, CityClusters, CC1),
select(N2, CC1, CC2),
cluster_distance(N1, N2, D)),
[result(_, NewCluster, Remainder)|_]),
cluster([NewCluster|Remainder], FinalCityClusters).
Prolog的内置排序是根据第一个参数对结构进行排序。我们在这里再次作弊,创建了一个新的结构,result/3
,它将包含距离、具有该距离的集群以及要考虑的其余项目<代码>选择/3非常方便。它的工作原理是从列表中拉出一个项目,然后返回没有该项目的列表。我们在这里使用它两次,从列表中选择两个项目(我不必担心将一个地方与它本身进行比较!)。CC1被标记为自由变量。结果结构将被创建,用于考虑每个可能的集群以及我们给出的项目。同样,setof/3
将对列表进行排序以使其唯一,因此列表中的第一项恰好是距离最短的项。一次setof/3
呼叫需要做很多工作,但我喜欢作弊
最后一行说,获取新集群并将其附加到剩余的项目中,然后递归地将其转发给我们自己。调用的结果最终将是基本情况
现在它起作用了吗?让我们做一个quick-n-dirty主程序来测试它:
main :-
setof(leaf(X), (all_cities(Cities), member(X, Cities)), Basis),
cluster(Basis, Result),
write(Result), nl.
第一条线是构建初始条件(所有城市都在它们自己的一个集群中)的一种低俗方法。第二行调用谓词来对事物进行聚类。然后我们把它写出来。我们得到了什么?(输出手动缩进以确保可读性。)
顺序略有不同,但结果是一样的
如果我对使用<代码> SET/OS/<代码>(我将是)感到困惑,那么考虑使用<代码>聚合< /C>库或用简单的递归过程重写这些谓词,用手聚合并找到最小值。
你是否考虑过使用<代码> AsStudio和<代码>缩回< /代码>?main :-
setof(leaf(X), (all_cities(Cities), member(X, Cities)), Basis),
cluster(Basis, Result),
write(Result), nl.
cluster(
cluster(
leaf(FI),
cluster(
leaf(BA),
cluster(
leaf(NA),
leaf(RM)))),
cluster(
leaf(MI),
leaf(TO)))