MrShi
3 天以前 3d6ff15899256f33cd100d95237f613c023d50df
server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/ClusterCustomKMeans.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,147 @@
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<SketchCateModel> clusterPoints(List<JkSketchCustomer> customers, int k, int d){
            List<SketchCateModel> list = new ArrayList<>();
            if(customers.size() <= k){
                int index =0;
                for (JkSketchCustomer c : customers) {
                    SketchCateModel sketchCateModel = new SketchCateModel();
                    sketchCateModel.setId(index);
                    List<JkSketchCustomer> 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<DoublePointNew> 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<DoublePointNew> clusterer = new KMeansPlusPlusClusterer<>(k, d, new EuclideanDistance());
            List<CentroidCluster<DoublePointNew>> clusters = clusterer.cluster(points);
            int index  = 0;
            int maxMembersPerCluster = 200; // è®¾ç½®æ¯ä¸ªç°‡çš„æœ€å¤§æˆå‘˜æ•°
            List<CentroidCluster<DoublePointNew>> allList = new ArrayList<>();
            for (CentroidCluster<DoublePointNew> 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<DoublePointNew> 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<JkSketchCustomer> 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<DoublePointNew> cluster, List<JkSketchCustomer> 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<JkSketchCustomer> 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);
    }
}