@Override
  double evaluate(JavaRDD<Vector> evalData) {
    Map<Integer,ClusterMetric> clusterMetricsByID = fetchClusterMetrics(evalData).collectAsMap();
    Map<Integer,ClusterInfo> clustersByID = getClustersByID();
    DistanceFn<double[]> distanceFn = getDistanceFn();

    return clustersByID.entrySet().stream().mapToDouble(entryI -> {
      Integer idI = entryI.getKey();
      double[] centerI = entryI.getValue().getCenter();
      double clusterScatter1 = clusterMetricsByID.get(idI).getMeanDist();
      // this inner loop should not be set to j = (i+1) as DB Index computation is not symmetric.
      // For a given cluster i, we look for a cluster j that maximizes
      // the ratio of (the sum of average distances from points in cluster i to its center and
      // points in cluster j to its center) to (the distance between cluster i and cluster j).
      // The key here is the Maximization of the DB Index for a cluster:
      // the cluster that maximizes this ratio may be j for i but not necessarily i for j
      return clustersByID.entrySet().stream().mapToDouble(entryJ -> {
        Integer idJ = entryJ.getKey();
        if (idI.equals(idJ)) {
          return 0.0;
        }
        double[] centerJ = entryJ.getValue().getCenter();
        double clusterScatter2 = clusterMetricsByID.get(idJ).getMeanDist();
        return (clusterScatter1 + clusterScatter2) / distanceFn.applyAsDouble(centerI, centerJ);
      }).max().orElse(0.0);
    }).average().orElse(0.0);
  }
@ Override double evaluate ( JavaRDD < Vector > evalData ) { Map < Integer , ClusterMetric > clusterMetricsByID = fetchClusterMetrics ( evalData ) . collectAsMap ( ) ; Map < Integer , ClusterInfo > clustersByID = getClustersByID ( ) ; DistanceFn < double [ ] > distanceFn = getDistanceFn ( ) ; return clustersByID . entrySet ( ) . stream ( ) . mapToDouble ( entryI -> { Integer idI = entryI . getKey ( ) ; double [ ] centerI = entryI . getValue ( ) . getCenter ( ) ; double clusterScatter1 = clusterMetricsByID . get ( idI ) . getMeanDist ( ) ; return clustersByID . entrySet ( ) . stream ( ) . mapToDouble ( entryJ -> { Integer idJ = entryJ . getKey ( ) ; if ( idI . equals ( idJ ) ) { return 0.0 ; } double [ ] centerJ = entryJ . getValue ( ) . getCenter ( ) ; double clusterScatter2 = clusterMetricsByID . get ( idJ ) . getMeanDist ( ) ; return ( clusterScatter1 + clusterScatter2 ) / distanceFn . applyAsDouble ( centerI , centerJ ) ; } ) . max ( ) . orElse ( 0.0 ) ; } ) . average ( ) . orElse ( 0.0 ) ; }
@param evalData data for evaluation
@return the Davies-Bouldin Index (http://en.wikipedia.org/wiki/Cluster_analysis#Internal_evaluation);
lower is better