Как написать код Pythoni c для изменения массива, чтобы сделать его закрытым для операции, действующей на его строки - PullRequest
0 голосов
/ 29 апреля 2020

У меня есть массив A [:,:] и операция Op, действующая на строки x = A [:, J] of A. Поэтому для каждой строки x AI получим Op (x). Если Op (x) не является строкой A, я добавляю его к A. Я делаю это до тех пор, пока A не закроется под Op (я предполагаю, что Op не приводит к бесконечной l oop, т.е. Op закрывается под определенное количество итераций). В конце этого процесса, учитывая расширенное A, закрытое под Op, я также хочу перестановку Pindex, такую, что Op (A [:, J]) = A [:, Pindex (J)].

Я смог написать Python код, чтобы сделать это:

import numpy as np

A=np.array([[0,2,3],
            [0,-3,-1],
            [0,4,3]])

def Op(x):
    return [0,-x[2],x[1]-x[2]]



A=A.tolist()

last=len(A)
Pindex=[]

for i,x in enumerate(A):
    found=False 
    xOp=Op(x)
    for j,y in enumerate(A):
        if np.array_equal(y,xOp):
            Pindex.append(j)
            found=True
            break
    if not found:
        A.append(xOp)
        Pindex.append(last)
        last+=1

A=np.asarray(A)      


print A      
print Pindex
print A[Pindex]

Однако, это не кажется мне очень "pythoni c". Я думаю, что это может быть улучшено, чтобы сделать это быстрее. Любое предложение?

PS Это часть большого кода, где мне нужно использовать массивы. Мне нужно было преобразовать массив в список, потому что мне нужно было обновить длину объекта, для которого я выполняю итерации. Возможно, есть более разумный способ сделать это только с массивами.

PPS Я не был уверен в названии вопроса. Я могу изменить его, если у вас есть предложения.

1 Ответ

0 голосов
/ 29 апреля 2020

Вы, конечно, можете векторизовать мясо вашего l oop, если векторизуете op (python соглашается использовать snake_case). Например, учитывая ваш начальный массив,

A = np.array([[0, 2, 3],
              [0,-3,-1],
              [0, 4, 3]])

Начните с определения op, которое работает на все сразу:

def op(x):
    return np.stack((x[:, 0], -x[:, 2], x[:, 1] - x[:, 2]), axis=1)

Вы можете комбинировать массивы, сначала маскируя части, которые уже продублированы в A. Использование @ подхода Untubu asvoid в сочетании с in1d.

dt = np.dtype((np.void, A.dtype.itemsize * A.shape[-1]))

def asvoid(arr):
    arr = np.ascontiguousarray(arr)
    if np.issubdtype(arr.dtype, np.floating):
        arr += 0.
    return arr.view(dt).squeeze()

Для построения массива ваш l oop может выглядеть примерно так:

while True:
    B = op(A)
    mask = np.in1d(asvoid(B), asvoid(A), invert=True)
    if mask.any():
        A = np.concatenate((A, B[mask]), axis=0)
    else:
        break

Когда вы закончите, у вас будет две перестановки строк: A и op(A). Вы можете вычислить индекс сортировки от одного к другому, используя метод, подобный методу { ссылка }:

oa = np.argsort(asvoid(A), axis=0)
ob = np.argsort(asvoid(B), axis=0)
ib = np.empty_like(oa)
ib[ob] = np.arange(B.shape[0])
J = oa[ib]

Вы также можете наращивать J постепенно, так как вы знаете, что каждый элемент A на данной итерации уже имеет J, тогда как приращение с предыдущей итерации (B) может или не может быть. На самом деле, вам следует звонить op только с постоянно уменьшающейся B, если закрытие гарантировано. Единственная проблема заключается в том, что вам нужно будет поддерживать A в отсортированном порядке (argsorted в порядке), так как вы добавляете элементы B для облегчения поиска.

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