Как получить равномерно распределенную выборку из значений массива Perl? - PullRequest
3 голосов
/ 23 ноября 2010

У меня есть массив, содержащий много значений от 0 до 360 (как градусы по кругу), но распределен неравномерно:

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

Теперь мне нужно уменьшить эти значения, например. Только 4, но как можно более равномерно распределенные значения.

Как это сделать?

Спасибо, Jan

Ответы [ 2 ]

3 голосов
/ 23 ноября 2010

Поместите числа в круг, как часы.Теперь создайте логический крест, скажем, в 12, 3, 6 и 9 часов.Поставьте 12 на первое число.Теперь найдите, какие числа будут ближайшими к 3, 6 и 9 часам, и запишите сумму расстояний этих трех чисел рядом с первым числом.

Выполните итерацию, вращая верхнюю часть вашего креста -12 часов - по часовой стрелке, пока точно не совпадет со следующим номером.Снова измерьте расстояние до ближайших чисел к каждой из трех других точек пересечения и запишите этот результат рядом с текущим 12-часовым номером.

Повторяйте, пока не достигнете того, что ваш 12-часовой поворот повернут полностью к исходным 3-м часам, после чего вы закончите.Независимо от того, какое число назначено наименьшей сумме, оно определяет конфигурацию выигрыша.

Это решение обобщает любой диапазон значений R и любого числа N конечных точек, до которого вы хотите уменьшить набор.Каждая точка на «кресте» находится на расстоянии R / N друг от друга, и вам нужно только вращать, пока вершина вашего креста не достигнет того места, где следующий рычаг находился в исходном положении.Таким образом, если вы хотите получить 6 точек, у вас будет 6-точечный крест, каждый с шагом 60 градусов, а не 4-точечный крест с углом 90 градусов.Если ваш диапазон отличается, вы все равно выполняете ту же операцию.Таким образом, вам не нужны физические часы и кросс для реализации этого алгоритма: он работает для любых R и N.

Мне не нравится этот ответ с точки зрения Perl, так как мне не удалось включитьлюбые знаки доллара в решении.:)

1 голос
/ 23 ноября 2010

Используйте алгоритм кластеризации , чтобы разделить ваши данные на равномерно распределенные разделы.Затем возьмите случайное значение из каждого кластера.Следующий $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

Первый столбец - центр кластера, второй - выбранное значение этого кластера.Расстояние между центрами должно быть максимально увеличено в соответствии с алгоритмом максимизации ожидания .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...