0x00 сводка
Alink — это платформа алгоритмов машинного обучения нового поколения, разработанная Alibaba на основе вычислительного движка реального времени Flink.Это первая в отрасли платформа машинного обучения, которая поддерживает как пакетные, так и потоковые алгоритмы. Эта и предыдущие статьи помогут вам проанализировать реализацию оценки кластера в Alink.
0x01 Фоновая концепция
1.1 Что такое кластеризация
Кластеризация, с точки зрения непрофессионала, означает, что вещи сгруппированы вместе, а люди разделены на группы.
Кластеризация — это наблюдательное обучение, а не обучение на основе примеров. Кластеризацию можно использовать как независимый инструмент для получения распределения данных, наблюдения за характеристиками каждого кластера данных и сосредоточения внимания на конкретных кластерах для дальнейшего анализа.
Кластерный анализ также можно использовать в качестве этапа предварительной обработки для других задач интеллектуального анализа данных, таких как классификация, правила ассоциации.
1.2 Метод кластерного анализа
Кластерный анализ можно условно разделить на следующие методы:
Метод деления
- Construct various partitions and then evaluate them by some criterion,e.g.,minimizing the sum of square errors
- Typical methods:k-means,k-medoids,CLARANS
Иерархический подход:
- Create a hierarchical decomposition of the set of data (or objects) using some criterion
- Typical methods: Diana,Agnes,BIRCH,CAMELEON
Методы на основе плотности:
- Based on connectivity and density functions
- Typical methods: DBSCAN,OPTICS,DenClue
Сеточный подход:
- Based on multiple-level granularity structure
- Typical methods: STING,WaveCluster,CLIQUE
Модельный подход:
- A model is hypothesized for each of the clusters and tries to find the best fit of that model to each other
- Typical methods: EM,SOM,COBWEB
Методы, основанные на частых закономерностях:
- Based on the analysis of frequent patterns
- Typical methods: p-Cluster
Подход, основанный на ограничениях:
- Clustering by considering user-specified or application-specific constraints
- Typical methods: COD(obstacles),constrained clustering
Ссылочный подход:
- Objects are often linked together in various ways
- Massive links can be used to cluster objects: SimRank,LinkClus
1.3 Оценка кластеризации
Оценка кластеризации оценивает возможность кластеризации набора данных и качество результатов, полученных с помощью метода кластеризации. Оценка кластеризации в основном включает: оценку тенденции кластеризации, определение количества кластеров в наборе данных и измерение качества кластеризации.
Оцените тенденции кластеризации: Для заданного набора данных оцените, имеет ли набор данных неслучайную структуру. Слепое использование метода кластеризации в наборе данных вернет некоторые кластеры, которые могут ввести в заблуждение. Кластерный анализ наборов данных имеет смысл только в том случае, если в данных присутствует неслучайная структура.
Оценка тенденции кластера определяет, имеет ли данный набор данных неслучайную структуру, которая может привести к значимым кластерам. Набор данных без какой-либо неслучайной структуры, такой как равномерно распределенные точки в пространстве данных, хотя алгоритм кластеризации может возвращать кластеры для этого набора данных, эти кластеры случайны и не имеют смысла. Кластеризация требует неравномерного распределения данных.
Определение качества кластера: после использования метода кластеризации набора данных необходимо оценить качество полученных кластеров.
Существует два типа методов: внешние методы и внутренние методы.
- Внешние методы: контролируемые методы, требующие эталонных данных. Определенная мера используется для оценки степени соответствия результатов кластеризации эталонным данным.
- Внутренние методы: неконтролируемые методы без эталонных данных. Степень агрегации внутри классов и степень дисперсии между классами.
0x02 Показатели оценки, поддерживаемые Alink
Документ Alink выглядит следующим образом: Оценка кластеризации предназначена для оценки влияния результатов прогнозирования алгоритма кластеризации, и поддерживаются следующие индикаторы оценки. Но на самом деле больше можно узнать из его тестового кода.
Compactness(CP),Более низкий CP означает более близкое расстояние внутри кластера
Seperation(SP), чем выше SP, тем больше расстояние кластеризации между классами
Davies-Bouldin Index(DB), чем меньше БД, тем меньше внутриклассовое расстояние и больше межклассовое расстояние
Calinski-Harabasz Index(VRC), больший VRC означает лучшее качество кластеризации
Из его тестового кода мы можем обнаружить больше метрик:
Assert.assertEquals(metrics.getCalinskiHarabaz(), 12150.00, 0.01);
Assert.assertEquals(metrics.getCompactness(), 0.115, 0.01);
Assert.assertEquals(metrics.getCount().intValue(), 6);
Assert.assertEquals(metrics.getDaviesBouldin(), 0.014, 0.01);
Assert.assertEquals(metrics.getSeperation(), 15.58, 0.01);
Assert.assertEquals(metrics.getK().intValue(), 2);
Assert.assertEquals(metrics.getSsb(), 364.5, 0.01);
Assert.assertEquals(metrics.getSsw(), 0.119, 0.01);
Assert.assertEquals(metrics.getPurity(), 1.0, 0.01);
Assert.assertEquals(metrics.getNmi(), 1.0, 0.01);
Assert.assertEquals(metrics.getAri(), 1.0, 0.01);
Assert.assertEquals(metrics.getRi(), 1.0, 0.01);
Assert.assertEquals(metrics.getSilhouetteCoefficient(), 0.99,0.01);
Нам нужно ввести несколько показателей
2.1 Коэффициент силуэта:
Для каждого объекта o в D вычислите:
- a(o) : среднее расстояние a(o) между o и другими объектами в кластере, к которому принадлежит o.
- b(o) : минимальное среднее расстояние от o до всех кластеров, не содержащих o.
Полученный коэффициент силуэта определяется как:
Фактор силуэта имеет значение от -1 до 1.
Значение a(o) отражает компактность кластера, которому принадлежит o. Чем меньше значение, тем компактнее кластер.
Значение b(o) отражает степень отделения o от других кластеров. Чем больше значение b(o), тем больше o отделено от других кластеров.
Когда значение коэффициента силуэта o близко к 1, кластер, содержащий o, компактен, а o находится далеко от других кластеров, что является желательной ситуацией.
Отрицательное значение коэффициента силуэта означает, что в желаемом случае o ближе к объектам в других кластерах, чем к объектам в своем кластере, что во многих случаях плохо и его следует избегать.
2.2 Калински-Харабаз (CH)
Индекс CH измеряет близость внутри класса, вычисляя сумму квадратов расстояний между точками в классе и центром класса, и измеряет степень разделения набора данных, вычисляя сумму квадратов расстояний. между различными центральными точками и центральной точкой набора данных.Показатель CH определяется степенью разделения.Получено отношение к герметичности. Следовательно, чем больше КГ, тем ближе сам класс и тем больше он разбросан между классами, то есть лучше результат кластеризации.
Коэффициенты CH и силуэта применимы, когда фактическая информация о классе неизвестна.
2.3 Индекс Дэвиса-Булдина (Dbi)
Индекс Бодинга Дэвидсона (DBI), также известный как Индекс пригодности классификации, был разработан Дэвидомл ·Дэвис и Дональд· БулдинПредлагаемый индекс для оценки достоинств алгоритмов кластеризации.
Этот DBI предназначен для расчета отношения суммы внутриклассового расстояния и внеклассового расстояния, чтобы оптимизировать выбор значения k и избежать локальной оптимальной ситуации, вызванной только вычислением целевой функции Wn в K- означает алгоритм.
2.4 Индекс Рэнда (RI), скорректированный индекс Рэнда (ARI)
Среди них C представляет фактическую информацию о категории, K представляет результат кластеризации, a представляет логарифм элементов одной и той же категории в C и K, а b представляет логарифм элементов разных категорий в C и K.
Диапазон значений RI составляет [0, 1], и чем больше значение, тем более согласуются результаты кластеризации с реальной ситуацией. Чем больше RI, тем выше точность эффекта кластеризации и выше чистота в каждом классе.
Для достижения «в случае, когда результаты кластеризации генерируются случайным образом, индекс должен быть близок к нулю», предлагается Скорректированный индекс ранда (Adjusted rand index), обладающий более высокой степенью дискриминации:
Диапазон значений ARI составляет [−1, 1], и большее значение означает, что результат кластеризации более соответствует реальной ситуации. В широком смысле ARI измеряет, насколько хорошо подходят два распределения данных.
0x03 Пример кода
Пример кода для оценки кластеризации выглядит следующим образом:
public class EvalClusterBatchOpExp {
public static void main(String[] args) throws Exception {
Row[] rows = new Row[] {
Row.of(0, "0,0,0"),
Row.of(0, "0.1,0.1,0.1"),
Row.of(0, "0.2,0.2,0.2"),
Row.of(1, "9,9,9"),
Row.of(1, "9.1,9.1,9.1"),
Row.of(1, "9.2,9.2,9.2")
};
MemSourceBatchOp inOp = new MemSourceBatchOp(Arrays.asList(rows), new String[] {"label", "Y"});
KMeans train = new KMeans()
.setVectorCol("Y")
.setPredictionCol("pred")
.setK(2);
ClusterMetrics metrics = new EvalClusterBatchOp()
.setPredictionCol("pred")
.setVectorCol("Y")
.setLabelCol("label")
.linkFrom(train.fit(inOp).transform(inOp))
.collectMetrics();
System.out.println(metrics.getCalinskiHarabaz());
System.out.println(metrics.getCompactness());
System.out.println(metrics.getCount());
System.out.println(metrics.getDaviesBouldin());
System.out.println(metrics.getSeperation());
System.out.println(metrics.getK());
System.out.println(metrics.getSsb());
System.out.println(metrics.getSsw());
System.out.println(metrics.getPurity());
System.out.println(metrics.getNmi());
System.out.println(metrics.getAri());
System.out.println(metrics.getRi());
System.out.println(metrics.getSilhouetteCoefficient());
}
}
Результат:
12150.000000000042
0.11547005383792497
6
0.014814814814814791
15.588457268119896
2
364.5
0.1199999999999996
1.0
1.0
1.0
1.0
0.9997530305375205
0x04 Общая логика
Общая логика кода выглядит следующим образом:
- Операция расчета индекса, связанного с меткой
- Работайте с каждым разделом, используя callLocalPredResult
- flatMap 1 состоит в том, чтобы разбить строку и получить метку y
- flatMap 2 — разбить строку и получить y_hat, поэтому первые два шага — получить карту сопоставления y и y_hat. Эти два передаются в CalLocalPredResult для использования.
- Вызовите CalLocalPredResult, чтобы построить матрицу путаницы
- Используйте сокращение, чтобы объединить результаты этих операций над разделами.
- Используйте ExtractParamsFromConfusionMatrix для расчета чистоты, NMI и других показателей на основе матрицы путаницы.
- Работайте с каждым разделом, используя callLocalPredResult
- Операция расчета индекса, связанного с вектором
- Группировать данные по категориям
- Группировка и слияние, вызов векторных метрик распределенных вычислений CalcClusterMetricsSummary
- Обход строк и накопление в sumVector
- Цикл для вычисления некоторой статистики
- Вызовите ReduceBaseMetrics и снова объединитесь, чтобы сформировать BaseMetricsSummary.
- Вызовите функцию calSilhouetteCoefficient, чтобы вычислить SilhouetteCoefficient.
- Хранить данные как параметры
- Объединить вывод
- Создайте объединение, объедините labelMetrics и vectorMetrics и объедините их в итоговую таблицу.
- групповое слияние
- вывод в последнюю таблицу
Конкретный код выглядит следующим образом:
public EvalClusterBatchOp linkFrom(BatchOperator<?>... inputs) {
BatchOperator in = checkAndGetFirst(inputs);
String labelColName = this.getLabelCol();
String predResultColName = this.getPredictionCol();
String vectorColName = this.getVectorCol();
DistanceType distanceType = getDistanceType();
ContinuousDistance distance = distanceType.getFastDistance();
DataSet<Params> empty = MLEnvironmentFactory.get(getMLEnvironmentId()).getExecutionEnvironment().fromElements(
new Params());
DataSet<Params> labelMetrics = empty, vectorMetrics;
if (null != labelColName) { // 针对 label 操作
// 获取数据
DataSet<Row> data = in.select(new String[] {labelColName, predResultColName}).getDataSet();
// 使用 calLocalPredResult 对每个分区操作
labelMetrics = calLocalPredResult(data)
.reduce(new ReduceFunction<LongMatrix>() { // 使用 reduce 归并这些分区操作结果
@Override
public LongMatrix reduce(LongMatrix value1, LongMatrix value2) {
value1.plusEqual(value2);
return value1;
}
})
.map(new MapFunction<LongMatrix, Params>() {
@Override
public Params map(LongMatrix value) {
// 使用 extractParamsFromConfusionMatrix 根据混淆矩阵计算 purity, NMI等指标
return ClusterEvaluationUtil.extractParamsFromConfusionMatrix(value);
}
});
}
if (null != vectorColName) {
// 获取数据
DataSet<Row> data = in.select(new String[] {predResultColName, vectorColName}).getDataSet();
DataSet<BaseMetricsSummary> metricsSummary = data
.groupBy(0) // 对数据按照类别进行分组
.reduceGroup(new CalcClusterMetricsSummary(distance)) // 分布式计算向量相关的指标
.reduce(new EvaluationUtil.ReduceBaseMetrics());// 归并
DataSet<Tuple1<Double>> silhouetteCoefficient = data.map( // 计算silhouette
new RichMapFunction<Row, Tuple1<Double>>() {
@Override
public Tuple1<Double> map(Row value) {
List<BaseMetricsSummary> list = getRuntimeContext().getBroadcastVariable(METRICS_SUMMARY);
return ClusterEvaluationUtil.calSilhouetteCoefficient(value,
(ClusterMetricsSummary)list.get(0));
}
}).withBroadcastSet(metricsSummary, METRICS_SUMMARY)
.aggregate(Aggregations.SUM, 0);
// 把数据存储为Params
vectorMetrics = metricsSummary.map(new ClusterEvaluationUtil.SaveDataAsParams()).withBroadcastSet(
silhouetteCoefficient, SILHOUETTE_COEFFICIENT);
} else {
vectorMetrics = in.select(predResultColName)
.getDataSet()
.reduceGroup(new BasicClusterParams());
}
DataSet<Row> out = labelMetrics
.union(vectorMetrics) // 把 labelMetrics 和 vectorMetrics 联合起来
.reduceGroup(new GroupReduceFunction<Params, Row>() { // 分组归并
@Override
public void reduce(Iterable<Params> values, Collector<Row> out) {
Params params = new Params();
for (Params p : values) {
params.merge(p);
}
out.collect(Row.of(params.toJson()));
}
});
// 输出到最后表
this.setOutputTable(DataSetConversionUtil.toTable(getMLEnvironmentId(),
out, new TableSchema(new String[] {EVAL_RESULT}, new TypeInformation[] {Types.STRING})
));
return this;
}
0x05 для операции с меткой
5.1 calLocalPredResult
потому что этоDataSet<Row> data = in.select(new String[] {labelColName, predResultColName}).getDataSet();
, поэтому здесь рассматриваются y и y_hat.
Есть два flatMap, связанных вместе.
- flatMap 1 состоит в том, чтобы разбить строку и получить метку y
- flatMap 2 состоит в том, чтобы разбить строку и получить y_hat
Обе плоские карты связаны с DistinctLabelIndexMap и проектом(0).Функция DistinctLabelIndexMapGive each label an ID, return a map of label and ID.
, который должен дать каждому идентификатору метку. project(0) должен извлечь метку.
Итак, первые два шага — получить карту сопоставления y и y_hat. Эти два передаются в CalLocalPredResult для использования.
Третий шаг — вызвать CalLocalPredResult для построения матрицы путаницы.
Конкретный код выглядит следующим образом:
private static DataSet<LongMatrix> calLocalPredResult(DataSet<Row> data) {
// 打散Row,得到 Label y
DataSet<Tuple1<Map<String, Integer>>> labels = data.flatMap(new FlatMapFunction<Row, String>() {
@Override
public void flatMap(Row row, Collector<String> collector) {
if (EvaluationUtil.checkRowFieldNotNull(row)) {
collector.collect(row.getField(0).toString());
}
}
}).reduceGroup(new EvaluationUtil.DistinctLabelIndexMap(false, null)).project(0);
// 打散Row,得到 y_hat
DataSet<Tuple1<Map<String, Integer>>> predictions = data.flatMap(new FlatMapFunction<Row, String>() {
@Override
public void flatMap(Row row, Collector<String> collector) {
if (EvaluationUtil.checkRowFieldNotNull(row)) {
collector.collect(row.getField(1).toString());
}
}
}).reduceGroup(new EvaluationUtil.DistinctLabelIndexMap(false, null)).project(0);
// 前两步是得到 y 和 y_hat 的映射 map。这两个会广播给 CalLocalPredResult 使用
// Build the confusion matrix.
DataSet<LongMatrix> statistics = data
.rebalance()
.mapPartition(new CalLocalPredResult())
.withBroadcastSet(labels, LABELS)
.withBroadcastSet(predictions, PREDICTIONS);
return statistics;
}
CalLocalPredResult строит матрицу путаницы.
- В функции open y и y_hat получаются из системы.
- В функции mapPartition устанавливается матрица путаницы.
matrix = {long[2][]@10707}
0 = {long[2]@10709}
0 = 0
1 = 0
1 = {long[2]@10710}
0 = 1
1 = 0
Код:
static class CalLocalPredResult extends RichMapPartitionFunction<Row, LongMatrix> {
private Map<String, Integer> labels, predictions;
@Override
public void open(Configuration parameters) throws Exception {
List<Tuple1<Map<String, Integer>>> list = getRuntimeContext().getBroadcastVariable(LABELS);
this.labels = list.get(0).f0;
list = getRuntimeContext().getBroadcastVariable(PREDICTIONS);
this.predictions = list.get(0).f0;
}
@Override
public void mapPartition(Iterable<Row> rows, Collector<LongMatrix> collector) {
long[][] matrix = new long[predictions.size()][labels.size()];
for (Row r : rows) {
if (EvaluationUtil.checkRowFieldNotNull(r)) {
int label = labels.get(r.getField(0).toString());
int pred = predictions.get(r.getField(1).toString());
matrix[pred][label] += 1;
}
}
collector.collect(new LongMatrix(matrix));
}
}
5.2 extractParamsFromConfusionMatrix
ExtractParamsFromConfusionMatrix Здесь нужно рассчитать ряд показателей, таких как чистота и NMI, в соответствии с матрицей путаницы.
public static Params extractParamsFromConfusionMatrix(LongMatrix longMatrix) {
long[][] matrix = longMatrix.getMatrix();
long[] actualLabel = longMatrix.getColSums();
long[] predictLabel = longMatrix.getRowSums();
long total = longMatrix.getTotal();
double entropyActual = 0.0;
double entropyPredict = 0.0;
double mutualInfor = 0.0;
double purity = 0.0;
long tp = 0L;
long tpFpSum = 0L;
long tpFnSum = 0L;
for (long anActualLabel : actualLabel) {
entropyActual += entropy(anActualLabel, total);
tpFpSum += combination(anActualLabel);
}
entropyActual /= -Math.log(2);
for (long aPredictLabel : predictLabel) {
entropyPredict += entropy(aPredictLabel, total);
tpFnSum += combination(aPredictLabel);
}
entropyPredict /= -Math.log(2);
for (int i = 0; i < matrix.length; i++) {
long max = 0;
for (int j = 0; j < matrix[0].length; j++) {
max = Math.max(max, matrix[i][j]);
mutualInfor += (0 == matrix[i][j] ? 0.0 :
1.0 * matrix[i][j] / total * Math.log(1.0 * total * matrix[i][j] / predictLabel[i] / actualLabel[j]));
tp += combination(matrix[i][j]);
}
purity += max;
}
purity /= total;
mutualInfor /= Math.log(2);
long fp = tpFpSum - tp;
long fn = tpFnSum - tp;
long totalCombination = combination(total);
long tn = totalCombination - tp - fn - fp;
double expectedIndex = 1.0 * tpFpSum * tpFnSum / totalCombination;
double maxIndex = 1.0 * (tpFpSum + tpFnSum) / 2;
double ri = 1.0 * (tp + tn) / (tp + tn + fp + fn);
return new Params()
.set(ClusterMetrics.NMI, 2.0 * mutualInfor / (entropyActual + entropyPredict))
.set(ClusterMetrics.PURITY, purity)
.set(ClusterMetrics.RI, ri)
.set(ClusterMetrics.ARI, (tp - expectedIndex) / (maxIndex - expectedIndex));
}
0x06 Связанный с вектором
Первые два шага — это распределенные вычисления и слияние:
DataSet<BaseMetricsSummary> metricsSummary = data
.groupBy(0)
.reduceGroup(new CalcClusterMetricsSummary(distance))
.reduce(new EvaluationUtil.ReduceBaseMetrics());
6.1 CalcClusterMetricsSummary
ClusterEvaluationUtil.getClusterStatistics вызывается для выполнения вычислений.
public static class CalcClusterMetricsSummary implements GroupReduceFunction<Row, BaseMetricsSummary> {
private ContinuousDistance distance;
public CalcClusterMetricsSummary(ContinuousDistance distance) {
this.distance = distance;
}
@Override
public void reduce(Iterable<Row> rows, Collector<BaseMetricsSummary> collector) {
collector.collect(ClusterEvaluationUtil.getClusterStatistics(rows, distance));
}
}
ClusterEvaluationUtil.getClusterStatistics выглядит следующим образом
public static ClusterMetricsSummary getClusterStatistics(Iterable<Row> rows, ContinuousDistance distance) {
List<Vector> list = new ArrayList<>();
int total = 0;
String clusterId;
DenseVector sumVector;
Iterator<Row> iterator = rows.iterator();
Row row = null;
while (iterator.hasNext() && !EvaluationUtil.checkRowFieldNotNull(row)) {
// 取出第一个不为空的item
row = iterator.next();
}
if (EvaluationUtil.checkRowFieldNotNull(row)) {
clusterId = row.getField(0).toString(); // 取出 clusterId
Vector vec = VectorUtil.getVector(row.getField(1)); // 取出 Vector
sumVector = DenseVector.zeros(vec.size()); // 初始化
} else {
return null;
}
while (null != row) { // 遍历 rows,累积到 sumVector
if (EvaluationUtil.checkRowFieldNotNull(row)) {
Vector vec = VectorUtil.getVector(row.getField(1));
list.add(vec);
if (distance instanceof EuclideanDistance) {
sumVector.plusEqual(vec);
} else {
vec.scaleEqual(1.0 / vec.normL2());
sumVector.plusEqual(vec);
}
total++;
}
row = iterator.hasNext() ? iterator.next() : null;
}
DenseVector meanVector = sumVector.scale(1.0 / total); // 取mean
// runtime变量,这里示例是第二组的向量
list = {ArrayList@10654} size = 3
0 = {DenseVector@10661} "9.0 9.0 9.0"
1 = {DenseVector@10662} "9.1 9.1 9.1"
2 = {DenseVector@10663} "9.2 9.2 9.2"
double distanceSum = 0.0;
double distanceSquareSum = 0.0;
double vectorNormL2Sum = 0.0;
for (Vector vec : list) { // 循环,计算出几个统计信息
double d = distance.calc(meanVector, vec);
distanceSum += d;
distanceSquareSum += d * d;
vectorNormL2Sum += vec.normL2Square();
}
// runtime变量
sumVector = {DenseVector@10656} "27.3 27.3 27.3"
meanVector = {DenseVector@10657} "9.1 9.1 9.1"
distanceSum = 0.34641016151377424
distanceSquareSum = 0.059999999999999575
vectorNormL2Sum = 745.3499999999999
return new ClusterMetricsSummary(clusterId, total, distanceSum / total, distanceSquareSum, vectorNormL2Sum,
meanVector, distance);
}
6.2 ReduceBaseMetrics
Вот слияние для формирования BaseMetricsSummary.
/**
* Merge the BaseMetrics calculated locally.
*/
public static class ReduceBaseMetrics implements ReduceFunction<BaseMetricsSummary> {
@Override
public BaseMetricsSummary reduce(BaseMetricsSummary t1, BaseMetricsSummary t2) throws Exception {
return null == t1 ? t2 : t1.merge(t2);
}
}
6.3 calSilhouetteCoefficient
Третий шаг — вызвать функцию calSilhouetteCoefficient для вычисления SilhouetteCoefficient.
vectorMetrics = metricsSummary.map(new ClusterEvaluationUtil.SaveDataAsParams()).withBroadcastSet(
silhouetteCoefficient, SILHOUETTE_COEFFICIENT);
Вот та же обработка, что и по формуле
public static Tuple1<Double> calSilhouetteCoefficient(Row row, ClusterMetricsSummary clusterMetricsSummary) {
if (!EvaluationUtil.checkRowFieldNotNull(row)) {
return Tuple1.of(0.);
}
String clusterId = row.getField(0).toString();
Vector vec = VectorUtil.getVector(row.getField(1));
double currentClusterDissimilarity = 0.0;
double neighboringClusterDissimilarity = Double.MAX_VALUE;
if (clusterMetricsSummary.distance instanceof EuclideanDistance) {
double normSquare = vec.normL2Square();
for (int i = 0; i < clusterMetricsSummary.k; i++) {
double dissimilarity = clusterMetricsSummary.clusterCnt.get(i) * normSquare
- 2 * clusterMetricsSummary.clusterCnt.get(i) * MatVecOp.dot(vec, clusterMetricsSummary.meanVector.get(i)) + clusterMetricsSummary.vectorNormL2Sum.get(i);
if (clusterId.equals(clusterMetricsSummary.clusterId.get(i))) {
if (clusterMetricsSummary.clusterCnt.get(i) > 1) {
currentClusterDissimilarity = dissimilarity / (clusterMetricsSummary.clusterCnt.get(i) - 1);
}
} else {
neighboringClusterDissimilarity = Math.min(neighboringClusterDissimilarity,
dissimilarity / clusterMetricsSummary.clusterCnt.get(i));
}
}
} else {
for (int i = 0; i < clusterMetricsSummary.k; i++) {
double dissimilarity = 1.0 - MatVecOp.dot(vec, clusterMetricsSummary.meanVector.get(i));
if (clusterId.equals(clusterMetricsSummary.clusterId.get(i))) {
if (clusterMetricsSummary.clusterCnt.get(i) > 1) {
currentClusterDissimilarity = dissimilarity * clusterMetricsSummary.clusterCnt.get(i) / (clusterMetricsSummary.clusterCnt.get(i) - 1);
}
} else {
neighboringClusterDissimilarity = Math.min(neighboringClusterDissimilarity,
dissimilarity);
}
}
}
return Tuple1.of(currentClusterDissimilarity < neighboringClusterDissimilarity ?
1 - (currentClusterDissimilarity / neighboringClusterDissimilarity) :
(neighboringClusterDissimilarity / currentClusterDissimilarity) - 1);
}
6.4 SaveDataAsParams
Четвертый шаг — сохранить данные как Params
public static class SaveDataAsParams extends RichMapFunction<BaseMetricsSummary, Params> {
@Override
public Params map(BaseMetricsSummary t) throws Exception {
Params params = t.toMetrics().getParams();
List<Tuple1<Double>> silhouetteCoefficient = getRuntimeContext().getBroadcastVariable(
EvalClusterBatchOp.SILHOUETTE_COEFFICIENT);
params.set(ClusterMetrics.SILHOUETTE_COEFFICIENT,
silhouetteCoefficient.get(0).f0 / params.get(ClusterMetrics.COUNT));
return params;
}
}
0x06 Комбинированный вывод
На этом этапе выполняется объединение для объединения labelMetrics и vectorMetrics, а затем объединение и вывод в итоговую таблицу.
DataSet<Row> out = labelMetrics
.union(vectorMetrics)
.reduceGroup(new GroupReduceFunction<Params, Row>() {
@Override
public void reduce(Iterable<Params> values, Collector<Row> out) {
Params params = new Params();
for (Params p : values) {
params.merge(p);
}
out.collect(Row.of(params.toJson()));
}
});
this.setOutputTable(DataSetConversionUtil.toTable(getMLEnvironmentId(),
out, new TableSchema(new String[] {EVAL_RESULT}, new TypeInformation[] {Types.STRING})
));
0xEE Личная информация
★★★★★★Думая о жизни и технологиях★★★★★★
Публичный аккаунт WeChat:мысли Росси
Если вы хотите получать своевременные новости о статьях, написанных отдельными лицами, или хотите видеть технические материалы, рекомендованные отдельными лицами, обратите внимание.
ссылка 0xFF
Алгоритмы кластеризации и их метрики оценки
[ML] Показатели оценки кластеризации
Индекс оценки результатов кластеризации
Как оценить качество результатов кластеризации?
Алгоритм оценки кластеризации — коэффициент силуэта
Индекс оценки того, является ли эффект кластеризации хорошим или плохим
Индекс оценки эффекта кластеризации ARI
Индекс оценки алгоритма кластеризации — индекс Дэвиса-Булдина (Dbi)
【Еженедельный блог】Краткое введение в индекс Дэвиса-Булдина (DBI)