package com.doumee.core.tsp; import java.math.BigDecimal; import java.util.*; import com.doumee.core.utils.Constants; import com.doumee.dao.admin.request.SketchCateModel; import com.doumee.dao.business.model.JkSketchCustomer; import lombok.extern.slf4j.Slf4j; import org.apache.commons.math3.ml.clustering.*; import org.apache.commons.math3.ml.distance.EuclideanDistance; /** * * @author xjx * */ @Slf4j public class ClusterCustomKMeans{ //欧式距离 public List clusterPoints(List customers, int k, int d){ List list = new ArrayList<>(); if(customers.size() <= k){ int index =0; for (JkSketchCustomer c : customers) { SketchCateModel sketchCateModel = new SketchCateModel(); sketchCateModel.setId(index); List cList = new ArrayList<>(); cList.add(c); sketchCateModel.setTotalNum(c.getTotalNum()); sketchCateModel.setCustomerList(cList); sketchCateModel.setStartPoint(c); sketchCateModel.setTotalCustomer(1); list.add(sketchCateModel); log.error("Cluster " + index + "members:"+1+"/200 "+" 客户:"+ c.getName()); index ++; } return list; } List points = new ArrayList<>(); for (int i = 0; i < customers.size(); i++) { DoublePointNew p = new DoublePointNew(new double[]{customers.get(i).getLatitude().doubleValue(), customers.get(i).getLongitude().doubleValue()}); p.setCustomer(customers.get(i)); points.add(p); // 示例点1 } KMeansPlusPlusClusterer clusterer = new KMeansPlusPlusClusterer<>(k, d, new EuclideanDistance()); List> clusters = clusterer.cluster(points); int index = 0; int maxMembersPerCluster = 200; // 设置每个簇的最大成员数 List> allList = new ArrayList<>(); for (CentroidCluster cluster : clusters) { if(cluster.getPoints() ==null || cluster.getPoints().size() ==0){ log.error("Cluster " + clusters.indexOf(cluster) + "members:"+cluster.getPoints().size()+"/200 无数据"); continue; } log.error("Cluster " + clusters.indexOf(cluster) + "members:"+cluster.getPoints().size()+"/200 "+"中心点:"+ Arrays.toString(cluster.getCenter().getPoint())+"中心点:"+ cluster.getPoints().get(0).getCustomer().getName()); if (cluster.getPoints().size() > maxMembersPerCluster) { // 这里可以重新运行聚类算法或者手动调整簇的分配策略 log.error("Cluster " + clusters.indexOf(cluster) + " exceeds maximum members:" + cluster.getPoints().size() + "/200, re-clustering needed."); // 可以考虑再次调用KMeansPlusPlusClusterer或其它逻辑来处理超限情况。 } allList.add(cluster); } for (CentroidCluster cluster : allList) { // System.out.println("Cluster " + clusters.indexOf(cluster) + "members:"+cluster.getPoints().size()+"/200 "); if (cluster.getPoints().size() > maxMembersPerCluster) { // 这里可以重新运行聚类算法或者手动调整簇的分配策略 // System.out.println("Cluster " + clusters.indexOf(cluster) + " exceeds maximum members:"+cluster.getPoints().size()+"/200, re-clustering needed."); // 可以考虑再次调用KMeansPlusPlusClusterer或其它逻辑来处理超限情况。 } SketchCateModel sketchCateModel = new SketchCateModel(); sketchCateModel.setId(index); List cList = new ArrayList<>(); for(DoublePointNew doublePointNew:cluster.getPoints()){ cList.add(doublePointNew.getCustomer()); sketchCateModel.setTotalNum(Constants.formatBigdecimal(sketchCateModel.getTotalNum()).add(Constants.formatBigdecimal(doublePointNew.getCustomer().getTotalNum()))); } sortPointByCenterPoint(cluster,cList); sketchCateModel.setCustomerList(cList); sketchCateModel.setStartPoint(cList.get(0)); sketchCateModel.setTotalCustomer(cList.size()); list.add(sketchCateModel); } return list; } private void sortPointByCenterPoint(CentroidCluster cluster, List cList) { double clat = Constants.formatBigdecimal(cList.get(0).getLatitude()).doubleValue(); double clong = Constants.formatBigdecimal(cList.get(0).getLongitude()).doubleValue(); if(cluster!=null || cluster.getCenter() != null || cluster.getCenter().getPoint() != null && cluster.getCenter().getPoint().length>=2){ clong = cluster.getCenter().getPoint()[1]; clat = cluster.getCenter().getPoint()[0]; } for(JkSketchCustomer c : cList){ double latDiff = Constants.formatBigdecimal(c.getLatitude()).doubleValue() - clat; double lonDiff = Constants.formatBigdecimal(c.getLongitude()).doubleValue() - clong; c.setDistanceCenter(Math.sqrt(latDiff * latDiff + lonDiff * lonDiff)); // 欧氏距离 } Collections.sort(cList, (p1, p2) -> Double.compare(p1.getDistanceCenter(), p2.getDistanceCenter())); } public class DoublePointNew extends DoublePoint{ private JkSketchCustomer customer; public DoublePointNew(double[] point) { super(point); } public JkSketchCustomer getCustomer() { return customer; } public void setCustomer(JkSketchCustomer customer) { this.customer = customer; } } public static void main(String[] args) { List points = new ArrayList<>(); for (int i = 0; i <10; i++) { JkSketchCustomer a = new JkSketchCustomer(); a.setLatitude(new BigDecimal(30.19d )); a.setLongitude(new BigDecimal(117.40 )); a.setName("客户"+i); points.add(a); } for (int i = 0; i <10; i++) { JkSketchCustomer a = new JkSketchCustomer(); a.setLatitude(new BigDecimal(31.19d )); a.setLongitude(new BigDecimal(118.40 )); a.setName("客户"+i); points.add(a); } for (int i = 10; i <3000; i++) { JkSketchCustomer a = new JkSketchCustomer(); a.setLatitude(new BigDecimal(31.19d-(0.1d)*Math.random())); a.setLongitude(new BigDecimal(118.40-(0.2d)*Math.random())); a.setName("客户"+i); points.add(a); } double threshold = 1000; // 设置距离阈值,超过这个距离就不属于同一聚类。 (new ClusterCustomKMeans()).clusterPoints(points, 100,1); } }