聚类算法中基于链接的算法大致有三种:单链接算法(single link),平均链接算法(average link),最小生成数算法(minimum spanning tree)。现在实现单链接算法,其他算法以后再续吧。
单链接算法的过程是 首先生成各个元素的距离矩阵,根据距离和阀值的比对来控制生成的聚类个数,阀值越大,生成的聚类越少,直到同属一类。
下面例子实现了根据经纬度来实现城市的聚类。
001 package singlelink;
002
003 import java.util.ArrayList;
004 import java.util.HashSet;
005 import java.util.List;
006 import java.util.Set;
007
008 public class SingleLinkTest {
009
010 public static void main(String[] args) {
011
012 List<City> citys = new ArrayList<City>();
013
014 City city0 = new City();
015 city0.setName("北 京");
016 city0.setX(116.28);
017 city0.setY(39.54);
018 citys.add(city0);
019
020
021 City city1 = new City();
022 city1.setName("上 海");
023 city1.setX(121.29);
024 city1.setY(31.14);
025 citys.add(city1);
026
027 City city2 = new City();
028 city2.setName("天 津");
029 city2.setX(117.11);
030 city2.setY(39.09);
031 citys.add(city2);
032
033 City city3 = new City();
034 city3.setName("重 庆");
035 city3.setX(106.32);
036 city3.setY(29.32);
037 citys.add(city3);
038
039
040 City city4 = new City();
041 city4.setName("哈尔滨");
042 city4.setX(126.41);
043 city4.setY(45.45);
044 citys.add(city4);
045
046
047 City city5 = new City();
048 city5.setName("长 春");
049 city5.setX(125.19);
050 city5.setY(43.52);
051 citys.add(city5);
052
053
054 City city6 = new City();
055 city6.setName("南 京");
056 city6.setX(118.50);
057 city6.setY(32.02);
058 citys.add(city6);
059
060 City city7 = new City();
061 city7.setName("武 汉");
062 city7.setX(114.21);
063 city7.setY(30.37);
064 citys.add(city7);
065
066
067 City city8 = new City();
068 city8.setName("台 北");
069 city8.setX(121.31);
070 city8.setY(25.03);
071 citys.add(city8);
072
073 City city9 = new City();
074 city9.setName("香 港");
075 city9.setX(114.10);
076 city9.setY(22.18);
077 citys.add(city9);
078
079 SingleLink sing = new SingleLink(citys);
080 List<Set<City>> list = sing.compute();
081 for (Set<City> list0 : list) {
082 System.out.println("=============");
083 for (City city : list0) {
084 System.out.println(city.getName() + " : (" + city.getX()+","+city.getY()+")");
085 }
086 }
087 }
088
089 }
090
091 /**
092 * 聚类之 单链接算法
093 *
094 * <a href="http://my.oschina.net/arthor" target="_blank" rel="nofollow">@author</a> duyf
095 *
096 */
097 class SingleLink {
098
099 private List<City> data;
100
101 // 默认阀值
102 private double distanceX = 8;
103
104 public SingleLink(List<City> list) {
105 data = list;
106 }
107
108 public List<Set<City>> compute() {
109 List<Set<City>> list = new ArrayList<Set<City>>();
110
111 // 距离矩阵
112 double[][] ds = new double[data.size()][data.size()];
113
114 for (int i = 0; i < data.size(); i++) {
115 City city1 = data.get(i);
116 for (int j = i + 1; j < data.size(); j++) {
117 City city2 = data.get(j);
118 ds[i][j] = getDistance(city1, city2);
119 // 矩阵 对称性
120 ds[j][i] = ds[i][j];
121 }
122 ds[i][i] = 0.0;
123 }
124
125 for (int i = 0; i < ds.length; i++) {
126 for (int j = 0; j < ds.length; j++) {
127 System.out.print((int) ds[i][j] + ",");
128 }
129 System.out.println();
130 }
131
132 boolean[] hasUsed = new boolean[ds.length];
133 for (int i = 0; i < ds.length; i++) {
134 Set<City> setDs = new HashSet<City>();
135 if (hasUsed[i]) {
136 continue;
137 }
138 for (int j = i; j < ds.length; j++) {
139 if (ds[i][j] <= distanceX && hasUsed[j]==false) {
140 setDs.add(data.get(j));
141 hasUsed[j] = true;
142 }
143 }
144 if (setDs.size() > 0) {
145 list.add(setDs);
146 }
147
148 }
149 return list;
150 }
151
152 // 计算空间距离
153 private double getDistance(City city1, City city2) {
154 double distance=Math.pow(city1.getX()-city2.getX(),2)+Math.pow(city1.getY()-city2.getY(),2);
155 return Math.sqrt(distance);
156
157 }
158
159 }
160
161 /**
162 * 城市
163 *
164 * <a href="http://my.oschina.net/arthor" target="_blank" rel="nofollow">@author</a> duyf
165 *
166 */
167 class City {
168
169 private String name;
170 // 经度
171 private double x;
172
173 // 纬度
174 private double y;
175
176 public double getX() {
177 return x;
178 }
179
180 public void setX(double x) {
181 this.x = x;
182 }
183
184 public double getY() {
185 return y;
186 }
187
188 public void setY(double y) {
189 this.y = y;
190 }
191
192 public String getName() {
193 return name;
194 }
195
196 public void setName(String name) {
197 this.name = name;
198 }
199
200 public boolean equals(Object obj) {
201 if (obj == null) {
202 return false;
203 }
204 if (this == obj) {
205 return true;
206 }
207 City other = (City) obj;
208 if (this.getX() == other.getX() && this.getY() == other.getY()) {
209 return true;
210 }
211 return false;
212 }
213 }