Öğeleri “eşit bir şekilde” dağıtacak algoritma


25

Değerleri bir listeden dağıtmak için bir algoritma arıyorum, ki sonuçta elde edilen liste olabildiğince "dengeli" veya "eşit olarak dağıtılmış" (tırnak işaretleri halinde) çünkü bunları tanımlamanın en iyi yolu olduğundan emin değilim ... sonra bir sonucun diğerinden daha iyi olup olmadığını ölçmek için bir yol sağlayacağım).

Yani, liste için:

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

Değerleri yeniden dağıttıktan sonra en iyi sonuçlardan biri şudur:

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

Bunun kadar iyi olan başka sonuçlar olabilir ve elbette bu, daha az üniform bir değerler kümesiyle daha da karmaşıklaşıyor.

Bir sonucun diğerinden daha iyi olup olmadığını ölçmek için bu:

  1. Her bir madde ile bir sonraki ürün arasındaki mesafeleri aynı değerde sayınız.

  2. Bu mesafeler kümesi için standart sapmayı hesaplayın. Düşük dağılım, daha iyi sonuç anlamına gelir.

Gözlemler:

  • Bir mesafe hesaplanırken aynı değere sahip bir öğe bulunmadan listenin sonuna ulaşılır, listenin başına geri döneriz. Böylece, en fazla, aynı madde bulunacak ve o maddenin uzaklığı listenin uzunluğu olacaktır. Bu, listenin döngüsel olduğu anlamına gelir ;
  • Tipik bir liste, farklı miktarlarda ~ 15 farklı değerde ~ 50 maddeye sahiptir.

Yani:

  • Sonuç olarak [1, 2, 3, 1, 2, 3], mesafeler [3, 3, 3, 3, 3, 3]ve standart sapma 0;
  • Sonuç olarak [1, 1, 2, 2, 3, 3], mesafeler [1, 5, 1, 5, 1, 5]ve standart sapma 2;
  • İlk sonucu ikinciden daha iyi yapan (düşük sapma iyidir).

Bu tanımlara bakıldığında, hangi algoritmaları veya stratejileri aramam gerektiğine dair bir ipucu istiyorum.


En azından yaklaşık olarak, Bölümleme (optimizasyon varyantı) problemini çözmek istiyormuş gibi görünüyorsunuz . Bunun için muhtemelen pek çok algoritma var!
Raphael

Bunu tekrar okudum, neden tüm değerlerin oluşumunu sayıp sonra döngüsel olarak değerleri yerleştirmek her zaman en uygun çözümü vermiyor?
Raphael

Yanıtlar:


8

Benzer bir problemi araştırırken bu soruyla karşılaştım: tabakalaşmayı azaltmak için optimum sıvı ilavesi. Çözümüm sizin durumunuz için de geçerli olacak gibi görünüyor.

A, B ve C sıvılarını 30,20,10 (30 birim A, 20 birim B ve 10 birim C) oranında karıştırmak istiyorsanız, hepsini ekleyin. A, sonra tüm B ve sonra tüm C. Küçük birimleri karıştırmaktan daha iyi olursunuz. Örneğin, [A, B, A, C, B, A] dizisindeki tek birimli eklemeler yapın. Bu tamamen tabakalaşmayı önleyecektir.

Bunu yapmamın yolu, öncelik sırasını kullanarak bir çeşit birleştirme gibi davranmak. Eklemeleri tanımlamak için bir yapı oluşturursam:

MergeItem
    Item, Count, Frequency, Priority

Frekans "her N bir" olarak ifade edilir. Öyleyse altı defadan üçüne eklenen A, 2 (6/3) sıklığına sahiptir.

Ve başlangıçta içeren bir öbek başlat:

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

Şimdi ilk öğeyi öbekten kaldırıyorum ve çıkarıyorum. Ardından sayısını 1 azaltın ve Önceliği Frekansla artırın ve tekrar yığına ekleyin. Sonuçta ortaya çıkan yığın:

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

Ardından, B'yi yığından kaldırın, çıktılayın ve güncelleyin, ardından yığına geri ekleyin:

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

Bu şekilde devam edersem, istenen karışımı elde ederim. Yığına eşit Öncelikli öğeler eklendiğinde, ilk önce en yüksek Frekans değerine sahip olan (yani en az sıklık) sipariş verilmesini sağlamak için özel bir karşılaştırıcı kullanırım.

Blogumda sorunun ve çözümün daha ayrıntılı bir tanımını yazdım ve onu gösteren bazı çalışma C # kodları sundum. Bkz . Listedeki öğeleri eşit şekilde dağıtma .

Yorumlardan sonra güncelleme

Sorunumun OP'nin sorununa benzer olduğunu ve bu nedenle çözümümün potansiyel olarak yararlı olduğunu düşünüyorum. OP'nin sorusu bağlamında cevabımı daha fazla çerçevelendirmediğim için özür dilerim.

Çözümümün 0, 1 ve 2 yerine A, B ve C kullandığı ilk itiraz kolayca giderildi. Bu sadece bir isimlendirme meselesi. Düşünmek ve "iki 1" den ziyade "iki A" demeyi daha kolay ve daha az kafa karıştırıcı buluyorum. Ancak bu tartışmanın amaçları için OP'nin terminolojisini kullanmak için aşağıdaki çıktıları değiştirdim.

Tabii ki sorunum mesafe kavramıyla ilgileniyor. Eğer "şeyleri eşit şekilde yaymak" istiyorsanız, mesafe belirtilir. Fakat yine de, sorunumun OP'nin sorununa ne kadar benzer olduğunu yeterince gösteremediğim için başarısız oldum.

OP'nin sunduğu iki örnekle birkaç test yaptım. Yani:

[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]

Terminolojimde bunlar sırasıyla [2,2,2] ve [4,3,2,1] olarak ifade edilir. Yani, son örnekte, "0 türünde 4 öğe, 1 türünde 3 öğe, 2 türünde 2 öğe ve 3 türünde 1 öğe."

Test programımı çalıştırdım (hemen aşağıda açıklandığı gibi) ve sonuçlarımı yayınladım. OP'den giriş yapıldığında, sonuçlarımın ona benzer, daha kötü veya daha iyi olup olmadığını söyleyemem. Hiç kimseyi yayınlamadığı için sonuçlarımı kimsenin sonuçlarıyla da karşılaştıramam.

Ben algoritma için iyi bir çözüm sağlar Ancak, diyebiliriz benim sıvının karıştırılması durumunda stratifıkasyonun ortadan kaldırma sorunu. Ve benziyor o OP'ın soruna makul bir çözüm sağlar.

Aşağıda gösterilen sonuçlar için, blog girişimde ayrıntılandırdığım algoritmayı, ilk önceliğe ayarlanmış olarak kullandım Frequency/2ve yığın karşılaştırıcısı daha sık kullanılan maddeyi tercih etmek için değiştirildi. Değiştirilen kod, değiştirilen satırların yorumuyla birlikte burada gösterilir.

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;
    }
}

Test programımı OP'nin ilk örneğiyle çalıştırarak alıyorum:

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

Bu yüzden algoritmam, tüm sayımların eşit olmasının önemsiz problemi için çalışıyor.

OP’nin yayınladığı ikinci sorun için;

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

Bunu geliştirmek için bariz bir yol görmüyorum. Madde 0 [2,3,2,3] veya diğer 2 ve 3 düzenlemeleri için mesafelerin ayarlanması yeniden düzenlenebilir, ancak bu, 1 ve / veya 2 maddelerinin sapmalarını değiştirir. "optimum" bu durumda. Daha sık veya daha az sıklıkta nesneler üzerinde daha büyük bir sapma olması daha mı iyidir?

OP'den başka sorunlardan yoksun olarak, açıklamalarını kendi birkaçımı telafi etmek için kullandım. Görevinde şöyle dedi:

Tipik bir liste, farklı miktarlarda ~ 15 farklı değerde ~ 50 maddeye sahiptir.

Yani iki testim:

[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

Ve sonuçlarım:

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

Ve ikinci örnek için:

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 Lütfen güncellememe bakın. Sorunumun OP'nin sorunuyla nasıl benzer olduğunu ve algoritmamın OP'nin sorununa nasıl bir çözüm getirdiğini gösterdiğime inanıyorum.
Jim Mischel,

İyi şeyler! Mükemmel güncelleme için teşekkürler. Upvoted.
DW

Daha önce de söylediğim gibi oldukça ilginç. Bu fikrin basitliği çekici. Hepsini dikkatlice okuyacak vaktim yoktu. Çözümünüz asıl sorunun döngüselliğini dikkate alıyor mu? Bunu amaca uygun hale getirmenin bir yolu olabilir, ama istediğinden emin değilim.
babou

@babou: Mesafe hesaplamalarım sonuçlarda gördüğünüz gibi etrafa sarılıyor, ancak algoritmanın kendisi OP'nin probleminin döngüsel doğası için herhangi bir özel harçlık vermiyor. Ayrıca algoritmayı buna uyarlayabilecek bir yol görmüyorum. Veya, bu konuda, döngüsel niteliği hesaba katmanın sonuçları iyileştirir. Her ne kadar iki katına çıkmayı düşünmek ilginç olsa da (yani [3,2,1] 'i [6,4,2]' ye değiştirerek), ki bu aynı şekilde etkili olacaktır. Benim şüphem, algoritmanın aynı sonuçları vereceğidir.
Jim Mischel,

6

Bu "NP" gibi sert kokuyor. Peki, NP zor bir probleminiz olduğunda ne yaparsınız? Ona bir sezgisel veya bir yaklaşım algoritması atın veya bir SAT çözücü kullanın.

Sizin durumunuzda, mutlak optimal çözüme ihtiyacınız yoksa, makul bir başlangıç ​​noktası benzetilmiş tavlamayı denemek olabilir . Herhangi bir aday çözümünü almanın ve yakındaki bir aday çözümüne götürmenin doğal bir yolu var: listeden iki öğeyi rastgele seçip değiştir. Simüle edilmiş tavlama, tekrarlı bir şekilde, çözümü iyileştirmeye çalışacaktır. Eğer aşina değilseniz, benzetilmiş tavlama ile ilgili birçok kaynak bulabilirsiniz. Ayrıca, aday çözümde küçük değişiklikler yapan diğer “yerel hareketler” setleriyle deneysel olarak, onu adım adım iyileştirme umuduyla deneyimleyebilirsiniz (yani, mesafelerin standart sapmasını azaltır).

Bu işe yaramazsa, benim ikinci önerim bunu SAT çözümleyicisine atmayı denemek olacaktır . Sorun boyutunuz, bunun işe yarayabileceği kadar küçük. Optimizasyon fonksiyonunuzla ilgili karar sorunuyla başlayın: verildiğinde , standart sapması olan bir çözüm var mı (yani, varyansın )? Bu bir SAT örneği olarak ifade edilebilir. SAT olarak ifade etmek karışık olacaktır, ancak STP gibi bir ön uç kullanırsanız, STP tamsayı aritmetiğini desteklediğinden, biraz daha kolaylaşacaktır. Böylece, boolean unknowns olabilir , eğer dizinin öğesi değerini tutarsa, doğru iset t 2 x i , j x i , j i j t 2ttt2xi,jxi,jij. Şimdi bunun orijinal girdinin geçerli bir müsaadesi olduğu bazı kısıtlamaları ifade edebilirsiniz. Ayrıca, daha fazla tamsayı bilinmeyenleri oluşturabilir ve onları öğeler arasındaki mesafelere eşit olmaya zorlamak için kısıtlamalar ekleyebilir ve ardından bu mesafelerin varyansını hesaplayabilir ve bunun olması gerektiğini öne süren bir kısıtlama ekleyebilirsiniz . Tabii ki, SAT çözücünün en kötü çalışma süresi üsseldir, bu yüzden SAT çözücüler bu problemi patlatabilir ... ancak bu sorunu çözebilecekler de mümkün. Deneyebileceğin başka bir teknik.t2

Ama size benzetilmiş tavlama ile başlamanızı öneririm. Bu deneyeceğim ilk şey, çünkü işe yarayabileceğini düşünüyorum.


Önerileriniz bu tür zamanlama problemlerini çözmenin standart yoludur. Sanırım bunun için ticari bir yazılım var. Bununla nasıl başa çıkıyorlar?
babou

@babou, harika bir soru - Hiçbir fikrim yok!
DW

Algoritmamın ayrıntılarını daha da geliştirdim, ancak mevcut uygulamaların bunu kullanacağından çok şüpheliyim. Aslında, zamanlama uygulamalarının bu tür bir sorunla mı ilgilendiğini merak ediyorum. SE.softwarerecs hakkında bilgi istiyorum, burada nasıl bir soru soracağımı görmedim, yorum yaptığım gibi.
babou

Optimum çözeltisi NP-zor olabilir. Ancak oldukça uygulanabilir bir çözüm O (n log k) 'dır, burada n toplam öğe sayısıdır ve k öğe türlerinin sayısıdır. Cevabımı ve bağlantılı blog yazımı görün.
Jim Mischel

2

Sezgisel algoritma taslağı

Bu sorun için kesin bir çözümüm yok. Ancak Raphael'in yorumu , sezgisel algoritmaların geliştirildiği bölümleme problemi gibi göründüğünü öne sürdüğü için, sezgisel bir yaklaşım deneyeceğim. Bu sadece bir sezgisel algoritma taslağıdır.

vn[1..n]ini

nvnvn/nv

v

in/ninmodnin/ni

Bu bizim algoritmamızı yönlendirecek.

Ama önce, tekil değerlerin (sadece bir defa meydana gelen) daima aynı eşleşme mesafesine sahip olacağını not ettik . Dolayısıyla yerleşimleri önemli değildir ve algoritma tarafından göz ardı edilebilir. Sonunda kalan yuvaları alacaklar.n

En sapma bu mesafeler olmak zorunda çünkü Sonra, en kesin kareler toplamına az katkıda bulunmak, biz, bu her zaman sapma en yere yani değerlerini ilk değerlerini denemek öyle ki en iyisidir.| n / n i - v |i|n/niv|

İlk başta çok az sayıda meydana gelen bir değer olabilir. Bence bu aslında bir fark yaratmıyor çünkü zira kullanılan yuvaların yarattığı kısıtlamalar, yerleştirilen değerlerin ()) sayısı ile orantılı.

Düşünülen ilk değer herhangi bir kısıtlama olmadan yerleştirilebilir. Öyleyse, diğer sapmalar standart sapmaya olan katkılarını en aza indirecek şekilde yerleştirilmelidir, ancak sadece önceden hangi değerlerle yerleştirilmiş olursa olsun serbest bırakılan yuvalarda.

Bir değerin geri kalan yuvalara yerleştirilmesi, sadece standart sapmaya minimum katkısı olanları koruyarak, iki konum arasında aynı sayıda değeri yerleştiren hesaplamaları birleştirmek için dinamik bir programlama algoritması ile yapılabilir. sapmalarının karelerinin toplamı için asgari değer).

Bazen, birkaç minimal çözüm olacaktır. Bu durumda, kalan boşlukları en eşit şekilde dağıtan en az çözümü seçerek, biraz gevşekliği korumaya çalışırsınız. Bu, her bir çözelti için (değil ile ilgili olarak, bunların ortalama değere füzyonlu halkalı kalan serbest yuvaları arasındaki mesafelerin standart sapması bilgisayar tarafından hesaplanabilmektedir ).v

Sonra bir sonraki kalan değer için tekrarlayın öyleen iyisidir, tüm singleton olmayan değerler yerleştirilinceye kadar devam eder.| n / n j - v |j|n/njv|

Ardından singleton değerlerini kalan yuvalara koyarsınız.

Bunun genellikle makul bir çözüm sunması gerektiğine inanıyorum, ancak nasıl ispatlanacağı veya açığı optimal bir çözümle tahmin edebileceğim hakkında hiçbir fikrim yok.


Tek olanları bir kenara bırakarak, en çok ya da en az olanlarla başlayıp başlamamamızın önemi olmadığı konusunda aynı düşünceye sahibim. Görünüşe göre bana en iyi sonuçları veren strateji , değerleri oluşuma göre sıralamaya ve en çok meydana gelenlerden başlayarak sıraya koymaya başlar. Bu doğal olarak singletonları sonuna kadar bırakır.
moralar

@moraes Önemli olan, değerinden uzaklıktaki ortalama sapmayı azaltarak sipariş vermektir . Bu normalde en az ve en yaygın olanları değiştirir, bu nedenle her iki uçtan ortaya doğru başlar ( yakın oluşum sayısı , çünkü , ortalama mesafedir). Tabii ki Singletons hariç. n / v Vvn/vV
babou

10 [0, 0, 0, 0, 1, 1, 1, 2, 2, 3]ve v değerine sahip bir liste için 4, ilk değerleri 1( 10/3 = 3.33, v'ye en yakın), sonra 2( 10/2 = 5, en yakın), sonra 0( 10/4 = 2.5) yerleştireceğimizi mi kastediyorsunuz ? Veya: "v değerinden uzaklıktaki ortalama sapma azalması" örneğini verebilir misiniz?
moralar

1
Hayır, tam tersini yapıyorum. Örneğinize göre konumlandırma sırası ilk önce O, çünkü ortalama uzaklık 2,5, en çok v = 4, sonra 2, sonra 1 ve tekil 3'tür. 3 - - - Daha açık bir şekilde yeniden yazmamı mı önerirsiniz? Bu strateji için açıklamamın bir parçası mı?
babou

Hayır, bu iyi. Bu fikir boyunca bir şeyler deneyeceğim ve tekrar rapor edeceğim.
moralar

1

Partiye çok geç kaldım gibi gözüküyor, ancak birileri bu duruma tekrar katılabilirse diye yazıyorum. Benim çözümüm @ babou'nın artılarına benzer. Bugün erken saatlerde, beni bu iş parçacığına yönlendiren gömülü bir sistemde zamanlama sorunu yaşadım. C'deki sorunuma özel bir uygulamam var, ancak Python'da daha genel bir çözüm yayınlayacağımı düşündüm (C sürümü kendimi küçük, sabit boyutlu bir yığınla sınırlamamıştım ve hafızası yok. ayırmalar, bu yüzden tüm algoritmayı yerinde uygularım). Aşağıda kullanılan kenar yumuşatma tekniği, 2 bit renkli ekranda bir çizgi çizmek için kullanabileceğiniz bir şeydir. Buradaki algoritma, Jim Mischel tarafından kullanılan girdiler için standart sapma toplamı kullanılarak, bu belirli çözümden daha düşük bir puan elde eder (yani daha iyi).

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

İçin sonuçlar

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 tarafından belirtilen formun girişleri verilmişse, O (n) adımlarında Big Omega (n * log (n)) bellek bitlerini kullanarak n'nin öğe sayısı olduğu, onu bu fonksiyon tarafından kullanılabilen bir forma dönüştürebilirsiniz. 255 öğeli bir listede, tekrar sayımlarıyla paralel bir dizi tutarak, 255 fazladan bayttan daha fazlasına ihtiyacınız olmaz. Alternatif olarak, bir kişi O (1) ekstra bellekle bir çift yerinde çeşit gerçekleştirebilir.

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)

Düzenleme: Bu çözüm karşı örnek tarafından en iyi çıktı üretmediğini biliyorum. Bir girdi [6, 2, 1]üretir [0, 1, 0, 0, 2, 0, 0, 1, 0]; daha iyi bir çözümdür [0, 0, 1, 0, 2, 0, 0, 1, 0].


Algoritmamın kod açıklamalarında ve başlangıçta algoritmanın temelini açıkladığına inanıyorum.
lungj

Algoritmanızın arkasındaki fikirlerin kendi kendine yeten bir tanımını görmek ve algoritmanın özlü sözde kodunu görmek isterdim. Şu anda tanıtım metninde gördüğüm şey şu: (1) yaklaşımınız @ babou'ya benziyor ve (2) bir anti-aliasing tekniği kullanıyor (bir şekilde). Ayrıca, buradaki herkes Python'u okumuyor. Her durumda, bu eski bir cevap, bu yüzden geliştirmek istemiyorsanız anlıyorum, ancak yalnızca bu sitede beklentilerimizi not ediyorum - sadece sizin için değil, bu sayfada karşılaşabilecekler için gelecek ve cevap vermeye yatkın olmak.
DW

0

Bu algoritma, her bir tamsayı farklı bir kategoriyi temsil ettiği bir tamsayı dizisi ile çalışır. Her kategori için ayrı diziler oluşturur. Örneğin, başlangıç ​​dizisi [1, 1, 1, 2, 2, 3] ise, üç dizi, [3], [2, 2], [1, 1, 1] oluşturacaktır.

Oradan en küçük iki diziyi (bu örnekte, [3] ve [2,2]) yinelemeli olarak birleştirir ve en küçük sayının oranına dayanarak daha küçük dizinin öğelerinin yerleşimini en küçük ikinci diziye yerleştirir daha büyüklerin oluşumuna karşı daha küçük kategoriler. Bu örnekte, [2,3,2] ile kurulacaktı. Daha sonra bu diziyi yalnızca bir dizi kalıncaya kadar bir sonraki daha büyük diziye birleştirilecek olan daha küçük dizi olarak kullanır.

<?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
Bu bir kodlama sitesi değil. Lütfen sadece kod cevaplarını göndermeyin. Bunun yerine, cevabınızın arkasındaki fikirleri açıklamanızı ve algoritmanız için kısa bir sözde kod sunmanızı istiyoruz.
DW

Bilgisayar Bilimlerine Hoşgeldiniz ! Farkında değilseniz veya bir an için unuttuysanız, kodu belirli bir dilde okumak genellikle, kod kendimiz tarafından yazılmış olsa bile, yapabileceğimiz en zor işlerden biridir. Bu sitedeki gerçek kodu çok fazla takdir etmememizin bir nedeni de olsa da, sözde yazılmış sözde koddan çok daha fazla çalışmayı temsil ediyor olabilir. Tabii ki, derhal çalıştırılabilen veya kırpılabilen tüm gerçek çalışma kodlarını takdir ediyorum.
Apass.Jack

Bir açıklama var. yorumlanan gösteri kodunda; APL gibi bazı arkaik sözdizimlerinde değil, sözde koda yeterince yakın olan bir sözdizimini anlamak kolaydır. Açıklamam monospace fontunda olmasa yardımcı olur mu?
vtim

Evet. Yardımcı olur. Herkes PHP okumaz, belki herkes yorumun ne olduğunu belirleyemez (belki de saman adam argümanıdır) veya sadece kod bloğunu okumak ve yorumlamak istemez, ama en baştaki notu okuyunuz. her şeyi anlatıyor. Benden +1. Kodunuz temiz ve iyi belgelenmiştir, ancak biz sadece kodlama yapan bir site değiliz, bu yüzden burada yazılı açıklama önemlidir. Düzenlemeniz için teşekkürler.
Evil

-1

ANSI C KODU

Bu kod, n boyutunda düz bir çizgiyi hayal ederek çalışır (burada n kategori sayısıdır), kökeni geçen vektörel (v1, v2, ..., vi, ... vn) vektörleri ile gösterir. Kategorideki öğeler i. Başlangıç ​​noktasından başlayarak amaç, çizgiye en yakın noktayı bulmaktır. [0 0 0 0 0 1 1 1 2 2 2 3] örneğini kullanarak [0 1 2 0 3 1 0 2 0 1 2 0] sonucunu üretir. Lungj örneğini [0 0 0 0 0 0 1 1 2] kullanarak, [0 1 0 0 2 0 0 1 0] 'ı alıyoruz ki bu da Lungj’un sonucuyla tamamen aynı.

Algoritma sadece tamsayı aritmetiği kullanılarak ve sadece her noktadan çizgiye kadar olan mesafeler arasındaki deltalar dikkate alınarak daha verimli hale getirilir.

#define MAXCATEGORIES 100

int main () {int i = 0; int j = 0; int catsize = 0; int vektörü [MAXCATEGORIES]; nokta [MAXCATEGORIES]; int kategorileri = 0; int totalitems = 0; en iyi int = 0; uzun d2 = 0L; uzun vp = 0L; uzun v2 = 0L; uzun delta = 0L; uzun beta = 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
Siteye Hoşgeldiniz! Biçimlendirme bilgisinde, kodunuzun her satırını dört boşlukla girmeniz gerekir, böylece sistem doğru bir şekilde işaretlenir. Genel olarak, sorulara cevap olarak büyük kod blokları aramıyoruz ve özellikle veri girişi yordamlarınız buraya bir şey eklemiyor. Yazınızın üst kısmında bazı açıklamalar var, ancak bunu genişletip kodu kısmak daha iyi olur.
David Richerby

Bu bir kodlama sitesi değil. Lütfen sadece kod cevaplarını göndermeyin. Bunun yerine, cevabınızın arkasındaki fikirleri açıklamanızı ve algoritmanız için kısa bir sözde kod sunmanızı istiyoruz.
DW

-1

çözümüm:

    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']

Lütfen algoritmanızı tanımlamak için sözde kod kullanın (bazı gerekli yorumlar ile).
xskxzr

Bu bir kodlama sitesi değil. Lütfen sadece kod cevaplarını göndermeyin. Bunun yerine, cevabınızın arkasındaki fikirleri açıklamanızı ve algoritmanız için kısa bir sözde kod sunmanızı istiyoruz.
DW
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.