#arrays #numpy
#массивы #numpy
Вопрос:
Рассмотрим небольшой образец массива целых чисел из 6 столбцов:
import numpy as np
J = np.array([[1, 3, 1, 3, 2, 5],
[2, 6, 3, 4, 2, 6],
[1, 7, 2, 5, 2, 5],
[4, 2, 8, 3, 8, 2],
[0, 3, 0, 3, 0, 3],
[2, 2, 3, 3, 2, 3],
[4, 3, 4, 3, 3, 4])
Я хочу удалить, из J:
а) все строки, в которых первая и вторая ПАРЫ элементов являются точными совпадениями (это удаляет строки типа [1,3, 1,3, 2,5])
б) все строки, в которых вторая и третья ПАРЫ элементов являются точными совпадениями (это удаляет строки, подобные [1,7, 2,5, 2,5])
Совпадения между любыми другими парами разрешены.
У меня есть решение, приведенное ниже, но оно обрабатывается в два этапа. Если есть более прямой, более чистый или более легко расширяемый подход, мне было бы очень интересно.
K = J[~(np.logical_and(J[:,0] == J[:,2], J[:,1] == J[:,3]))]
L = K[~(np.logical_and(K[:,2] == J[:,4], K[:,3] == K[:,5]))]
K удаляет 1-ю, 5-ю и 7-ю строки из J, оставляя
K = [[2, 6, 3, 4, 2, 6],
[1, 7, 2, 5, 2, 5],
[4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3]])
L удаляет 2-ю строку из K, давая окончательный результат.
L = [[2, 6, 3, 4, 2, 6],
[4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3]])
Я надеюсь на эффективное решение, потому что, изучая эту проблему, мне нужно распространить эти идеи на 8-столбчатые массивы, где
Я удаляю строки, имеющие точные совпадения между 1-й и 2-й ПАРАМИ, 2-й и 3-й ПАРАМИ и 3-й и 4-й ПАРАМИ.
Ответ №1:
Поскольку мы проверяем соседние пары на равенство, различие в 3D
измененных данных, по-видимому, было бы одним из способов сделать это для более чистого векторизованного —
# a is input array
In [117]: b = a.reshape(a.shape[0],-1,2)
In [118]: a[~(np.diff(b,axis=1)==0).all(2).any(1)]
Out[118]:
array([[2, 6, 3, 4, 2, 6],
[4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3]])
Если вы хотите повысить производительность, пропустите различие и перейдите к разделенному равенству —
In [142]: a[~(b[:,:-1] == b[:,1:]).all(2).any(1)]
Out[142]:
array([[2, 6, 3, 4, 2, 6],
[4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3]])
Общее количество столбцов
Также распространяется на общее количество столбцов —
In [156]: a
Out[156]:
array([[1, 3, 1, 3, 2, 5, 1, 3, 1, 3, 2, 5],
[2, 6, 3, 4, 2, 6, 2, 6, 3, 4, 2, 6],
[1, 7, 2, 5, 2, 5, 1, 7, 2, 5, 2, 5],
[4, 2, 8, 3, 8, 2, 4, 2, 8, 3, 8, 2],
[0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3],
[2, 2, 3, 3, 2, 3, 2, 2, 3, 3, 2, 3],
[4, 3, 4, 3, 3, 4, 4, 3, 4, 3, 3, 4]])
In [158]: b = a.reshape(a.shape[0],-1,2)
In [159]: a[~(b[:,:-1] == b[:,1:]).all(2).any(1)]
Out[159]:
array([[4, 2, 8, 3, 8, 2, 4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3, 2, 2, 3, 3, 2, 3]])
Конечно, мы предполагаем, что количество столбцов позволяет выполнять сопряжение.
Комментарии:
1. Возможно, было бы лучше использовать
axis=-1
последовательно вместоaxis=2
иaxis=1
.2. @MateenUlhaq Это просто более точно. Из-за более высоких значений dims мы в любом случае добавили бы больше двоеточий .
3. Ваше 2-е решение, в частности, очень эффективно. Как относительный новичок, не могли бы вы просто показать, что это применимо к регистру из 8 столбцов? (то есть: устранение 1-2-х пар совпадений, 2-3-х пар совпадений, 3-4-х пар совпадений)
4. @user109387 Это работает для любого количества столбцов без каких-либо изменений в коде. Или вы хотите, чтобы я показал это в качестве примера выполнения?
5. Добавлен @user109387.
Ответ №2:
То, что у вас есть, вполне разумно. Вот что я бы написал:
def eliminate_pairs(x: np.ndarray) -> np.ndarray:
first_second = (x[:, 0] == x[:, 2]) amp; (x[:, 1] == x[:, 3])
second_third = (x[:, 1] == x[:, 3]) amp; (x[:, 2] == x[:, 4])
return x[~(first_second | second_third)]
Вы также могли бы применить теорему Деморгана и исключить дополнительную not
операцию, но это менее важно, чем ясность.
Комментарии:
1. Если бы это было расширено, скажем, до массива из 8 столбцов, где у нас есть первый-второй, второй-третий и третий-четвертый, как бы вы обработали оператор Return?
2. @user109387 В этот момент я бы переключился на что-то похожее на ответ Дивакара и просто сравнил с помощью срезов после изменения формы (что необходимо для наложения структуры «сопряжения»).
Ответ №3:
Давайте попробуем цикл:
mask = False
for i in range(0,3,2):
mask = (J[:,i:i 2]==J[:,i 2:i 4]).all(1) | mask
J[~mask]
Вывод:
array([[2, 6, 3, 4, 2, 6],
[4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3]])