Устранить фазу и сравнить массивы в python - PullRequest
0 голосов
/ 25 марта 2020

Я предполагаю, что об этом уже спрашивали, но я действительно не знаю, как сформулировать свой поиск, поэтому я создаю новый вопрос. У меня есть массив numpy, например:

A = np.array([[1, 0],[0,1],[1,-1],[-1,1],[1j,1],[1,-1j]])

Так что это имеет 6 строк, однако 2 набора по 2 одинаковы только для фазы: строка 3 и 4

[1,-1] = -1*[-1,1]

или строка 5 и 6

[1j,1] = 1j*[1,-1j]

есть ли функция funct или код, который позволяет мне найти эти "дубликаты" и устранить их. Поэтому он должен дать мне результат A_new в форме:

A_new = funct(A)

приводит к

A_new = np.array([[1, 0],[0,1],[1,-1],[1j,1]])

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

Спасибо и извинения, если об этом уже спрашивали.

Маркус

Ответы [ 3 ]

2 голосов
/ 25 марта 2020

Дедупликация в Numpy проста:

values = np.array([[1, 0],[0,1],[1,-1],[-1,1],[1j,1],[1,-1j]])
deduped = numpy.unique(values)

Но, конечно, unique использует нормальную Python эквивалентность для сравнения значений. Поскольку ваши значения - это пары, где [1,-1] == [-1,1], вам нужно получить numpy, чтобы использовать другую реализацию равенства.

import numpy as np


class Pair:
    def __init__(self, ab):
        self.a, self.b = ab

    def __eq__(self, other):
        return (self.a, self.b) in [(other.a*x, other.b*x) for x in [1, -1, 1j, -1j]]

    def __lt__(self, other):
        return False

    def __repr__(self):
        return f'[{self.a}, {self.b}]'


xs = [Pair(x) for x in [[1, 0], [0, 1], [1, -1], [-1, 1], [1j, 1], [1, -1j]]]
values = np.array(xs)
print(np.unique(values))

Здесь массив состоит из списка Pair объектов, которые иметь операцию равенства, определенную на них с __eq__. Обратите внимание, что __lt__ также определен, потому что np.unique работает путем сортировки значений. Вы должны заменить его допустимой операцией «меньше чем», если она определена для ваших пар, чтобы избежать ненадежных результатов.

Я добавил __repr__, чтобы результирующий список Pair объектов печатался лучше.

Результат:

[[1, 0] [0, 1] [1, -1] [1j, 1]]
1 голос
/ 25 марта 2020

Вот математический способ сделать это. Если любые две пары значений p1, p2 в массиве A «одинаковы, но с фазой», то если c=p1/p2, то c[0]==c[1]. Мы можем сделать это векторизованным способом, используя матричное умножение:

import numpy as np
import warnings
warnings.filterwarnings("ignore")

def phasefilter(A):
    A_0, A_1 = A[:,0].reshape(-1,1), A[:,1].reshape(-1,1)
    B_0, B_1 = 1/(A_0.T), 1/(A_1.T)
    C_0, C_1 = A_0@B_0, A_1@B_1
    phasemap = C_0==C_1
    return np.array([A[i] for i,(pmap) in enumerate(phasemap) if phasemap[i][np.arange(i+1,A.shape[0])].sum()==0])

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

A = np.array([[1, 0],[0,1],[1,-1],[-1,1],[1j,1],[1,-1j]])
print('Out:\n',phasefilter(A))
A = np.array([[2,3],[1,2],[-2,-3],[4,-5],[6,7],[-5,4]])
print('Out:\n',phasefilter(A))
A = np.array([[2,3],[1,2],[-2,-3],[4,-5],[2,3],[-5,4]])
print('Out:\n',phasefilter(A))

Вывод:

Out:
 [[ 1.+0.j  0.+0.j]
 [ 0.+0.j  1.+0.j]
 [-1.+0.j  1.+0.j]
 [ 1.+0.j -0.-1.j]]
Out:
 [[ 1  2]
 [-2 -3]
 [ 4 -5]
 [ 6  7]
 [-5  4]]
Out:
 [[ 1  2]
 [ 4 -5]
 [ 2  3]
 [-5  4]]

Редактировать: Несмотря на то, что описанный выше метод прост, он плохо масштабируется до больших размеров, поэтому вот еще более обобщенное решение для любого числа измерений:

def phasefilter(A, P=np.array([[1,-1,1j,-1j]])):
    N, M = A.shape[0], A.shape[1]
    AT = A.reshape(N,M,1)
    PM = np.swapaxes(AT@P, 1, 2).reshape(-1,M)
    return A[[i for i in range(N) if not (PM[4*i]==PM[4*(i+1):]).all(axis=1).any()]]
1 голос
/ 25 марта 2020

Это работает, но уродливо и медленно:

## Defining the cases
B1 = -1*A
B2 = 1j*A
B3 = -1j*A
## Check all cases and replace if necessary
for i in range(len(A)):
    for j in range(len(B1)):
        C = (A[i]==B1[j]).all()
        if C:
            A[i] = B1[j]/(-1)
        else:
            C = (A[i]==B2[j]).all()
            if C:
                A[i] = B2[j]/(1j)
            else:
                C = (A[i]==B3[j]).all()
                if C:
                    A[i] = B3[j]/(-1j)
A_new = np.unique(A,axis=0)

Может быть, есть еще идеи?

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