アイテムを「均等に」配布するアルゴリズム


25

結果のリストが可能な限り「バランスの取れた」または「均等に分散」されるように、リストから値を分散するアルゴリズムを探しています(これらがそれを記述するための最良の方法であると確信していないため、引用符で...後で、結果が他の結果よりも良いかどうかを測定する方法を提供します)。

したがって、リストの場合:

[1, 1, 2, 2, 3, 3]

値を再配布した後の最良の結果の1つは次のとおりです。

[1, 2, 3, 1, 2, 3]

これと同じくらい良い結果が他にもあるかもしれません。もちろん、値のセットが不均一になると、より複雑になります。

これは、結果が他よりも優れているかどうかを測定する方法です。

  1. 各アイテムと同じ値を持つ次のアイテム間の距離を数えます。

  2. その距離のセットの標準偏差を計算します。分散が低いほど、より良い結果が得られます。

観察:

  • 距離を計算し、同じ値を持つアイテムを見つけることなくリストの最後に到達すると、リストの最初に戻ります。そのため、多くても同じアイテムが検出され、そのアイテムの距離はリストの長さになります。これは、リストが周期的であることを意味します。
  • 典型的なリストには、さまざまな数量で最大15個の異なる値を持つ最大50個のアイテムがあります。

そう:

  • 結果の[1, 2, 3, 1, 2, 3]場合、距離は[3, 3, 3, 3, 3, 3]であり、標準偏差は0;です。
  • 結果の[1, 1, 2, 2, 3, 3]場合、距離は[1, 5, 1, 5, 1, 5]であり、標準偏差は2;です。
  • これにより、最初の結果が2番目の結果よりも良好になります(偏差が小さいほど良い)。

これらの定義を考慮して、どのアルゴリズムまたは戦略を検索すべきかの手がかりを求めます。


少なくとも近似的に、パーティション問題(の最適化バリアント)を解決したいようです。おそらく多くのアルゴリズムがあります!
ラファエル

これを読み直して、すべての値の出現をカウントしてから値を周期的に配置すると、必ずしも最適なソリューションが得られないのはなぜですか?
ラファエル

回答:


8

同様の問題を調査しながらこの質問に出くわしました。成層を減らすための液体の最適な添加。私の解決策はあなたの状況にも当てはまるようです。

液体A、B、およびCを30、20、10の割合(つまり、Aの30単位、Bの20単位、およびCの10単位)で混合する場合、すべてを追加すると成層になります。 A、次にすべてのB、そしてすべてのCのようになります。小さなユニットをミキシングする方が良いでしょう。たとえば、シーケンス[A、B、A、C、B、A]で単一ユニットの追加を行います。それは完全に層化を防ぎます。

私がそれを見つけたのは、優先度キューを使用して、一種のマージとして扱うことです。追加を説明する構造を作成した場合:

MergeItem
    Item, Count, Frequency, Priority

頻度は「Nごとに1つ」として表されます。したがって、6回のうち3回追加されるAの頻度は2(6/3)です。

そして、最初に含まれるヒープを初期化します:

(A, 3, 2, 2)
(B, 2, 3, 3)
(C, 1, 6, 6)

次に、ヒープから最初のアイテムを削除して出力します。次に、カウントを1減らし、頻度による優先度を上げて、ヒープに追加します。結果のヒープは次のとおりです。

(B, 2, 3, 0)
(A, 2, 2, 4)
(C, 1, 6, 6)

次に、ヒープからBを削除し、出力して更新し、ヒープに追加し直します。

(A, 2, 2, 4)
(C, 1, 6, 6)
(B, 1, 3, 6)

そのように続けると、希望の混合物が得られます。カスタムコンパレーターを使用して、等しい優先度のアイテムがヒープに挿入されたときに、最も高い頻度の値(つまり、最も低い頻度)のアイテムが最初に順序付けられるようにします。

私は自分のブログで問題とその解決策のより完全な説明を書き、それを説明するいくつかの実用的なC#コードを提示しました。リスト内のアイテムの均等配布を参照してください。

コメント後に更新

私の問題はOPの問題に似ていると思うので、私の解決策は潜在的に有用だと思います。私は、OPの質問の観点から、私の回答をもっとフレーミングしないことをおpoびします。

私のソリューションは0、1、2ではなくA、B、Cを使用しているという最初の異論は、簡単に修正できます。それは単に命名法の問題です。「2つの1」ではなく「2つのA」について考えて発言する方が簡単でわかりやすいと思います。しかし、この議論のために、OPの命名法を使用するために、以下の出力を変更しました。

もちろん、私の問題は距離の概念を扱っています。「物を均等に広げる」場合は、距離が必要です。しかし、繰り返しますが、私の問題がOPの問題にどのように似ているかを適切に示さなかったことは、私の失敗でした。

OPが提供する2つの例を使用して、いくつかのテストを実行しました。あれは:

[1,1,2,2,3,3]  // which I converted to [0,0,1,1,2,2]
[0,0,0,0,1,1,1,2,2,3]

私の命名法では、それらはそれぞれ[2,2,2]および[4,3,2,1]として表されます。つまり、最後の例では、「タイプ0の4アイテム、タイプ1の3アイテム、タイプ2の2アイテム、およびタイプ3の1アイテム」です。

テストプログラムを実行し(すぐ下で説明します)、結果を投稿しました。OPからの入力がないため、私の結果が彼に似ているか、悪いか、良いかはわかりません。また、誰も投稿していないため、自分の結果を他の人の結果と比較することもできません。

ただし、このアルゴリズムは、液体を混合する際の成層化を排除するという私の問題に対する優れたソリューションを提供すると言えます。そして、それ OPの問題に対する合理的な解決策を提供するよう見えます。

以下に示す結果では、ブログエントリで詳述したアルゴリズムを使用し、初期優先度をに設定しFrequency/2、より頻繁な項目を優先するようにヒープ比較子を変更しました。変更されたコードがここに表示され、変更された行がコメント化されています。

private class HeapItem : IComparable<HeapItem>
{
    public int ItemIndex { get; private set; }
    public int Count { get; set; }
    public double Frequency { get; private set; }
    public double Priority { get; set; }

    public HeapItem(int itemIndex, int count, int totalItems)
    {
        ItemIndex = itemIndex;
        Count = count;
        Frequency = (double)totalItems / Count;
        // ** Modified the initial priority setting.
        Priority = Frequency/2;
    }

    public int CompareTo(HeapItem other)
    {
        if (other == null) return 1;
        var rslt = Priority.CompareTo(other.Priority);
        if (rslt == 0)
        {
            // ** Modified to favor the more frequent item.
            rslt = Frequency.CompareTo(other.Frequency);
        }
        return rslt;
    }
}

OPの最初の例でテストプログラムを実行すると、次のようになります。

Counts: 2,2,2
Sequence: 1,0,2,1,0,2
Distances for item type 0: 3,3
Stddev = 0
Distances for item type 1: 3,3
Stddev = 0
Distances for item type 2: 3,3
Stddev = 0

したがって、私のアルゴリズムは、すべてのカウントが等しいという些細な問題に対して機能します。

OPが投稿した2番目の問題については、次のようになりました。

Counts: 4,3,2,1
Sequence: 0,1,2,0,1,3,0,2,1,0
Distances for item type 0: 3,3,3,1
Stddev = 0.866025403784439
Distances for item type 1: 3,4,3
Stddev = 0.471404520791032
Distances for item type 2: 5,5
Stddev = 0
Distances for item type 3: 10
Stddev = 0
Standard dev: 0.866025403784439,0.471404520791032,0,0

私はそれを改善する明らかな方法を見ていません。アイテム0 [2,3,2,3]または2および3のその他の配置の距離を変更することができますが、それはアイテム1および/または2の偏差を変更します。 「最適」はこの状況です。頻度の高いアイテムまたは頻度の低いアイテムの偏差を大きくする方がよいでしょうか?

OPから他の問題がないため、私は彼の説明を使用して自分のいくつかを作成しました。彼は彼の投稿で言った:

典型的なリストには、さまざまな数量で最大15個の異なる値を持つ最大50個のアイテムがあります。

したがって、私の2つのテストは次のとおりです。

[8,7,6,5,5,4,3,3,2,2,2,1,1,1,1]  // 51 items, 15 types
[12,6,5,4,4,3,3,3,2,2,2,1,1]     // 48 items, 13 types

そして私の結果:

Counts: 8,7,6,5,5,4,3,3,2,2,2,1,1,1,1
Sequence: 0,1,2,3,4,5,7,6,0,1,2,8,9,10,4,3,0,1,5,2,0,1,3,4,6,7,14,11,13,12,0,2,5,1,0,3,4,2,8,10,9,1,0,7,6,5,3,4,2,1,0
Distances for item type 0: 8,8,4,10,4,8,8,1
Stddev = 2.82566363886433
Distances for item type 1: 8,8,4,12,8,8,3
Stddev = 2.76272565797339
Distances for item type 2: 8,9,12,6,11,5
Stddev = 2.5
Distances for item type 3: 12,7,13,11,8
Stddev = 2.31516738055804
Distances for item type 4: 10,9,13,11,8
Stddev = 1.72046505340853
Distances for item type 5: 13,14,13,11
Stddev = 1.08972473588517
Distances for item type 6: 17,20,14
Stddev = 2.44948974278318
Distances for item type 7: 19,18,14
Stddev = 2.16024689946929
Distances for item type 8: 27,24
Stddev = 1.5
Distances for item type 9: 28,23
Stddev = 2.5
Distances for item type 10: 26,25
Stddev = 0.5
Distances for item type 11: 51
Stddev = 0
Distances for item type 12: 51
Stddev = 0
Distances for item type 13: 51
Stddev = 0
Distances for item type 14: 51
Stddev = 0

2番目の例では:

Counts: 12,6,5,4,4,3,3,3,2,2,2,1,1
Sequence: 0,1,2,0,3,4,7,5,6,0,1,8,9,10,0,2,0,3,4,1,0,2,6,7,5,12,11,0,1,0,3,4,2,0,1,10,8,9,0,7,5,6,0,
4,3,2,1,0
Distances for item type 0: 3,6,5,2,4,7,2,4,5,4,5,1
Stddev = 1.68325082306035
Distances for item type 1: 9,9,9,6,12,3
Stddev = 2.82842712474619
Distances for item type 2: 13,6,11,13,5
Stddev = 3.44093010681705
Distances for item type 3: 13,13,14,8
Stddev = 2.34520787991171
Distances for item type 4: 13,13,12,10
Stddev = 1.22474487139159
Distances for item type 5: 17,16,15
Stddev = 0.816496580927726
Distances for item type 6: 14,19,15
Stddev = 2.16024689946929
Distances for item type 7: 17,16,15
Stddev = 0.816496580927726
Distances for item type 8: 25,23
Stddev = 1
Distances for item type 9: 25,23
Stddev = 1
Distances for item type 10: 22,26
Stddev = 2
Distances for item type 11: 48
Stddev = 0
Distances for item type 12: 48
Stddev = 0

@DWアップデートをご覧ください。私の問題がOPの問題にどのように似ているか、そしてアルゴリズムがOPの問題の解決策をどのように提供するかを示すと信じています。
ジムミッシェル

いい物!素晴らしいアップデートをありがとう。賛成。
DW

前に言ったように、非常に興味深い。アイデアのシンプルさが魅力的です。すべてを注意深く読む時間はありませんでした。実際のソリューションでは、元の質問の周期性を実際に考慮していますか?目的に合わせて調整する方法があるかもしれませんが、私は完全にはわかりません。
babou

@babou:結果からわかるように、距離の計算はラップアラウンドしますが、アルゴリズム自体はOPの問題の周期的な性質を具体的に考慮していません。また、アルゴリズムを適応させる方法も見当たりません。または、その点については、周期的な性質をどのように考慮するかが結果を改善するでしょう。すべてのカウントを2倍にすること(つまり[3,2,1]を[6,4,2]に変更すること)を検討することは興味深いですが、これは事実上同じことです。私の疑いは、アルゴリズムが同じ結果を生成することです。
ジムミッシェル

6

これはNPハードのように「臭い」ます。それでは、NPに問題がある場合はどうしますか?ヒューリスティックまたは近似アルゴリズムを投げるか、SATソルバーを使用します。

あなたの場合、絶対的な最適解が必要ない場合、合理的な出発点はシミュレーテッドアニーリングを試すことです。候補ソリューションを取得して近くの候補ソリューションに移動する自然な方法があります。リスト内の2つのアイテムをランダムに選択し、それらを交換します。シミュレーテッドアニーリングは、ソリューションの改善を繰り返し試みます。慣れていない場合は、シミュレーテッドアニーリングに関する多くのリソースを見つけることができます。ソリューションを少しずつ改善する(距離の標準偏差を減らす)ことを期待して、候補ソリューションに小さな変更を加える「ローカル移動」の他のセットを試すこともできます。

ttt2バツjバツjjt2

しかし、シミュレーテッドアニーリングから始めることをお勧めします。それがうまくいくかもしれないと思うので、それは私が試みる最初のことです。


あなたの提案は、これらの種類のスケジューリングの問題に対処する標準的な方法ですか?このための商用ソフトウェアがいくつかあると思います。彼らはどのようにそれを処理しますか?
babou

@babou、素晴らしい質問-私にはわからない!
DW

アルゴリズムの詳細をさらに開発しましたが、既存のアプリケーションでそれを使用することは非常に難しいと思います。実際、スケジューリングアプリケーションがこの種の問題に対処しているかどうかさえ疑問です。私はちょうど私がしたようにコメントとして以外、ここで質問をする方法を見ることができないので、私はSE.softwarerecsに関する情報を求めてきました。
babou 14

最適なソリューションは、NP困難であるかもしれません。しかし、非常に実行可能なソリューションはO(n log k)です。ここで、nはアイテムの総数、kはアイテムタイプの数です。私の答えとリンクされたブログ記事をご覧ください。
ジムミッシェル

2

ヒューリスティックアルゴリズムのスケッチ

この問題の正確な解決策はありません。しかし、Raphaelのコメントは、ヒューリスティックアルゴリズムが開発されたパーティションの問題のように見えるため、ヒューリスティックアプローチを試みます。これは、発見的アルゴリズムのスケッチにすぎません。

vn[1..n]ini

nvnvn/nv

v

n/nnmodnn/n

これがアルゴリズムの指針になります。

n

|n/nv|

これは、最初は非常に多く発生する非常に多くの値である場合があります。スロットを占有することによって作成される制約は、配置された値の数(?)に比例するため、実際には違いはないと思います。

最初に考慮される値は、制約なしで配置できます。次に、他の値は、標準偏差への寄与を最小化するように配置する必要がありますが、以前に配置された値によって解放されたスロットにのみ配置されます。

残りのスロットでの値の出現の配置は、2つの位置の間に同じ数の値を配置する計算をマージするために、動的プログラミングアルゴリズムを使用して実行できます。偏差の二乗和の最小値)。

v

j|n/njv|

次に、残りのスロットにシングルトン値を配置します。

これは一般的に合理的な解決策を提供するはずだと思いますが、それを証明する方法や最適な解決策とのギャップを推定する方法についてはまだわかりません。


私は、シングルトンを別にして、最も一般的なものから始めても、最も一般的なものから始めても関係ないという同じ印象を持っています。明らかに最高の結果をもたらした戦略は、発生順に値をソートし、最も発生する値から順番に配置することから始まります。これにより、当然シングルトンが最後まで残ります。
モラ14

vn/vV

10個の値[0, 0, 0, 0, 1, 1, 1, 2, 2, 3]とv を持つリストの場合、4最初の値110/3 = 3.33、vに最も近い)、次に210/2 = 5、次に近い)、次に010/4 = 2.5)を配置するということですか?または:「値vからの距離の平均偏差の減少」の例を挙げていただけますか?
モラ14

1
いいえ、反対です。あなたの例を挙げると、ポジショニングの順序は、平均距離2,5がv = 4から最も大きく逸脱するため最初にO、次に2、次に1、シングルトン3になります。---この戦略の説明の一部ですか?
babou 14

大丈夫です。このアイデアに沿って何かを試し、報告します。
モラ14

1

私はパーティーにとても遅れているように見えますが、誰かが再びこれに遭遇した場合に備えて投稿します。私の解決策は@babouのプラスに似ています。本日、組み込みシステムでスケジューリングの問題が発生し、このスレッドに至りました。私はCの問題に固有の実装を持っていますが、ここにPythonでより一般的なソリューションを投稿すると思いました(Cバージョンは、小さな固定サイズのスタックとメモリなしに制限しているという事実によって複雑になります割り当てなので、アルゴリズム全体をその場で実行します)。以下で使用されるアンチエイリアス手法は、2ビット色で画面上に線を描くために使用できるものです。このアルゴリズムは、Jim Mischelが使用する入力の標準偏差の合計を使用して測定した場合、その特定のソリューションよりも低いスコア(つまり、より良い)を達成します。

def generate(item_counts):
'''item_counts is a list of counts of "types" of items. E.g., [3, 1, 0, 2] represents
   a list containing [1, 1, 1, 2, 4, 4] (3 types of items/distinct values). Generate
   a new list with evenly spaced values.'''
# Sort number of occurrences by decreasing value.
item_counts.sort(reverse=True)
# Count the total elements in the final list.
unplaced = sum(item_counts)
# Create the final list.
placements = [None] * unplaced

# For each type of item, place it into the list item_count times.
for item_type, item_count in enumerate(item_counts):
    # The number of times the item has already been placed
    instance = 0
    # Evenly divide the item amongst the remaining unused spaces, starting with
    # the first unused space encountered.
    # blank_count is the number of unused spaces seen so far and is reset for each
    # item type.
    blank_count = -1
    for position in range(len(placements)):
        if placements[position] is None:
            blank_count += 1
            # Use an anti-aliasing technique to prevent bunching of values.
            if blank_count * item_count // unplaced == instance:
                placements[position] = item_type
                instance += 1
    # Update the count of number of unplaced items.
    unplaced -= item_count

return placements

の結果

Input counts: 8,7,6,5,5,4,3,3,2,2,2,1,1,1,1
Sum of stddev: 16.8 (vs. 22.3 via Jim Mischel)

Input of counts: 12,6,5,4,4,3,3,3,2,2,2,1,1
Sum of stddev: 18.0 (vs. 19.3 via Jim Mischel)

@moraesで指定された形式の入力が与えられた場合、Big Omega(n * log(n))ビットのメモリを使用してO(n)ステップでこの関数で使用可能な形式に変換できます(nはアイテムの数( 255個の要素を含むリストでは、繰り返しカウントで並列配列を保持することにより、255バイトを超える余分なバイトは必要ありません。または、O(1)の追加メモリを使用して、インプレースソートのペアを実行できます。

PS

import numpy
import collections

def evaluate(l):
    '''Given a distribution solution, print the sum of stddevs for each type in the solution.'''
    l2 = l * 2
    distances = [None] * len(l)
    distance_dict = collections.defaultdict(list)
    for i in range(len(l)):
        distances[i] = l2.index(l[i], i + 1) - i
        distance_dict[l[i]].append(l2.index(l[i], i + 1) - i)

    keys = list(distance_dict.keys())
    keys.sort()
    score = 0
    # Calculate standard deviations for individual types.
    for key in keys:
        sc = numpy.std(distance_dict[key])
        score += sc
    print('Stddev sum: ', score)

編集:このソリューションは反例による最適な出力を生成しないことを知っています。入力[6, 2, 1]生成[0, 1, 0, 0, 2, 0, 0, 1, 0]; より良い解決策は[0, 0, 1, 0, 2, 0, 0, 1, 0]です。


コードのコメントでアルゴリズムを説明し、プリアンブルでアルゴリズムの基礎を説明したと思います。
突進

アルゴリズムの背後にあるアイデアの自己完結型の説明と、アルゴリズムの簡潔な擬似コードを見たいと思います。現在、私が紹介テキストで見ているのは、(1)あなたのアプローチが@babouに似ていること、および(2)アンチエイリアス手法を使用していることです(なんとか)。また、ここで全員がPythonを読むわけではありません。いずれにせよ、それは古い答えですので、あなたがそれを改善したくない場合は理解していますが、私はこのサイトに対する私たちの期待に注目しています-あなただけでなく、未来と答える傾向があります。
DW

0

このアルゴリズムは、各整数が異なるカテゴリを表す整数の配列で機能します。カテゴリごとに個別の配列を作成します。たとえば、開始配列が[1、1、1、2、2、3]の場合、3つの配列[3]、[2、2]、[1、1、1]が作成されます。

そこから、2つの最小の配列(この例では[3]と[2,2])を再帰的に組み合わせ、主に数の比率に基づいて、小さな配列の要素の配置を2番目に小さい配列に配置します。大きいカテゴリと小さいカテゴリの出現回数。この例では、[2,3,2]になります。次に、この配列を小さな配列として使用し、残りの配列が1つだけになるまで、次に大きい配列に結合します。

<?php
/**
 *This will separete the source array into separate arrays for each category
 */
function splitArrayByCategory($source) {

    //  index is the category, value is the tally
    $categoryCounts  = array_count_values($source);

    // Sort that list, keep index associations
    asort($categoryCounts);

    // build separate arrays for each category
    // index = order, smaller index = smaller category count
    // value = array of each category
    $separated = array();
    foreach ($categoryCounts as $category => $tally)
        $separated[] = array_fill(0, $tally, $category);

    return $separated;
}

/**
 * Will take the array of arrays generated by splitArrayByCategory, and merge
 * them together so categories are evenly distributed
 */
function mergeCategoryArrays($categoryArray) {

    // How many entries are there, for the smallest & second smallest categories
    $smallerCount = count($categoryArray[0]);
    $largerCount  = count($categoryArray[1]);

    // Used to determine how much space there should be between these two categories
    $space = $largerCount/$smallerCount;

    // Merge the array of the smallest category into the array of the second smallest
    foreach ($categoryArray[0] as $domIndex => $domain) {
        // Where should we splice the value into the second array?
        $location = floor($domIndex*$space+$domIndex+($space/2));
        // actually perform the splice
        array_splice($categoryArray[1], $location, 0, $domain);
    }

    // remove the smallest domain we just spliced into the second smallest
    unset($categoryArray[0]);

    // reset the indexes
    $categoryArray = array_values($categoryArray);

    // If we have more than one index left in the categoryArray (i.e. some things
    // still need to get merged), let's re-run this function,
    if (count($categoryArray)>1)
        $categoryArray = mergeCategoryArrays($categoryArray);

    return $categoryArray;
}

// The sample list we're working with.
// each integer represents a different category
$listSample = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,6,6,7,7,7,7];

// Split the sample list into separate arrays for each category
$listSplitByCategory = splitArrayByCategory($listSample);

// If there are not at least two categories, what's the point?
if (count($listSplitByCategory) < 2) throw new Exception("You need at least two categories");

// perform the actual distribution of categories.
$listEvenlyDistributed = mergeCategoryArrays($listSplitByCategory)[0];

// Display the array before and after the categories are evenly distributed
for ($i=0; $i<count($listSample); $i++) {
    print $listSample[$i].",";
    print $listEvenlyDistributed[$i]."\n";
}

2
これはコーディングサイトではありません。コードのみの回答を投稿しないでください。代わりに、答えの背後にあるアイデアを説明し、アルゴリズムの簡潔な擬似コードを提供してください。
DW

コンピュータサイエンスへようこそ!気づかなかったり、しばらく忘れてしまった場合に備えて、特定の言語でコードを読むことは、たとえコードが自分で書かれたとしても、私たちができる最も難しいタスクの1つです。これは、このサイトで実際のコードをあまり評価していない理由の一部です。もちろん、すぐに実行したり、きらめくことができる実際の作業コードはすべて感謝しています。
Apass.Jack

説明があります。コメント付きのデモコード内。これは、APLのような古風な構文ではなく、疑似コードに十分に近いわかりやすい構文です。私の説明が等幅フォントではなかったら助けになるでしょうか?
vtim

はい。それは役立ちます。誰もがPHPを読んでいるわけではありませんし、コメントとは何か(おそらくストローマンの引数かもしれません)を判断したり、単にコードのブロックを読んで解釈したりすることはできませんが、先頭に含めたアイデアを読んで、それはすべてを伝えます。私から+1。あなたのコードはきれいで文書化されていますが、私たちは単にコーディングサイトではないので、ここではテキストによる説明が重要です。編集していただきありがとうございます。

-1

ANSI Cコード

このコードは、方向ベクトル(v1、v2、...、vi、... vn)で原点を通過するn次元空間(nはカテゴリの数)の直線を想像することで機能します。viはカテゴリーiのアイテム。原点から開始する目的は、線に最も近い点を見つけることです。例[0 0 0 0 0 1 1 1 2 2 2 3]を使用すると、結果[0 1 2 0 3 1 0 2 0 1 2 0]が生成されます。Lungjの例[0 0 0 0 0 0 1 1 2]を使用すると、[0 1 0 0 2 0 0 1 0]が得られます。これは、Lungjの結果とまったく同じです。

アルゴリズムは、整数演算のみを使用し、各ポイントからラインまでの距離間のデルタのみを考慮することにより、より効率的になります。

#define MAXCATEGORIES 100

int main(){int i = 0; int j = 0; int catsize = 0; int vector [MAXCATEGORIES]; int point [MAXCATEGORIES]; intカテゴリ= 0; int totalitems = 0; int best = 0; long d2 = 0L; long vp = 0L; long v2 = 0L; 長いデルタ= 0L; ロングベータ= 0L;

printf("Enter the size of each category (enter 0 to finish):\r\n");
do
{
    catsize = 0;
    #ifdef _MSVC_LANG
            scanf_s("%d", &catsize);
    #else
            scanf("%d", &catsize)
    #endif
    if (catsize > 0)
    {
        vector[categories] = catsize;
        totalitems += catsize;
        categories++;
    }
} while (catsize > 0);

for (i = 0; i < categories; i++)
{
    v2 += vector[i] * vector[i];
    point[i] = 0;
}

for (i = 0; i < totalitems; i++)
{
    for (j = 0; j < categories; j++)
    {
        delta = (2 * point[j] + 1)*v2 - (2 * vp + vector[j])*vector[j];
        if (j == 0 || delta < beta)
        {
            best = j;
            beta = delta;
        }
    }
    point[best]++;
    vp += vector[best];
    printf("%c ", best + '0');  // Change '0' to 'A' if you like letters instead
}
return 0;

}


1
サイトへようこそ!フォーマットに関しては、システムがマークアップを正しく取得できるように、コードの各行を4つのスペースでインデントする必要があります。一般に、質問への回答として大きなコードブロックを探しているわけではありません。特に、データ入力ルーチンはここに何も追加していません。投稿の上部に説明がありますが、それを拡張してコードを削減する方が良いでしょう。
デヴィッドリチャービー

これはコーディングサイトではありません。コードのみの回答を投稿しないでください。代わりに、答えの背後にあるアイデアを説明し、アルゴリズムの簡潔な擬似コードを提供してください。
DW

-1

私の解決策:

    vc = train['classes'].value_counts()
    vc = dict(sorted(vc.items()))
    df = pd.DataFrame()
    train['col_for_sort'] = 0.0

    i=1
    for k,v in vc.items():
        step = train.shape[0]/v
        indent = train.shape[0]/(v+1)
        df2 = train[train['classes'] == k].reset_index(drop=True)
        for j in range(0, v):
        df2.at[j, 'col_for_sort'] = indent + j*step + 0.0001*i   
    df= pd.concat([df2,df])
    i+=1

    train = df.sort_values('col_for_sort', ascending=False).reset_index(drop=True)
    del train['col_for_sort']

アルゴリズムを記述するために、擬似コードを(いくつかの必要なコメントとともに)使用してください。
xskxzr

これはコーディングサイトではありません。コードのみの回答を投稿しないでください。代わりに、答えの背後にあるアイデアを説明し、アルゴリズムの簡潔な擬似コードを提供してください。
DW
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.