如何从Perl数组值中获取均匀分布的样本?

时间:2010-11-23 02:07:08

标签: arrays perl evenly

我有一个数组,其中包含0到360之间的许多值(如圆圈中的度数),但分布不均匀:

1,45,46,47,48,49,50,51,52,53,54,55,100,120,140,​​188,210,280,355

现在我需要将这些值减少到例如仅限4,但尽可能均匀分布值。

怎么做?

谢谢, 扬

2 个答案:

答案 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}},中心与的距离应最大化。