Алгоритм розподілу елементів "рівномірно"


25

Я шукаю алгоритм для розподілу значень зі списку, щоб отриманий список був максимально "збалансованим" або "рівномірно розподіленим" (у лапках, тому що я не впевнений, що це найкращі способи описати його ... пізніше я запропоную спосіб виміряти, чи результат кращий за інші).

Отже, для списку:

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

Один з найкращих результатів після повторного розподілу значень:

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

Можуть бути й інші результати настільки ж хороші, як цей, і, звичайно, це ускладнюється менш менш рівномірним набором значень.

Ось як виміряти, чи результат краще, ніж інші:

  1. Порахуйте відстані між кожним і наступним пунктом з однаковим значенням.

  2. Обчисліть стандартне відхилення для цього набору відстаней. Менша дисперсія означає кращий результат.

Спостереження:

  • Підраховуючи відстань і досягаючи кінця списку, не знаходячи елемент з однаковим значенням, ми повертаємося до початку списку. Отже, щонайменше, буде знайдено той самий елемент, і відстань до нього буде довжиною списку. Це означає, що список циклічний ;
  • Типовий список містить ~ 50 предметів з ~ 15 різними значеннями в різних кількостях.

Так:

  • Для результату [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;
  • Що робить перший результат кращим за другий (нижнє відхилення краще).

З огляду на ці визначення, я прошу підказки, які алгоритми чи стратегії слід шукати.


Схоже, ви хочете вирішити (оптимізаційний варіант) проблеми розділу , хоча б приблизно. Напевно, існує багато алгоритмів для цього!
Рафаель

Перечитавши це, чому підрахунок виникнення всіх значень і потім циклічне розміщення значень не завжди дає оптимальне рішення?
Рафаель

Відповіді:


8

Я зіткнувся з цим питанням, досліджуючи подібну проблему: оптимальні добавки рідин для зменшення стратифікації. Здається, моє рішення також застосовно до вашої ситуації.

Якщо ви хочете змішати рідини A, B і C у пропорції 30,20,10 (тобто 30 одиниць A, 20 одиниць B і 10 одиниць С), ви закінчите стратифікацією, якщо додати всі то А, то всі В, а потім усі С. Тобі краще змішувати менші одиниці. Наприклад, зробіть однорядні доповнення в послідовності [A, B, A, C, B, A]. Це взагалі запобіжить розшаруванню.

Я знайшов це зробити - це трактувати це як своєрідне злиття, використовуючи чергу пріоритету. Якщо я створю структуру для опису доповнень:

MergeItem
    Item, Count, Frequency, Priority

Частота виражається як «кожен N». Отже 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 #, який це ілюструє. Див. Рівномірний розподіл елементів у списку .

Оновлення після коментарів

Я думаю, що моя проблема схожа на проблему ОП, і тому моє рішення може бути корисним. Прошу вибачення за те, що більше не поставив свою відповідь в плані питання ОП.

Перше заперечення про те, що моє рішення використовує A, B і C, а не 0, 1 і 2, легко усувається. Це просто питання номенклатури. Мені легше і менш заплутано думати і говорити "два А", а не "два 1". Але для цілей цієї дискусії я змінив свої результати нижче, щоб використовувати номенклатуру ОП.

Звичайно, моя проблема стосується концепції відстані. Якщо ви хочете "рівномірно розподілити речі", мається на увазі відстань. Але, знову ж таки, це було моїм невдачею не адекватно показати, наскільки моя проблема схожа на проблему ОП.

Я провів кілька тестів з двома прикладами, які надав ОП. Це є:

[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] відповідно. Тобто в останньому прикладі "4 предмети типу 0, 3 елементи 1 типу, 2 елементи типу 2 та 1 предмет типу 3".

Я запустив свою тестову програму (як описано одразу нижче) та опублікував свої результати. Відсутній вхід з ОП, я не можу сказати, чи мої результати схожі на гірші, або кращі, ніж його. Я також не можу порівнювати свої результати з чиїмись результатами, тому що ще ніхто не публікував.

Я можу сказати, однак, що алгоритм забезпечує хороше рішення моєї проблеми усунення стратифікації при змішуванні рідин. І схоже, це забезпечує розумне вирішення проблеми ОП.

Для результатів, показаних нижче, я використав алгоритм, який я детально описав у своєму записі в блозі, з початковим пріоритетом, встановленим на 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;
    }
}

Запускаючи свою тестову програму з першого прикладу ОП, я отримую:

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

Отже, мій алгоритм працює для тривіальної задачі, коли всі рахунки рівні.

Для другої проблеми, яку опублікувала ОП, я отримав:

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. Я дійсно не знаю, що "Оптимум" є в цій ситуації. Чи краще мати більші відхилення на більш частих або на менш частих предметах?

Не маючи інших проблем з ОП, я використовував його описи, щоб скласти кілька моїх власних. Він сказав у своєму дописі:

Типовий список містить ~ 50 предметів з ~ 15 різними значеннями в різних кількостях.

Тож два мої тести були:

[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

А для другого прикладу:

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 Будь ласка, дивіться моє оновлення. Я вважаю, що я показую, наскільки моя проблема схожа на проблему ОП, і як мій алгоритм забезпечує вирішення проблеми ОП.
Джим Мішель

Хороший матеріал! Дякуємо за чудове оновлення. Отримано.
DW

Досить цікаво, як я вже говорив раніше. Простота ідеї приваблива. Я не встиг прочитати це все уважно. Чи реально ваше рішення враховує циклічність початкового питання? Можливо, є спосіб адаптувати його до мети, але я не зовсім впевнений.
бабу

@babou: Мої обчислення відстані обертаються, як ви бачите в результатах, але сам алгоритм не передбачає жодних специфічних припущень для циклічності проблеми ОП. Я також не бачу жодного способу, щоб я міг адаптувати алгоритм для цього. Або, з цього питання, як врахування циклічного характеру покращило б результати. Хоча цікаво розглянути подвоєння всіх підрахунків (тобто змінити [3,2,1] на [6,4,2]), що було б фактично тим самим. Я підозрюю, що алгоритм дав би однакові результати.
Джим Мішель

6

Це "пахне", як це може бути важко NP. Отже, що ви робите, коли у вас є складна проблема з NP? Накиньте евристику на це, або алгоритм наближення, або скористайтеся рішенням SAT.

У вашому випадку, якщо вам не потрібне абсолютне оптимальне рішення, однією розумною відправною точкою може бути спробу імітованого відпалу . Існує природний спосіб прийняти будь-яке рішення кандидата та перемістити його до сусіднього рішення кандидата: випадковим чином вибрати два пункти у списку та замінити їх. Імітаційний відпал ітераційно намагатиметься покращити рішення. Ви можете знайти багато ресурсів для імітованого відпалу, якщо ви не знайомі з ним. Ви також можете експериментувати з іншими наборами "локальних рухів", які вносять невеликі зміни до кандидатського рішення, сподіваючись на поступове його поліпшення (тобто зменшення стандартного відхилення відстаней).

ttt2xi,jxi,jijt2

Але я б запропонував почати з імітаційного відпалу. Це перше, що я спробував би, бо думаю, що це може просто спрацювати.


Чи є ваші пропозиції стандартним способом вирішення подібних проблем планування. Я думаю, для цього є якесь комерційне програмне забезпечення. Як вони з цим справляються?
babou

@babou, чудове запитання - я поняття не маю!
DW

Я ще більше розробив деталі свого алгоритму, але сумніваюся, що дуже багато існуючих додатків будуть використовувати це. Насправді мені навіть цікаво, чи стосуються програми планування такі проблеми. Я просив інформацію про SE.softwarerecs, оскільки я не бачу, як тут поставити питання, окрім коментаря, як я це робив.
babou

Оптимальне рішення може бути NP-важкою. Але досить працездатним рішенням є O (n log k), де n - загальна кількість елементів і k - кількість типів елементів. Дивіться мою відповідь та моє пов’язане повідомлення в блозі.
Джим Мішель

2

Ескіз евристичного алгоритму

У мене немає точного рішення цієї проблеми. Але оскільки коментар Рафаеля говорить про те, що це виглядає як проблема розділу, для якої розроблені евристичні алгоритми, я спробую евристичний підхід. Це лише ескіз евристичного алгоритму.

vn[1..n]ini

nvnvn/nv

v

in/ninmodnin/ni

Це буде керувати нашим алгоритмом.

n

i|n/niv|

Це може бути цінністю спочатку дуже багато дуже мало подій. Я думаю, що насправді це не має значення, оскільки обмеження, створені займаючи слоти, пропорційно кількості значень, розміщених добре (?).

Перше розглянуте значення можна розмістити без обмежень. Тоді Інші значення повинні бути розміщені так, щоб мінімізувати їх внесок у стандартне відхилення, але тільки у прорізи, залишені вільними за будь-яких значень, розміщених раніше.

Розміщення вхідних значень значення в інші слоти можна здійснити за допомогою алгоритму динамічного програмування, щоб об'єднати обчислення, які розміщують однакову кількість значень між двома позиціями, зберігаючи лише ті, які мають мінімальний внесок у стандартне відхилення (тобто мінімальне значення для суми квадрата їх відхилень).

v

j|n/njv|

Потім ви ставите значення одиночних в інші слоти.

Я вважаю, що це, як правило, повинно дати розумне рішення, але я досі не маю уявлення про те, як це довести чи оцінити розрив за допомогою оптимального рішення.


У мене таке ж враження, що не має значення, якщо ми почнемо з самих чи найменш поширених, залишивши одинаків убік. Стратегія, яка, очевидно, дала мені найкращі результати, починає сортувати значення за появою та розміщувати їх у порядку, починаючи з тих, що найбільше трапляються. Це, природно, залишає одинаків до кінця.
морени

vn/vV

Ви маєте на увазі, що для списку з 10 значеннями [0, 0, 0, 0, 1, 1, 1, 2, 2, 3]і v 4ми розмістимо спочатку значення 1( 10/3 = 3.33найближчі до v), потім 2( 10/2 = 5, наступне найближче), потім 0( 10/4 = 2.5)? Або: ви могли б навести приклад "зменшення середнього відхилення відстані від значення v"?
морени

1
Ні, я роблю навпаки. Беручи свій приклад, порядок позиціонування спочатку O, оскільки його середня відстань 2,5 найбільше відхиляється від v = 4, потім 2, потім 1, і сингл 3. - - - Чи пропонуєте ypu, що я повинен переписати чіткіше деякі частина мого пояснення цієї стратегії?
бабу

Ні, це добре. Я спробую щось уздовж цієї ідеї і звіту.
морени

1

Схоже, я дуже спізнююсь на вечірку, але розміщую повідомлення, якщо хтось знову наткнеться на це. Моє рішення схоже на плюс @ babou. Раніше сьогодні у мене була проблема планування вбудованої системи, яка привела мене до цього потоку. У мене є специфічна для моєї проблеми реалізація в C, але я придумав, що я опублікую більш загальне рішення в Python тут (версія C ускладнюється тим, що я обмежився невеликим стеком фіксованого розміру і без пам'яті виділення, тому я виконую весь алгоритм на місці). Метод протизшивання, який використовується нижче, - це те, що ви можете використовувати для малювання лінії на екрані з двобітним кольором. Тут алгоритм досягає меншої оцінки (тобто кращої), коли вимірюється, використовуючи суму стандартного відхилення для входів, використовуваних Джимом Мішелем, ніж це конкретне рішення.

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, можна перетворити її у форму, придатну для використання цієї функції на етапах O (n), використовуючи біти пам'яті Big Omega (n * log (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].


Я вважаю, що я пояснив свій алгоритм у коментарях до коду та основу алгоритму в преамбулі.
lungj

Я хотів би побачити самостійний опис ідей вашого алгоритму та стислий псевдокод для алгоритму. Наразі те, що я бачу у вступному тексті, - це (1) ваш підхід подібний до @ babou та (2) він використовує техніку протизшивання (якось). Також не всі тут читають Python. У будь-якому випадку це стара відповідь, тому я розумію, якщо ви не хочете вдосконалювати її, але я просто відзначаю наші очікування на цьому веб-сайті - не лише для вас, а для інших, хто може перейти на цю сторінку в майбутнє і схильний відповідати.
DW

0

Цей алгоритм працює з масивом цілих чисел, де кожне ціле число представляє різну категорію. Він створює окремі масиви для кожної категорії. Наприклад, якщо початковий масив є [1, 1, 1, 2, 2, 3], він створить три масиви, [3], [2, 2], [1, 1, 1].

Звідти він рекурсивно поєднує два найменші масиви (у цьому прикладі [3] та [2,2]) та розміщує розміщення елементів меншого масиву у другому найменшому масиві, виходячи здебільшого із співвідношення числа частоти зустрічань більших та менших категорій. У цьому прикладі ми закінчилися [2,3,2]. Тоді він буде використовувати цей масив як менший масив, який буде об’єднаний у наступний більший масив, поки не залишиться лише один масив.

<?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

Ласкаво просимо до інформатики ! Про всяк випадок, якщо ви не були в курсі чи забули на якусь мить, читання коду однією конкретною мовою - це, як правило, одне з найскладніших завдань, яке ми можемо мати, колись навіть, якщо код був написаний нами самим. Це є причиною, чому ми не дуже цінуємо реальний код на цьому сайті, хоча це може бути набагато більше роботи, ніж невірно написаний псевдокод. Звичайно, я ціную весь фактичний робочий код, який можна негайно запустити або закрутити.
Apass.Jack

Пояснення є. у коментованому демонстраційному коді; який не в архаїчному синтаксисі, як APL, але простий для розуміння синтаксис досить близький до псевдокоду. Чи допоможе це, якби моє пояснення не було шрифтом Monospace?
vtim

Так. Це допомагає. Не всі читають PHP, можливо, не всі могли визначити, що є коментарем (можливо, це солом'яний аргумент) або просто не хочуть читати блок коду та інтерпретувати його, але читати ідею, яку ви включили вгорі та це все розповідає. +1 від мене. Ваш код чистий і добре задокументований, але ми просто не кодуємо сайт, тому тут важливий текстовий опис. Дякуємо за вашу редакцію
Зло

-1

КОД ANSI C

Цей код працює, уявляючи пряму лінію в n розмірному просторі (де n - кількість категорій), що проходить через початок з вектором спрямованості (v1, v2, ..., vi, ... vn), де 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]. Використовуючи приклад Лунджа [0 0 0 0 0 1 1 2], ми отримуємо [0 1 0 0 2 0 0 1 0], що точно так само, як і результат Лунгдж.

Алгоритм робиться більш ефективним, лише використовуючи цілу арифметику і враховуючи лише дельти між відстанями від кожної точки до прямої.

#define MAXCATEGORIES 100

int main () {int i = 0; int j = 0; int catize = 0; int vector [MAXCATEGORIES]; int point [MAXCATEGORIES]; int категорії = 0; int totalitems = 0; int best = 0; довгий d2 = 0L; довгий vp = 0L; довгий 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
Ласкаво просимо на сайт! Форматуючи, потрібно відступити кожен рядок коду чотирма пробілами, щоб система отримала правильну розмітку. Загалом, ми не шукаємо великих блоків коду як відповідей на запитання, зокрема, ваші процедури введення даних тут нічого не додають. У вас є пояснення у верхній частині вашої публікації, але було б краще розширити це і скоротити код.
Девід Річербі

Це не сайт кодування. Будь ласка, не публікуйте відповідей, що стосуються лише коду. Натомість ми хотіли б, щоб ви пояснили ідеї, що стоять за вашою відповіддю, та надали стислий псевдокод для вашого алгоритму.
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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.