2010-11-23 78 views
3

我有一个数组包含0到360之间的许多值(如圆度),但分布不均匀:如何从Perl数组值中获得均匀分布的示例?

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

现在我需要将这些值减小到eg只有4个,但尽可能均匀的分布值。

如何做到这一点?

感谢, 扬

+1

你需要更仔细的话你的问题。目前它没有什么意义。 – singingfish 2010-11-23 02:12:18

回答

3

放在一个圆圈的数字,就像一个时钟。现在建立一个逻辑交叉点,例如12点,3点,6点和9点。把12放在第一个数字。现在找到哪些数字最接近3,6和9点,并记录第一个数字旁边的三个数字的距离的总和。

通过顺时针旋转十字的顶端 - 12点钟的点 - 直到它与下一个数字完全对齐为止。再次测量最近的数字与其他三个交叉点的距离,并将该分数记录在当前12点的数字旁边。

重复,直到你到达12点钟已经一路旋转至原来的3点钟,此时你就大功告成了。无论哪个号码具有分配给它的最低总和,都决定了获胜配置。

该解决方案推广到任何值的范围R 您希望减少设置的任何数量的N个最终点。在“跨界”每个点是R/N远离彼此,而你只需要旋转,直到你的十字架的顶部到达下一个手臂是在原来的位置。所以如果你想要6分,你会有一个六角十字,每相隔60度,而不是四角十字,相隔90度。如果您的范围不同,您仍然执行相同的操作。这样,你不需要物理时钟和交叉来实现这个算法:它可以用于任何R和N.

我感到很难从Perl的角度来看这个答案,因为我已经没有设法包括任何美元签署解决方案。 :)

+1

第1步:从Perl数组值中获取均匀分布的示例。第2步。 ???。第3步。** $$$ ** – 2010-11-23 06:25:28

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 

第一列是群集的中心,第二个是从群集中的选择的值。各中心的彼此距离应根据Expectation Maximization algorithm最大化。