комбинация 2d-массивов numpy

#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 могут быть короче: Example a = [(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 , либо array b могут содержать дубликаты.

5. можете ли вы привести пример того, как должен выглядеть c, если a и b содержат дубликаты, как вы упомянули?

Ответ №4:

  1. Для i=2 получите свою первую часть результата:

     c = a[i:]
      
  2. Получить «необычные» элементы между b и c :

     diff = np.array([x for x in b if x not in c])
      
  3. Выберите 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. Вероятно, это ваша проблема с данными, когда вы пытаетесь выбрать большее количество элементов, чем ваш родительский набор. Она работает с данными, которые вы указали в вопросе.