назначить значения списка другому списку - PullRequest
2 голосов
/ 08 марта 2020

У меня есть два списка одинаковой длины, один из которых содержит целые числа, а другой - с плавающей точкой. Я хочу присвоить каждому числу с плавающей точкой целое число - относительно .

По относительно , я имею в виду:

  • более высокие целые числа должны иметь более высокий шанс получить низкое число с плавающей запятой
  • более низкие целые числа должны иметь меньший шанс для получения низкого числа с плавающей точкой

Для назначения достаточно добавить числа с плавающей точкой в ​​массив результатов, чтобы integers[index] соответствовало назначенный result[index].

Поскольку я говорю о шансах , я не могу просто заказать один список по убыванию и один список по возрастанию и сопоставить их.

Я не совсем уверен, как подойти к моей проблеме. Я ищу некоторые функции / модули, о которых я не слышал - или как всегда предпочитал: pure python встроенные решения:)

#INDICES:   0    1    2    3    4    5    6    7    8    9  

integers = [5,   5,   2,   4,   3,   1,   4,   5,   2,   3  ]
floats =   [0.1, 0.2, 0.3, 0.3, 0.3, 0.7, 0.6, 0.8, 0.5, 0.5]


#possible result (could be different):
result =   [0.2, 0.3, 0.3, 0.5, 0.7, 0.8, 0.6, 0.1, 0.3, 0.5]

#the result values are assigned to the integers at the same index

Как вы можете видеть, в приведенном примере result[9]==0.5 назначено на integers[9]==3, а result[6]==0.6 назначено на integers[6]==4. Что является исключением из остальной части списка, поскольку в общем случае старшие числа с плавающей запятой присваиваются более низким целым числам.

Ответы [ 2 ]

1 голос
/ 08 марта 2020

Вот сравнительно простой подход:

import random

STD_DEV = 2

integers = sorted([5, 5, 2, 4, 3, 1, 4, 5, 2, 3], reverse=True)
floats = sorted([0.1, 0.2, 0.3, 0.3, 0.3, 0.7, 0.6, 0.8, 0.5, 0.5])

results = []
for i in range(0, len(integers)): 
    noisy_index = min(max(int(random.gauss(i, STD_DEV)), 0), len(floats)-1)
    results.append(floats[noisy_index])

print(results)
# [0.1, 0.2, 0.3, 0.2, 0.5, 0.3, 0.5, 0.5, 0.8, 0.7]

Сначала сортируются целые числа по убыванию, а затем по возрастанию с плавающей запятой, затем циклически перебираются по целочисленным индексам и определяют индекс значения с плавающей запятой для выборки из выборки из Гауссово распределение вокруг этого значения индекса. Значение STD_DEV даст вам контроль над тем, как часто будут выбираться другие индексы ... Я выбрал STD_DEV = 2, потому что он казался работоспособным (то есть маловероятно, что индекс = 0 будет переходить на индекс = 9).

Обратите внимание, что это действительно относительный подход к взвешиванию. Отсортированное целочисленное значение индекса - это то, что устанавливает наиболее вероятный плавающий элемент, который будет выбран, но он будет вести себя одинаково, если первые два числа будут 5, 5... или если они будут 500, 5....

РЕДАКТИРОВАТЬ : если вы хотите, чтобы целочисленные значения имели некоторый вес, превосходящий их относительное упорядочение, одним из подходов будет масштабирование стандартного отклонения распределения Гасса на основе значения. Вот один из подходов (из многих способов сделать это), который просто масштабирует стандартное отклонение на основе расстояния от целочисленного значения до среднего:

import random

BASE_STD_DEV = 2

integers = sorted([5, 5, 2, 4, 3, 1, 4, 5, 2, 3], reverse=True)
floats = sorted([0.1, 0.2, 0.3, 0.3, 0.3, 0.7, 0.6, 0.8, 0.5, 0.5])

avg_int = sum(integers)/len(integers)
max_dist = max([abs(i - avg_int) for i in integers])

results = []
for i, integer in enumerate(integers):
    factor = 1 - abs(integer - avg_int) / max_dist
    std_dev = BASE_STD_DEV * factor
    noisy_index = min(max(int(random.gauss(i, std_dev)), 0), len(floats)-1)
    results.append(floats[noisy_index])

print(results)
# [0.1, 0.2, 0.3, 0.2, 0.5, 0.3, 0.5, 0.5, 0.8, 0.7]

Вы можете легко настроить это, чтобы, возможно, иметь минимум стандартное отклонение или минимальное / максимальное factor, поскольку в настоящее время значения крайних значений не имеют стандартного отклонения.

0 голосов
/ 08 марта 2020

Примерно так должно получиться:

import random

def shuffle(ints, floats):

    new_ints = list(sorted(ints))
    new_floats = list(sorted(floats))

    def weight(x, n):
        # implement your own weight system here
        # maybe `n+x` - just make sure that as
        # x increases the weight increases
        return x

    def gen_weights(n):
        return [weight(x,n) for x in range(1,n+1)]

    result = []
    while new_ints:
        i = random.choices(range(len(new_ints)), gen_weights(len(new_ints)))[0]
        result.append((new_ints.pop(0), new_floats.pop(i)))

    new_result = []
    for x in ints:
        for i, (j, f) in enumerate(result):
            if j == x:
                new_result.append(f)
                del result[i]
                break
    return new_result

random.seed(1)

in1 = [5,   5,   2,   4,   3,   1,   4,   5,   2,   3  ]
in2 = [0.1, 0.2, 0.3, 0.3, 0.3, 0.7, 0.6, 0.8, 0.5, 0.5]

result = shuffle(in1, in2)
print(result)

Вывод:

[0.3, 0.1, 0.8, 0.5, 0.3, 0.3, 0.7, 0.2, 0.6, 0.5]

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

Наконец, функция просматривает каждый элемент в исходном списке целых и находит соответствующее целочисленное значение в списке результатов. Он удаляет это значение и добавляет его в список вывода (new_result).


Если вам не нравится система линейных весов, замените значение return x в функции weight с любой другой возрастающей функцией. Убедитесь, что более высокие значения x имеют более высокие возвращаемые значения.


Надеюсь, это поможет:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...