Я хочу сгруппировать свои данные с пользовательской матрицей расстояний, а не со встроенными алгоритмами (например, евклидовыми). И, кажется, нет четкого способа сделать это.
Я попытался добавить часть своего кода в демо в проекте Smile. Также пытался сделать это с тестированием в моем проекте, вот кусок кода:
StringBuilder sb = new StringBuilder();
String line;
while ((line = vrpJsonFromFile.readLine()) != null) {
sb.append(line).append("\n");
}
JSONArray jsonArray = new JSONObject(sb.toString()).getJSONArray("services");
Double[][] data = new Double[jsonArray.length()][2];
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject address = jsonArray.getJSONObject(i).getJSONObject("address");
data[i][0] = Double.parseDouble(address.getString("lon"));
data[i][1] = Double.parseDouble(address.getString("lat"));
}
// here
Distance<Double[]> distance1 = (x, y) -> Math.sqrt(Math.pow(y[1]-x[1],2) + Math.pow(y[0]-x[0], 2));
CLARANS<Double[]> clarans = new CLARANS<>(data, distance1, 3);
System.out.println(clarans);
Этот код создает кластеризацию CLARANS с помощью алгоритма Евклида (см. строку ниже комментария //here). Я должен изменить его с помощью моей собственной матрицы расстояний, и я надеюсь, что в Smile есть способ сделать это.
Вы, вероятно, можете использовать
Distance<Integer> d = (i,j) -> matrix[i][j];
для кластеризации номеров объектов, а не их векторов.
Но, возможно, стоит взглянуть на ELKI вместо этого, который имеет предопределенные классы для матриц расстояний и использует оптимизированные представления для наборов объектов, а не использовать дорогостоящие коробочные Integer
, как в лямбде выше. Поскольку i
и j
представляют собой целые числа в коробках, для каждого вычисления расстояния требуется дополнительное косвенное обращение к памяти (и промахи кеша), что может сильно снизить производительность. Он также имеет лучший алгоритм FastCLARANS, а также FastPAM, которые предположительно в O(k) раз быстрее.