在新的2D数组中排序2D数组(K-menas聚类)Java

时间:2020-06-17 18:39:44

标签: java sorting multidimensional-array k-means

作为输入,我有二维数组PointXY [] []簇,如下所示:

[[23.237633,53.78671], [69.15293,17.138134], [23.558687,45.70517]] . . .
[[47.851738,16.525734], [47.802097,16.689285], [47.946404,16.732542]]
[[47.89601,16.638218], [47.833263,16.478987], [47.88203,16.45793]]
[[47.75438,16.549816], [47.915512,16.506475], [47.768547,16.67624]]
.
.
.

所以数组中的元素属于PointXY []类型,定义如下

public PointXY(float x, float y) { 
              this.x = x;
              this.y = y;  
          }

我想做的是对输入簇进行排序,然后将其写入数组PointXY [] [] clustersSorted中,以便将簇中的每个PointXY(第一行除外)与第一行的每个值进行比较。 换句话说,下面图片中蓝色设置的元素将与红色圈出的每个值进行比较。 因此,我想比较2行之后的每个值与第一行中的每个值。

Picture1

通过调用Euclidian函数完成比较。

public double euclidian(PointXY other) {
              return Math.sqrt(Math.pow(this.x - other.x, 2)
                 + Math.pow(this.y - other.y, 2));
     }

输出应该是相同类型的2D数组,但是在每个红色圆圈点下(在输出数组中的相同位置处都保持相同)应该是蓝色部分中距红色圆圈值最近(按欧几里德距离)的点。

Picture2

这是K-Means聚类的数据结构,因此每个聚类是一列(绿色圆圈),第一个点是聚类的中心(红色圆圈),列中的所有其他点(黄色圆圈)是分配给中心的点。

所以问题是如何遍历输入数组簇,比较所描述的值并将它们写入数组簇中。

编辑: 我想计算蓝色圆圈组中每个点与红色圆圈中每个值之间的欧几里得距离。然后根据最小欧氏距离对它们进行排序。因此,在输出数组簇中,从蓝色圆圈中选出的每个点都将位于红色圆圈中的最近点之下。

3 个答案:

答案 0 :(得分:0)

创建大小为[n] [(n-1)* n]的临时浮点数/双精度数组,其中输入矩阵的大小为[n] [n-1]。

计算矩阵下部所有点与第一行中所有点的欧式距离,并将它们存储在临时数组中的相应位置。

为每个临时子数组创建一个副本。

对副本执行任何排序操作,最好是选择排序,因为您只需要对数组进行部分排序,直到找到最低的n-1个元素。

最后,创建一个大小为[n] [n-1]的新输出数组,将最低欧氏距离与其点对应,并在下面存储(n-1)个点的已排序(n-1)个元素组它们最接近的参考点。

答案 1 :(得分:0)

查看另一个答案:Grouping all points starting from the second row by the nearest center point from the first row


要按列对对象的二维数组进行排序,您可以先转置这个数组并对每一行进行排序,然后将它转置回来。要使用自定义比较器按照与第一个元素的距离对从第二个元素开始的一行元素进行排序 - 您可以使用 Arrays.sort(T[],int,int,Comparator) 方法:

int m = 4;
int n = 3;
PointXY[][] clusters = {
        {new PointXY(23.237633, 53.78671),
                new PointXY(69.15293, 17.138134),
                new PointXY(23.558687, 45.70517)},
        {new PointXY(47.851738, 16.525734),
                new PointXY(47.802097, 16.689285),
                new PointXY(47.946404, 16.732542)},
        {new PointXY(47.89601, 16.638218),
                new PointXY(47.833263, 16.478987),
                new PointXY(47.88203, 16.45793)},
        {new PointXY(47.75438, 16.549816),
                new PointXY(47.915512, 16.506475),
                new PointXY(47.768547, 16.67624)}};
// transpose a matrix
PointXY[][] transposed = new PointXY[n][m];
IntStream.range(0, n).forEach(i ->
        IntStream.range(0, m).forEach(j ->
                transposed[i][j] = clusters[j][i]));
// sort each line starting from the second
// element by the distance from the first element
Arrays.stream(transposed).forEach(cluster ->
        Arrays.sort(cluster, 1, cluster.length,
                Comparator.comparingDouble(point ->
                        Math.sqrt(Math.pow(cluster[0].x - point.x, 2)
                                + Math.pow(cluster[0].y - point.y, 2)))));
// transpose a matrix back
PointXY[][] clustersSorted = new PointXY[m][n];
IntStream.range(0, m).forEach(i ->
        IntStream.range(0, n).forEach(j ->
                clustersSorted[i][j] = transposed[j][i]));
// output
Arrays.stream(clustersSorted).map(Arrays::toString).forEach(System.out::println);
[23.237633,53.78671, 69.15293,17.138134, 23.558687,45.70517]
[47.75438,16.549816, 47.915512,16.506475, 47.768547,16.67624]
[47.89601,16.638218, 47.833263,16.478987, 47.946404,16.732542]
[47.851738,16.525734, 47.802097,16.689285, 47.88203,16.45793]

PointXY 应如下所示:

public class PointXY {
    double x, y;

    public PointXY(double x, double y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return x + "," + y;
    }
}

答案 2 :(得分:0)

查看另一个答案:Sorting a 2d array of objects by columns starting from the second row and transposing an array


构建排序集群。第一行是中心点。其他点按最近的中心分组。在这种情况下,所有点都按第二个中心点分组:

PointXY[][] clusters = {
        {new PointXY(23.237633, 53.78671),
                new PointXY(69.15293, 17.138134),
                new PointXY(23.558687, 45.70517)},
        {new PointXY(47.851738, 16.525734),
                new PointXY(47.802097, 16.689285),
                new PointXY(47.946404, 16.732542)},
        {new PointXY(47.89601, 16.638218),
                new PointXY(47.833263, 16.478987),
                new PointXY(47.88203, 16.45793)},
        {new PointXY(47.75438, 16.549816),
                new PointXY(47.915512, 16.506475),
                new PointXY(47.768547, 16.67624)}};
// array of a center points
PointXY[] centers = clusters[0];

PointXY[][] clustersSorted = Arrays
        // iterate over array of center points
        .stream(centers)
        // for each center point
        .map(center -> Stream.of(center, Arrays
                // iterate over array of clusters starting from the second row
                .stream(clusters, 1, clusters.length)
                // stream over the full array
                .flatMap(Arrays::stream)
                // filter nearest points to the current center point
                .filter(point -> Arrays
                        // iterate over array of center points
                        .stream(centers)
                        // sort by euclidean distance from current point
                        .sorted(Comparator.comparingDouble(centerXY ->
                                Math.sqrt(Math.pow(centerXY.x - point.x, 2)
                                        + Math.pow(centerXY.y - point.y, 2))))
                        // find nearest center point to the current point
                        .findFirst()
                        // check this center point is the current center point
                        .get() == center)
                // array of the nearest points to this center point
                .toArray(PointXY[]::new))
                // center point + array of its nearest points
                .flatMap(element -> element instanceof PointXY ?
                        Stream.of((PointXY) element) :
                        Arrays.stream((PointXY[]) element))
                // sorted cluster
                .toArray(PointXY[]::new))
        // sorted array of clusters
        .toArray(PointXY[][]::new);
// output
Arrays.stream(clustersSorted).map(Arrays::toString).forEach(System.out::println);
[23.237633,53.78671]
[69.15293,17.138134, 47.851738,16.525734, 47.802097,16.689285, 47.946404,16.732542, 47.89601,16.638218, 47.833263,16.478987, 47.88203,16.45793, 47.75438,16.549816, 47.915512,16.506475, 47.768547,16.67624]
[23.558687,45.70517]

PointXY 应如下所示:

public static class PointXY {
    double x, y;

    public PointXY(double x, double y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return x + "," + y;
    }
}