Как получить равномерно распределенный образец из значений массива Perl?

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

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

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

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

Спасибо Ян

2 ответа

Положите цифры по кругу, как часы. Теперь создайте логический крест, скажем, в 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

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

Другие вопросы по тегам