Участник:Андрей Туманов/Алгоритм кластеризации категориальных данных CLOPE: различия между версиями
ASA (обсуждение | вклад) |
|||
(не показано 27 промежуточных версий 4 участников) | |||
Строка 1: | Строка 1: | ||
+ | Основные авторы описания: [[Участник:Андрей_Туманов|А.Л.Туманов]] ([[#Общее описание алгоритма|1.1]], [[#Математическое описание алгоритма|1.2]], [[#Вычислительное ядро алгоритма|1.3]], [[#Макроструктура алгоритма|1.4]], [[#Схема реализации последовательного алгоритма|1.5]], [[#Входные и выходные данные алгоритма|1.9]]), [[Участник:Boltonidze|А.В.Александров]] ([[#Последовательная сложность алгоритма|1.6]], [[#Информационный граф|1.7]], [[#Ресурс параллелизма алгоритма|1.8]], [[#Свойства алгоритма|1.10]] [[#Существующие реализации алгоритма|2.7]]) | ||
= Свойства и структура алгоритмов = | = Свойства и структура алгоритмов = | ||
=== Общее описание алгоритма === | === Общее описание алгоритма === | ||
− | Алгоритм CLOPE (Clustering with sLOPE) неирархический метод кластеризации, предназначенный для кластеризации огромных наборов категориальных данных. К достоинствам алгоритма относятся высокие масштабируемость и скорость работы и качество кластеризации, что достигается использованием глобального критерия оптимизации на основе максимизации градиента высоты гистограммы кластера. Отличается простотой программной реализации. | + | Алгоритм CLOPE (Clustering with sLOPE<ref>Yang, Y., Guan, H., You. J. CLOPE: A fast and Effective Clustering Algorithm for Transactional Data In Proc. of SIGKDD’02, July 23-26, 2002, Edmonton, Alberta, Canada.</ref>) неирархический метод кластеризации, предназначенный для кластеризации огромных наборов категориальных данных. К достоинствам алгоритма относятся высокие масштабируемость и скорость работы и качество кластеризации, что достигается использованием глобального критерия оптимизации на основе максимизации градиента высоты гистограммы кластера. Отличается простотой программной реализации. |
Во время работы алгоритм хранит в памяти небольшое количество информации по каждому кластеру и требует минимальное число сканирований набора данных. CLOPE автоматически подбирает количество кластеров, причем это регулируется одним единственным параметром - коэффициентом отталкивания <math> r </math>. При этом он обеспечивает более высокую производительность и лучшее качество кластеризации в сравнении с многими иерархическими алгоритмами. | Во время работы алгоритм хранит в памяти небольшое количество информации по каждому кластеру и требует минимальное число сканирований набора данных. CLOPE автоматически подбирает количество кластеров, причем это регулируется одним единственным параметром - коэффициентом отталкивания <math> r </math>. При этом он обеспечивает более высокую производительность и лучшее качество кластеризации в сравнении с многими иерархическими алгоритмами. | ||
Строка 11: | Строка 12: | ||
Каждый кластер <math>C</math> имеет следующие характеристики: | Каждый кластер <math>C</math> имеет следующие характеристики: | ||
− | + | [[Файл:ExampleCLOPE.jpg|500px|thumb|right]] | |
<math>D(C)</math> – множество уникальных объектов; | <math>D(C)</math> – множество уникальных объектов; | ||
Строка 19: | Строка 20: | ||
<math>W(C)= \mid D(C) \mid ,H(C)=S(C)/W(C) </math> | <math>W(C)= \mid D(C) \mid ,H(C)=S(C)/W(C) </math> | ||
+ | |||
Функция стоимости: | Функция стоимости: | ||
Строка 32: | Строка 34: | ||
для заданных <math>D</math> и <math>r</math> найти разбиение <math>C</math> такое, что: | для заданных <math>D</math> и <math>r</math> найти разбиение <math>C</math> такое, что: | ||
− | <math>Profit(C) \longrightarrow max </math>. | + | <math>Profit(C) \longrightarrow max </math> <ref>Нейский И.М. Классификация и сравнение методов кластеризации.</ref>. |
=== Вычислительное ядро алгоритма === | === Вычислительное ядро алгоритма === | ||
− | Вычислительное ядро алгоритма состоит в вычислении на каждой итерации | + | Вычислительное ядро алгоритма состоит в вычислении на каждой итерации стоимости добавления и удаления транзакции из кластера: |
− | <math> | + | *вычисление нового размера кластера <math>S_{new}(C_i)=S(C_i) \pm \mid(t_n)\mid </math>, где <math>\mid(t_n)\mid</math> - длина транзакции |
+ | |||
+ | *вычисление новой ширины кластера <math>W_{new}(C_i)=\mid D(C_i \cup t_n)|</math> | ||
+ | |||
+ | *вычисление стоимости <math>\frac{S_{new}(C_i)(\mid C_i \mid \pm 1)}{W_{new}(C_i)^r} - \frac{S(C_i) \mid C_i \mid }{W(C_i)^r}</math> | ||
=== Макроструктура алгоритма === | === Макроструктура алгоритма === | ||
Строка 52: | Строка 58: | ||
Вторая часть алгоритма - уточняющие итерации: здесь происходит попытка улучшить вычисленные на первом этапе кластеры. В каждой итерации происходит перебор всех транзакций, и для каждой транзакции вычисляется цена удаления ее из текущего кластера и цена добавления в другой кластер. Суммарная стоимость перемещения будет являться суммой стоимостей удаления и добавления. Если максимальная стоимость перемещения данной транзакции в какой-либо больше нуля, то она перемещается в этот кластер. | Вторая часть алгоритма - уточняющие итерации: здесь происходит попытка улучшить вычисленные на первом этапе кластеры. В каждой итерации происходит перебор всех транзакций, и для каждой транзакции вычисляется цена удаления ее из текущего кластера и цена добавления в другой кластер. Суммарная стоимость перемещения будет являться суммой стоимостей удаления и добавления. Если максимальная стоимость перемещения данной транзакции в какой-либо больше нуля, то она перемещается в этот кластер. | ||
− | Вычисления происходят до тех пор, пока за итерацию происходит хотя бы одно перемещение транзакции. Если за итерацию не было произведено ни одного перемещения, то текущее состояние кластеров является устойчивым и оптимальным. | + | Вычисления происходят до тех пор, пока за итерацию происходит хотя бы одно перемещение транзакции. Если за итерацию не было произведено ни одного перемещения, то текущее состояние кластеров является устойчивым и оптимальным. <ref>Павлин Н. Кластеризация категорийных данных: масштабируемый алгоритм CLOPE, https://basegroup.ru/community/articles/clope</ref> |
Строка 60: | Строка 66: | ||
Входные параметры: | Входные параметры: | ||
− | + | * <math>t</math> - транзакции | |
− | + | * <math>r</math> - коэффициент отталкивания | |
− | + | Выходной параметр: | |
− | + | * <math>C</math> кластеры, в начале алгоритма - пустое множество | |
'''Инициализация:''' | '''Инициализация:''' | ||
Строка 114: | Строка 120: | ||
=== Последовательная сложность алгоритма === | === Последовательная сложность алгоритма === | ||
+ | |||
+ | В соответствии с ранее введенным обозначением <math>n</math> - количество транзакций, <math>m</math> - длина транзакции(максимальная), <math>k</math> - количество кластеров. | ||
+ | |||
+ | Основные вычисления восполняются в функции DeltaAdd/DeltaRemove: производится 1 сложение, не более <math>m</math> сложений/вычитаний, 2 умножения, 2 деления, 2 возведения в степень и 1 сложение - итого <math>m + 8</math> операций. | ||
+ | |||
+ | Операции выполняются для всех транзаций (<math>n</math> штук) и для всех кластеров (<math>k</math> штук). Итого выполняется <math>n*k*(m+8)</math> операций. | ||
+ | |||
+ | В добавок к этому при добавлении/удалении транзакции к кластеру производится пересчет его характеристик: <math>m+2</math> операции. | ||
+ | |||
+ | Из того можно сделать вывод, что оценка сложность алгоритма равна <math>O(n*k*m)</math>. | ||
=== Информационный граф === | === Информационный граф === | ||
+ | На этапе инициализации при обработке каждой транзакции количество кластеров может как увеличиться, так и остаться неизменным. Это показано пунктирными линиями: | ||
+ | [[Файл:init_clope.png|600px|center|Инициализация]] | ||
+ | На этапе итерации функции DeltaAdd/DeltaRemove могут считать параллельно для каждой транзакции | ||
+ | [[Файл:iter_clope.png |600px|center|Итерации]] | ||
=== Ресурс параллелизма алгоритма === | === Ресурс параллелизма алгоритма === | ||
+ | |||
+ | Вычисление стоимости добавления/удаления транзакции, которые выполняются функциями DeltaAdd/DeltaRemove, происходит независимо для всех <math>k</math> кластеров. Поэтому все вычисления можно производить параллельно. Таким образом сложность алгоритма с <math>O(n*k*m)</math> понижается до <math>O(n*m)</math>. | ||
=== Входные и выходные данные алгоритма === | === Входные и выходные данные алгоритма === | ||
+ | |||
+ | '''Входные данные:''' | ||
+ | |||
+ | <math>n</math> транзакций длины <math>m</math> и коэффициент отталкивания <math>r</math> | ||
+ | |||
+ | '''Выходные данные:''' | ||
+ | |||
+ | метки классов для каждой транзакции в соответствии с проведенной кластеризацией(числовая последовательность длины <math>n</math>) | ||
=== Свойства алгоритма === | === Свойства алгоритма === | ||
+ | |||
+ | * Соотношение последовательной и параллельной сложности алгоритма определяется количеством кластеров: <math>\dfrac{O(n*k*m)}{O(n*m)} = k</math> | ||
+ | * [[глоссарий#Вычислительная мощность|''Вычислительная мощность'']] алгоритма равна <math>\dfrac{nk(m+8) + m + 2}{nm + n + 1} \cong k</math> | ||
+ | * Алгоритм не является [[глоссарий#Устойчивость|''устойчивым'']], так как результат работы зависит от порядка чтения транзакций и от текущего набора транзакций в кластере. | ||
+ | * Выполняется свойство сбалансированности операций между параллельными ветвями алгоритма, так как для каждой транзакции выполняются функции DeltaAdd/DeltaRemove, считающие стоимость добавления/удаления транзакции. | ||
+ | * Свойство [[глоссарий#Детерминированность|''детерминированности алгоритмов'']] не выполняется, так как результат алгоритма зависит от порядка прохождения транзакций. Но если рассматривать транзакции как нумерованный список, то результат будет определен однозначно от запуска к запуску. Однако существует расширение алгоритма, обеспечивающее свойство детерминированности. <ref>Li, Y., Le, J., Wang, M. Improving CLOPE’s Profit Value and Stability with an Optimized Agglomerative Approach. Algorithms 2015, 8, 380-394.</ref>. | ||
+ | * Так как алгоритм предназначен для кластеризации категориальных данных, то он практически неприменим для числовой кластеризации. | ||
+ | * Быстро работает даже для большого количества данных, обеспечивая при этом хорошее качество кластеризации | ||
+ | * Имеет простую реализацию | ||
= Программная реализация алгоритма = | = Программная реализация алгоритма = | ||
Строка 132: | Строка 171: | ||
=== Масштабируемость алгоритма и его реализации === | === Масштабируемость алгоритма и его реализации === | ||
+ | Проверка масштабируемости производилась с использованием стандарта MPI на суперкомпьютере "Ломоносов" с числом процессоров: 1,8,16,32,64. | ||
+ | Результаты проверки масштабируемости приведены ниже на графике | ||
+ | [[file:maschtab_clope.png||700px|График масштабируемости]] | ||
=== Динамические характеристики и эффективность реализации алгоритма === | === Динамические характеристики и эффективность реализации алгоритма === | ||
Строка 138: | Строка 180: | ||
=== Существующие реализации алгоритма === | === Существующие реализации алгоритма === | ||
− | + | * http://weka.sourceforge.net/doc.stable/weka/clusterers/CLOPE.html - реализация в open source библиотеке для анализа данных WEKA(Waikato Environment for Knowledge Analysis) на языке Java | |
+ | Также существуют пользовательские реализации алгоритма: | ||
+ | * https://github.com/infozor/php_mysql_clustering_clope - реализация алгоритма на PHP | ||
+ | * https://github.com/Tolsi/scala-clope - реализация алгоритма Scala | ||
= Литература = | = Литература = | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− |
Текущая версия на 16:09, 3 февраля 2017
Основные авторы описания: А.Л.Туманов (1.1, 1.2, 1.3, 1.4, 1.5, 1.9), А.В.Александров (1.6, 1.7, 1.8, 1.10 2.7)
Содержание
- 1 Свойства и структура алгоритмов
- 1.1 Общее описание алгоритма
- 1.2 Математическое описание алгоритма
- 1.3 Вычислительное ядро алгоритма
- 1.4 Макроструктура алгоритма
- 1.5 Схема реализации последовательного алгоритма
- 1.6 Последовательная сложность алгоритма
- 1.7 Информационный граф
- 1.8 Ресурс параллелизма алгоритма
- 1.9 Входные и выходные данные алгоритма
- 1.10 Свойства алгоритма
- 2 Программная реализация алгоритма
- 2.1 Особенности реализации последовательного алгоритма
- 2.2 Локальность данных и вычислений
- 2.3 Возможные способы и особенности параллельной реализации алгоритма
- 2.4 Масштабируемость алгоритма и его реализации
- 2.5 Динамические характеристики и эффективность реализации алгоритма
- 2.6 Выводы для классов архитектур
- 2.7 Существующие реализации алгоритма
- 3 Литература
1 Свойства и структура алгоритмов
1.1 Общее описание алгоритма
Алгоритм CLOPE (Clustering with sLOPE[1]) неирархический метод кластеризации, предназначенный для кластеризации огромных наборов категориальных данных. К достоинствам алгоритма относятся высокие масштабируемость и скорость работы и качество кластеризации, что достигается использованием глобального критерия оптимизации на основе максимизации градиента высоты гистограммы кластера. Отличается простотой программной реализации.
Во время работы алгоритм хранит в памяти небольшое количество информации по каждому кластеру и требует минимальное число сканирований набора данных. CLOPE автоматически подбирает количество кластеров, причем это регулируется одним единственным параметром - коэффициентом отталкивания [math] r [/math]. При этом он обеспечивает более высокую производительность и лучшее качество кластеризации в сравнении с многими иерархическими алгоритмами.
1.2 Математическое описание алгоритма
Пусть имеется база транзакций [math]D[/math], состоящая из множества транзакций [math]\{t_1,t_2,...,t_n\}[/math]. Каждая транзакция есть набор объектов [math]\{i_1,...,i_m\}[/math]. Множество кластеров [math]\{C_1,...,C_k\}[/math] есть разбиение множества [math]\{t_1,...,t_n\}[/math], такое, что [math]C_1 \cup \dots \cup C_k=\{t_1,...,t_n\}[/math] и [math]C_i \ne \empty[/math] и [math]C_i \cap C_j = \empty [/math], для [math]i \ge 1, k \ge j[/math]. Каждый элемент [math]C_i[/math] называется кластером, а [math]n, m, k[/math] – количество транзакций, количество объектов в базе транзакций и число кластеров соответственно.
Каждый кластер [math]C[/math] имеет следующие характеристики:
[math]D(C)[/math] – множество уникальных объектов;
[math]Occ(i,C)[/math] – количество вхождений (частота) объекта [math]i[/math] в кластер [math]C[/math];
[math]S(C)= \sum_{i \in D(C)} Occ(i,C)= \sum_{t_i \in C} \mid t_i \mid , [/math]
[math]W(C)= \mid D(C) \mid ,H(C)=S(C)/W(C) [/math]
Функция стоимости:
[math] Profit(C) = \frac{\sum^{k}_{i=1} G(C_i) \times \mid C_i \mid} {\sum^{k}_{i=1} \mid C_i \mid } = \frac{\sum^{k}_{i=1} \frac{S(C_i)}{W(C_i)^r} \times \mid C_i \mid} {\sum^{k}_{i=1} \mid C_i \mid } [/math]
где [math]\mid C_i \mid[/math] количество объектов в [math]i[/math]-ом кластере, [math]k[/math] – количество кластеров, [math]r[/math] – коэффициент отталкивания [math](0 \lt r \le 1)[/math]
С помощью параметра [math]r[/math] регулируется уровень сходства транзакций внутри кластера, и, как следствие, финальное количество кластеров. Этот коэффициент подбирается пользователем. Чем больше [math]r[/math], тем ниже уровень сходства и тем больше кластеров будет сгенерировано.
Постановка задачи кластеризации алгоритмом CLOPE выглядит следующим образом:
для заданных [math]D[/math] и [math]r[/math] найти разбиение [math]C[/math] такое, что: [math]Profit(C) \longrightarrow max [/math] [2].
1.3 Вычислительное ядро алгоритма
Вычислительное ядро алгоритма состоит в вычислении на каждой итерации стоимости добавления и удаления транзакции из кластера:
- вычисление нового размера кластера [math]S_{new}(C_i)=S(C_i) \pm \mid(t_n)\mid [/math], где [math]\mid(t_n)\mid[/math] - длина транзакции
- вычисление новой ширины кластера [math]W_{new}(C_i)=\mid D(C_i \cup t_n)|[/math]
- вычисление стоимости [math]\frac{S_{new}(C_i)(\mid C_i \mid \pm 1)}{W_{new}(C_i)^r} - \frac{S(C_i) \mid C_i \mid }{W(C_i)^r}[/math]
1.4 Макроструктура алгоритма
Алгоритм состоит из следующих этапов:
1. Инициализация. На этом этапе происходит первый проход по таблице с транзакциями для построения начального разбиения, для каждой транзакции определяется кластер исходя из максимизации стоимости.
2. Итерация. На данном этапе для каждой транзакции проводится попытка перемещения в другой кластер для максимизации функции стоимости.
1.5 Схема реализации последовательного алгоритма
Первая часть алгоритма - инициализация: для каждой транзакции вычисляется кластер, к которому она будет отнесена исходя из максимизации функции стоимости. Для этого вычисляется вспомогательная функция DeltaAdd, которая считает стоимость добавления транзакции к одному из существующих кластеров, либо к пустому. В итоге транзакция помещается в кластер, для которого цена добавления максимальна.
Вторая часть алгоритма - уточняющие итерации: здесь происходит попытка улучшить вычисленные на первом этапе кластеры. В каждой итерации происходит перебор всех транзакций, и для каждой транзакции вычисляется цена удаления ее из текущего кластера и цена добавления в другой кластер. Суммарная стоимость перемещения будет являться суммой стоимостей удаления и добавления. Если максимальная стоимость перемещения данной транзакции в какой-либо больше нуля, то она перемещается в этот кластер.
Вычисления происходят до тех пор, пока за итерацию происходит хотя бы одно перемещение транзакции. Если за итерацию не было произведено ни одного перемещения, то текущее состояние кластеров является устойчивым и оптимальным. [3]
Схема реализации на псевдокоде:
Входные параметры:
- [math]t[/math] - транзакции
- [math]r[/math] - коэффициент отталкивания
Выходной параметр:
- [math]C[/math] кластеры, в начале алгоритма - пустое множество
Инициализация:
for t_i in t: max = 0 for C_j in C: if DeltaAdd(C_j,t_i,r) > max: max = DeltaAdd(C_j,t_i,r) C_best = C_j put t_i in C_best
Итерации:
move = True while move == True: move = False for t_i in t: max = 0 C_now = t_i.cluster removeCost = DeltaRemove(C_now,t_i,r) for C_j in C: if DeltaAdd(C_j,t_i,r) + removeCost > max: max = DeltaAdd(C_j,t_i,r) + removeCost C_best = C_j if max > 0 del t_i from C_now put t_i in C_best move = True
Вспомогательная функция DeltaAdd:
function DeltaAdd(C,t,r) S_new=C.size + t.itemCount W_new=C.wigth for item in t_i: if C_j.occ(item) = 0 W_new = W_new + 1 return S_new * (C.count+1) / (W_new ^ r) - (C.size * C.count) / (C.wigth ^ r)
Вспомогательная функция DeltaRemove:
function DeltaRemove(C,t,r) S_new=C.size - t.itemCount W_new=C.wigth for item in t: if C_j.occ(item) = 1 W_new = W_new - 1 return S_new * (C.count-1) / (W_new ^ r) - (C.size * C.count) / (C.wigth ^ r)
1.6 Последовательная сложность алгоритма
В соответствии с ранее введенным обозначением [math]n[/math] - количество транзакций, [math]m[/math] - длина транзакции(максимальная), [math]k[/math] - количество кластеров.
Основные вычисления восполняются в функции DeltaAdd/DeltaRemove: производится 1 сложение, не более [math]m[/math] сложений/вычитаний, 2 умножения, 2 деления, 2 возведения в степень и 1 сложение - итого [math]m + 8[/math] операций.
Операции выполняются для всех транзаций ([math]n[/math] штук) и для всех кластеров ([math]k[/math] штук). Итого выполняется [math]n*k*(m+8)[/math] операций.
В добавок к этому при добавлении/удалении транзакции к кластеру производится пересчет его характеристик: [math]m+2[/math] операции.
Из того можно сделать вывод, что оценка сложность алгоритма равна [math]O(n*k*m)[/math].
1.7 Информационный граф
На этапе инициализации при обработке каждой транзакции количество кластеров может как увеличиться, так и остаться неизменным. Это показано пунктирными линиями:
На этапе итерации функции DeltaAdd/DeltaRemove могут считать параллельно для каждой транзакции
1.8 Ресурс параллелизма алгоритма
Вычисление стоимости добавления/удаления транзакции, которые выполняются функциями DeltaAdd/DeltaRemove, происходит независимо для всех [math]k[/math] кластеров. Поэтому все вычисления можно производить параллельно. Таким образом сложность алгоритма с [math]O(n*k*m)[/math] понижается до [math]O(n*m)[/math].
1.9 Входные и выходные данные алгоритма
Входные данные:
[math]n[/math] транзакций длины [math]m[/math] и коэффициент отталкивания [math]r[/math]
Выходные данные:
метки классов для каждой транзакции в соответствии с проведенной кластеризацией(числовая последовательность длины [math]n[/math])
1.10 Свойства алгоритма
- Соотношение последовательной и параллельной сложности алгоритма определяется количеством кластеров: [math]\dfrac{O(n*k*m)}{O(n*m)} = k[/math]
- Вычислительная мощность алгоритма равна [math]\dfrac{nk(m+8) + m + 2}{nm + n + 1} \cong k[/math]
- Алгоритм не является устойчивым, так как результат работы зависит от порядка чтения транзакций и от текущего набора транзакций в кластере.
- Выполняется свойство сбалансированности операций между параллельными ветвями алгоритма, так как для каждой транзакции выполняются функции DeltaAdd/DeltaRemove, считающие стоимость добавления/удаления транзакции.
- Свойство детерминированности алгоритмов не выполняется, так как результат алгоритма зависит от порядка прохождения транзакций. Но если рассматривать транзакции как нумерованный список, то результат будет определен однозначно от запуска к запуску. Однако существует расширение алгоритма, обеспечивающее свойство детерминированности. [4].
- Так как алгоритм предназначен для кластеризации категориальных данных, то он практически неприменим для числовой кластеризации.
- Быстро работает даже для большого количества данных, обеспечивая при этом хорошее качество кластеризации
- Имеет простую реализацию
2 Программная реализация алгоритма
2.1 Особенности реализации последовательного алгоритма
2.2 Локальность данных и вычислений
2.3 Возможные способы и особенности параллельной реализации алгоритма
2.4 Масштабируемость алгоритма и его реализации
Проверка масштабируемости производилась с использованием стандарта MPI на суперкомпьютере "Ломоносов" с числом процессоров: 1,8,16,32,64. Результаты проверки масштабируемости приведены ниже на графике
2.5 Динамические характеристики и эффективность реализации алгоритма
2.6 Выводы для классов архитектур
2.7 Существующие реализации алгоритма
- http://weka.sourceforge.net/doc.stable/weka/clusterers/CLOPE.html - реализация в open source библиотеке для анализа данных WEKA(Waikato Environment for Knowledge Analysis) на языке Java
Также существуют пользовательские реализации алгоритма:
- https://github.com/infozor/php_mysql_clustering_clope - реализация алгоритма на PHP
- https://github.com/Tolsi/scala-clope - реализация алгоритма Scala
3 Литература
- ↑ Yang, Y., Guan, H., You. J. CLOPE: A fast and Effective Clustering Algorithm for Transactional Data In Proc. of SIGKDD’02, July 23-26, 2002, Edmonton, Alberta, Canada.
- ↑ Нейский И.М. Классификация и сравнение методов кластеризации.
- ↑ Павлин Н. Кластеризация категорийных данных: масштабируемый алгоритм CLOPE, https://basegroup.ru/community/articles/clope
- ↑ Li, Y., Le, J., Wang, M. Improving CLOPE’s Profit Value and Stability with an Optimized Agglomerative Approach. Algorithms 2015, 8, 380-394.