Пользовательская метрика расстояния для DBSCAN в Apache Commons Math (v3.1 против v3.6)

Я хочу использовать Apache Commons Math's DBSCANClusterer<T extends Clusterable> выполнить кластеризацию, используя алгоритм DBSCAN, но с пользовательской метрикой расстояния, поскольку мои точки данных содержат нечисловые значения. Кажется, что это было легко достижимо в старой версии (обратите внимание, что полное имя этого класса org.apache.commons.math3.stat.clustering.DBSCANClusterer<T> тогда как это org.apache.commons.math3.ml.clustering.DBSCANClusterer<T> для текущей версии), которая теперь устарела. В старой версии Clusterable взял бы тип-параметр, T описание типа точек данных, которые кластеризуются, и расстояние между двумя точками будет определяться реализацией Clusterable.distanceFrom(T) Например:

class MyPoint implements Clusterable<MyPoint> {
    private String someStr = ...;
    private double someDouble = ...;

    @Override
    public double distanceFrom(MyPoint p) {
        // Arbitrary distance metric goes here, e.g.:
        double stringsEqual = this.someStr.equals(p.someStr) ? 0.0 : 10000.0;
        return stringsEqual + Math.sqrt(Math.pow(p.someDouble - this.someDouble, 2.0)); 
    }
}

В текущем выпуске Clusterable больше не параметризован. Это означает, что нужно придумать способ представления своих (потенциально не числовых) точек данных как double[] и вернуть это представление из getPoint() Например:

class MyPoint implements Clusterable {
    private String someStr = ...;
    private double someDouble = ...;

    @Override
    public double[] getPoint() {
        double[] res = new double[2];
        res[1] = someDouble; // obvious
        res[0] = ...; // some way of representing someStr as a double required
        return res;
    }
}

А затем обеспечить реализацию DistanceMeasure который определяет пользовательскую функцию расстояния с точки зрения double[] представления двух сравниваемых точек, например:

class CustomDistanceMeasure implements DistanceMeasure {
    @Override
    public double compute(double[] a, double[] b) {
        // Let's mimic the distance function from earlier, assuming that
        // a[0] is different from b[0] if the two 'someStr' variables were
        // different when their double representations were created.
        double stringsEqual = a[0] == b[0] ? 0.0 : 10000.0;
        return stringsEqual + Math.sqrt(Math.pow(a[1] - b[1], 2.0));
    }
}

Мои точки данных имеют форму (целое, целое, строка, строка):

class MyPoint {
    int i1;
    int i2;
    String str1;
    String str2;
}

И я хочу использовать функцию / метрику расстояния, которая по существу говорит "если str1 и / или str2 отличаются для MyPoint mpa а также MyPoint mpb максимальное расстояние, в противном случае это евклидово расстояние между целыми числами ", как показано в следующем фрагменте:

class Dist {
    static double distance(MyPoint mpa, MyPoint mpb) {
        if (!mpa.str1.equals(mpb.str1) || !mpa.str2.equals(mpb.str2)) {
            return Double.MAX_VALUE;
        }
        return Math.sqrt(Math.pow(mpa.i1 - mpb.i1, 2.0) + Math.pow(mpa.i2 - mpb.i2, 2.0));
    }
}

Вопросы:

  1. Как я представляю String как double чтобы включить вышеуказанную метрику расстояния в текущем выпуске (v3.6.1) Apache Commons Math? String.hashCode() недостаточно, поскольку коллизии хеш-кода могут привести к тому, что разные строки будут считаться равными. Это кажется неразрешимой проблемой, поскольку я по сути пытаюсь создать уникальное отображение из бесконечного набора строк в конечный набор числовых значений (64 бит double).
  2. Поскольку (1) кажется невозможным, я неправильно понимаю, как использовать библиотеку? Если да, разве я ошибся?
  3. Является ли моей единственной альтернативой использование устаревшей версии для такого типа метрики расстояния? Если да, (3а), почему дизайнеры решили сделать библиотеку менее общей? Возможно, в пользу скорости? Возможно, чтобы избавиться от самореференции в class MyPoint implements Clusterable<MyPoint> что некоторые могут считать плохим дизайном? (Я понимаю, что это может быть слишком самоуверенным, поэтому, пожалуйста, не обращайте на это внимания, если это так). Для экспертов по математике: (3b) какие недостатки есть в использовании устаревшей версии, кроме прямой совместимости (устаревшая версия будет удалена в 4.0)? Это медленнее? Возможно, даже неправильно?

Примечание. Мне известно об ELKI, который, по-видимому, популярен среди пользователей SO, но он не соответствует моим потребностям, поскольку продается как инструмент командной строки и графического интерфейса пользователя, а не как библиотека Java для включения в сторонние приложения.:

Вы даже можете встроить ELKI в свое приложение (если вы принимаете лицензию AGPL-3), но в настоящее время мы (пока) не рекомендуем это делать, поскольку API по-прежнему существенно меняется. [...]

ELKI не предназначен для встраиваемой библиотеки. Его можно использовать, но он не предназначен для такого использования. У ELKI есть множество опций и функциональных возможностей, и это имеет свою цену, как во время выполнения (хотя он может легко превзойти использование памяти R и Weka, например!), Так и, в частности, в сложности кода.

ELKI был разработан для исследования алгоритмов интеллектуального анализа данных, а не для облегчения их включения в произвольные приложения. Вместо этого, если у вас есть конкретная проблема, вы должны использовать ELKI, чтобы выяснить, какой подход работает хорошо, а затем переопределить этот подход оптимизированным образом для вашей проблемы (возможно, даже в C++, чтобы еще больше уменьшить память и время выполнения).

0 ответов

Другие вопросы по тегам