我有一个数组,其中包含许多 0 到 360 之间的值(如圆圈中的度数),但分布不均:
1,45,46,47,48,49,50,51,52,53,54,55,100,120,140,188,210,280,355
现在我需要将这些值减少到例如 4,但要尽可能均匀地分布值。
怎么做?
谢谢,扬
把数字放在一个圆圈上,就像一个时钟。现在构建一个逻辑十字,比如在 12、3、6 和 9 点钟。将 12 放在第一个数字上。现在找出最接近 3 点、6 点和 9 点的数字,并在第一个数字旁边记录这三个数字的距离之和。
通过顺时针旋转十字的顶部(12 点钟点)进行迭代,直到它与下一个数字完全对齐。再次测量最接近的数字与其他三个交叉点的距离,并将该分数记录在当前 12 点钟数字旁边。
重复直到你的 12 点一直旋转到原来的 3 点,此时你就完成了。分配给它的总和最低的数字决定了获胜的配置。
该解决方案可推广到任何值范围的 R和您希望将集合减少到的任意数量的最终点 N。“十字架”上的每个点彼此相距 R/N,您只需旋转直到十字架的顶部到达下一个手臂在原始位置的位置。因此,如果您想要 6 个点,您将有一个 6 点交叉,每个 60 度,而不是一个 4 点交叉,每个 90 度。如果您的范围不同,您仍然执行相同的操作。这样你就不需要物理时钟和交叉来实现这个算法:它适用于任何 R 和 N。
从 Perl 的角度来看,我对这个答案感到很糟糕,因为我没有设法在解决方案中包含任何美元符号。:)
使用聚类算法将数据划分为均匀分布的分区。然后从每个集群中获取一个随机值。如下$datafile
所示:
1 1
45 45
46 46
...
210 210
280 280
355 355
第一列是标签,第二列是数据。运行以下内容$K = 4
:
use strict; use warnings;
use Algorithm::KMeans;
my $datafile = $ARGV[0] or die;
my $K = $ARGV[1] or 0;
my $mask = 'N1';
my $clusterer = Algorithm::KMeans->new(
datafile => $datafile,
mask => $mask,
K => $K,
terminal_output => 0,
);
$clusterer->read_data_from_file();
my ($clusters, $cluster_centers) = $clusterer->kmeans();
my %clusters;
while (@$clusters) {
my $cluster = shift @$clusters;
my $center = shift @$cluster_centers;
$clusters{"@$center"} = $cluster->[int rand( @$cluster - 1)];
}
use YAML; print Dump \%clusters;
返回这个:
120: 120
199: 188
317.5: 355
45.9166666666667: 46
第一列是集群的中心,第二列是从该集群中选择的值。中心之间的距离应该根据期望最大化算法最大化。