#python #arrays #python-3.x #numpy
#python #массивы #python-3.x #numpy
Вопрос:
Предположим, у меня есть два массива:
a = np.array(
[[0, 1],
[2, 3],
[4, 5],
[6, 7]])
b = np.array(
[[2, 3],
[6, 7],
[0, 1],
[4, 5]])
Как вы можете видеть, один массив является просто перетасовкой другого. Мне нужно объединить эти два массива, чтобы сформировать третий массив, c
такой как:
- первая часть массива
c
(до получения случайного индексаi
) состоит из элементов из первой части массиваa
(до получения индексаi
). Следовательно,c[:i] == a[:i]
должен возвращать True . - остальная часть массива
c
заполняется значениями из массиваb
, которые еще не находятся внутри массиваc
, в том же порядке, в котором они отображаются.
Учитывая, что индекс i
установлен в 2, желаемый результат для вышеуказанных массивов a
и b
в коде должен быть:
> c
[[0, 1],
[2, 3],
[6, 7],
[4, 5]]
Массив c
должен иметь ту же длину, что и массив b
и array a
, и есть вероятность, что два элемента в пределах либо array a
, либо array b
совпадают. Массив c
также должен состоять из тех же элементов, которые находятся в a
и b
, (т. е. он ведет себя несколько как перетасовка).
Я пробовал несколько решений, но ни одно из них не дало желаемого результата. Самым близким было это:
a = np.arange(10).reshape(5, 2)
np.random.shuffle(a)
b = np.arange(10).reshape(5, 2)
b_part = b[:4]
temp = []
for part in a:
if part in b_part:
continue
else:
temp.append(part)
temp = np.array(temp)
c = copy.deepcopy(np.vstack((b_part, temp)))
Однако иногда это приводит к тому, что массив c
становится меньше массивов a
и b
, поскольку элементы в любом списке иногда могут повторяться.
Комментарии:
1. Если элементы не уникальны, ваши правила подразумевают, что они
c
могут быть короче: Examplea = [(0,1),(2,3),(2,3),(4,5)] b=[(2,3),(4,5),(2,3),(0,1)] i=2
Таким образом, вы должны выбрать,a[:i]
что есть[(0,1),(2,3)]
, и изb
того, что еще не произошло, что есть(4,5)
. Этоc
было бы[(0,1),(2,3),(4,5)]
короче.2. @PaulPanzer Я понимаю, что именно это является причиной проблемы, но я не знаю, как я могу решить это сам (именно поэтому я задаю вопрос)
3. Первым делом нужно было бы решить, каким будет ваш желаемый ответ в этом случае.
4. имхо, ваш код работает (просто создайте a_part вместо b_part и поменяйте местами массивы в обоих циклах vstack (a_part, temp)), но ваша проблема с size (c) — это ваше определение проблемы, если у вас есть дубликаты внутри a, которые являются основой для c. Представьте, что вы разделяете a с индексом i в качестве результирующего c таким образом, что вы берете только один дубликат значений внутри a, поэтому ваш c не может иметь тот же размер, что и a или b, потому что вы не можете добавить другой дубликат из b
5. @KomronAripov используя ваш графический пример, попробуйте index [:4] вместо [:2] и выдайте нам результат.
Ответ №1:
Следующее должно нормально обрабатывать дубликаты.
def mix(a, b, i):
sa, sb = map(np.lexsort, (a.T, b.T))
mb = np.empty(len(a), '?')
mb[sb] = np.arange(2, dtype='?').repeat((i, len(a)-i))[sa]
return np.concatenate([a[:i], b[mb]], 0)
IT
- косвенная сортировка
a
иb
- создает маску, которая является истинной в позициях, не взятых из
a
, т. е. имеетi
ложные значения, а затемlen(a)-i
истинные значения. - использует порядок сортировки для сопоставления этой маски с
b
- фильтрует
b
с помощью маски и добавляет кa[:i]
Пример (транспонирован для экономии места):
a.T
# array([[2, 2, 0, 2, 3, 0, 2, 0, 0, 1],
# [0, 1, 2, 0, 1, 0, 3, 0, 0, 0]])
b.T
# array([[0, 0, 2, 1, 0, 0, 2, 2, 2, 3],
# [0, 0, 0, 0, 2, 0, 1, 3, 0, 1]])
mix(a, b, 6).T
# array([[2, 2, 0, 2, 3, 0, 0, 1, 0, 2],
# [0, 1, 2, 0, 1, 0, 0, 0, 0, 3]])
Комментарии:
1. Если
a = np.array( [[0, 1], [2, 3], [0, 0], [2, 3], [4, 5], [6, 7]]), b = np.array( [[2, 3], [6, 7], [0, 1], [4, 5], [2, 3], [0, 0]])
, то дляi=3
это решение даетc = [0, 1], [2, 3], [0, 0], [6, 7], [4, 5], [2, 3]]
. Последнее[2,3]
, вероятно, нарушает требование OP, поскольку оно уже получено изa
и не должно быть получено снова изb
.2. @fountainhead Нет, это другое
[2, 3]
;-] — Более серьезно, разъяснения OP относительно того, как обрабатывать дубликаты, разбросаны по нескольким комментариям.3. Несколько комментариев и несколько внешних ссылок тоже. 🙂
Ответ №2:
Вот одно из решений:
full_len = len(a)
b_not_in_a_part = ~np.all(np.isin(b,a[:i 1]),axis=1) # Get boolean mask, to apply on b
b_part_len = full_len-i-1 # Length of b part of c
c = np.concatenate((a[:i 1], b[b_not_in_a_part,:]), axis=0) # Contruct c, using the mask for the b part.
Тестирую это:
import numpy as np
a = np.array(
[[0, 1],
[2, 3],
[0, 0],
[2, 3],
[4, 5],
[6, 7]])
b = np.array(
[[2, 3],
[6, 7],
[0, 1],
[4, 5],
[2, 3],
[0, 0]])
i = 2
print ("a is:n", a)
print ("b is:n", b)
full_len = len(a)
b_not_in_a_part = ~np.all(np.isin(b,a[:i 1]),axis=1) # Get boolean mask, to apply on b
b_part_len = full_len-i-1 # Length of b part of c
c = np.concatenate((a[:i 1], b[b_not_in_a_part,:]), axis=0) # Contruct c, using the mask for the b part.
print ("c is:n", c)
Вывод:
a is:
[[0 1]
[2 3]
[0 0]
[2 3]
[4 5]
[6 7]]
b is:
[[2 3]
[6 7]
[0 1]
[4 5]
[2 3]
[0 0]]
c is:
[[0 1]
[2 3]
[0 0]
[6 7]
[4 5]]
Примечание: Для этого примера c
имеет длину всего 5
, хотя a
и b
имеют длину 6
. Это связано с тем, что из-за большого дублирования в b
в b
осталось недостаточно значений, которые можно использовать для c
.
Комментарии:
1. @KomronAripov: Эта ошибка возникает из-за того, что из-за большого дублирования в
b
недостаточно значений вb
, которые еще не используются изa
. Я могу это исправить, если вы скажете мне, каковы ваши требования для этого сценария.2. В таком сценарии нормально, если
c
имеет меньшую длину, чемa
илиb
? (Поскольку значений недостаточно для соответствия полной длине)3. @KomronAripov, Исправил ошибку, сделав предположение, что для
c
нормально иметь меньшую длину, если из-за большого дублирования вb
остается недостаточно значений, подходящих для перехода вc
Ответ №3:
Просто используйте numpy.concatenate() и убедитесь, что ваш индекс сам по себе равен плюс 1 (поскольку индексация numpy увеличивается до указанного значения индекса, но не включает его, см. Ниже): (Редактировать: похоже, вы изменили свои массивы a, b и c, поэтому я изменю свой приведенный ниже код, чтобы соответствовать)
import numpy as np
a = np.array(
[[0, 1],
[2, 3],
[4, 5],
[6, 7]])
b = np.array(
[[2, 3],
[6, 7],
[0, 1],
[4, 5]])
i = 2
c = a[0:i]
for k in b:
if k not in c:
c = np.concatenate((c, [k]))
print(c)
Вывод:
[[0 1]
[2 3]
[6 7]
[4 5]]
Комментарии:
1. после небольшого изменения массива b (теперь обновленного в ответе) результат получается не таким, как ожидалось.
2. это приводит к дублированию (даже если изначально их не было), что нежелательно…
3. Хорошо, я понял тебя, как насчет сейчас?
4. это все еще не решает проблему, из-за которой существует вероятность того, что либо массив
a
, либо arrayb
могут содержать дубликаты.5. можете ли вы привести пример того, как должен выглядеть c, если a и b содержат дубликаты, как вы упомянули?
Ответ №4:
-
Для
i=2
получите свою первую часть результата:c = a[i:]
-
Получить «необычные» элементы между
b
иc
:diff = np.array([x for x in b if x not in c])
-
Выберите
random
элементы изdiff
иconcatenate
в исходный массив:s = len(a) - i np.concatenate([c, diff[np.random.choice(diff.shape[0], size=s, replace=False), :]], axis=0)
ВЫВОД:
array([[0, 1],
[2, 3],
[4, 5],
[6, 7]])
Комментарии:
1. Вы можете добавлять
replace=False
при выборе случайных строк изb
. Обновлен код.2.
TypeError: randint() got an unexpected keyword argument 'replace'
3. @KomronAripov Извините, я виноват. Вы также должны изменить
randint
наchoice
. Попробуй сейчас?4.
ValueError: Cannot take a larger sample than population when 'replace=False'
5. Вероятно, это ваша проблема с данными, когда вы пытаетесь выбрать большее количество элементов, чем ваш родительский набор. Она работает с данными, которые вы указали в вопросе.