0 から 360 までの多くの値 (円の角度など) を含む配列がありますが、不均一に分布しています。
1,45,46,47,48,49,50,51,52,53,54,55,100,120,140,188,210,280,355
ここで、これらの値をたとえば 4 のみに減らす必要がありますが、できるだけ均等に分散された値にする必要があります。
どうやってするか?
ありがとう、ヤン
時計のように丸に数字を並べます。ここで、12 時、3 時、6 時、9 時の位置に論理的な十字を作成します。最初の数字に 12 を入れます。次に、3 時、6 時、9 時の位置に最も近い数字を見つけ、最初の数字の横にこれら 3 つの数字の距離の合計を記録します。
十字の上部 (12 時の位置) を時計回りに回転させて、次の数字と正確に一致するまで繰り返します。もう一度、他の 3 つのクロスポイントのそれぞれに最も近い数字がどれだけ離れているかを測定し、この現在の 12 時の数字の隣にそのスコアを記録します。
12 時の位置が元の 3 時の位置まで完全に回転するまで繰り返します。割り当てられた合計が最も低い番号が、勝者の構成を決定します。
このソリューションは、値 Rの任意の範囲と、セットを減らしたい最終ポイントの任意の数 N に一般化されます。「クロス」の各ポイントは互いに R/N 離れており、クロスの上部が次のアームが元の位置にあった場所に到達するまで回転するだけです。したがって、6 点が必要な場合は、90 度ごとに 4 点の十字ではなく、60 度ごとに 6 点の十字を作成します。範囲が異なる場合でも、同じ種類の操作を行います。そうすれば、このアルゴリズムを実装するために物理的なクロックとクロスは必要ありません。任意の R と N で機能します。
ソリューションにドル記号を含めることができなかったので、Perl の観点からこの回答については申し訳ありません。:)
クラスタリング アルゴリズムを使用して、データを均等に分散されたパーティションに分割します。次に、各クラスターからランダムな値を取得します。次$datafile
のようになります。
1 1
45 45
46 46
...
210 210
280 280
355 355
最初の列はタグ、2 番目の列はデータです。で次を実行します$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
最初の列はクラスターの中心で、2 番目の列はそのクラスターから選択された値です。中心同士の距離は、期待値最大化アルゴリズムに従って最大化する必要があります。