我有一个数组,其中包含0到360之间的许多值(如圆圈中的度数),但分布不均匀:
1,45,46,47,48,49,50,51,52,53,54,55,100,120,140,188,210,280,355
现在我需要将这些值减少到例如仅限4,但尽可能均匀分布值。
怎么做?
谢谢, 扬
答案 0 :(得分:3)
将数字放在圆圈上,就像时钟一样。现在构建一个逻辑交叉,比如在12点,3点,6点和9点。把12放在第一个数字。现在找到最接近3点,6点和9点的数字,并记录第一个数字旁边这三个数字距离的总和。
通过旋转十字架的顶部 - 12点钟点 - 顺时针旋转,直到它与下一个数字完全对齐为止。再次测量最接近的数字与其他三个交叉点的距离,并将该分数记录在当前12点的数字旁边。
重复直到你的12点钟一直旋转到原来的3点钟,此时你已经完成了。分配给它的最低总和中的任何一个确定获胜配置。
此解决方案适用于任何值范围R 和您希望将设置减少到的任何N个最终点。 “十字架”上的每个点都是相互远离的R / N,您只需旋转直到十字架的顶部到达下一个臂在原始位置的位置。因此,如果您想要6个点,那么您将拥有一个6角十字架,每个相隔60度,而不是每个相隔90度的四角十字架。如果您的范围不同,您仍然可以执行相同的操作。这样你就不需要物理时钟和交叉来实现这个算法:它适用于任何R和N.
从Perl的角度来看,我对这个答案感到很难过,因为我没有在解决方案中包含任何美元符号。 :)
答案 1 :(得分:1)
使用clustering algorithm将数据划分为均匀分布的分区。然后从每个群集中获取随机值。以下$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
第一列是群集的中心,第二列是该群集中的选定值。根据{{3}},中心与的距离应最大化。