У меня есть трехмерный массив numpy = a, содержащий координаты точек в пространстве. Преобразуя этот массив через операции с матрицей, я получил массив 4D numpy, так что для каждой строки a имеется соответствующий трехмерный блок в 4D массиве после матричных преобразований (включая операцию идентификации). Таким образом, ось нуля обоих массивов равна.
Теперь мне нужно найти, присутствует ли какая-либо строка с индексом [i] или нет в j-й строке, если она есть, либо удалить я или j (не имеет значения, если это я или j). Также я =! j, так как мы имеем операцию тождества. В качестве примера, чтобы уточнить:
>>> a # 3d array
array([[[0, 1, 2],
[0, 0, 2]],
[[2, 0, 0],
[0, 0, 2]],
[[0, 2, 1],
[0, 0, 0]]])
>>> b #4d array after applying transformation to 3d array(a)
array([[[[0, 1, 2],
[0, 0, 2]],
[[0, 0, 0],
[2, 1, 1]],
[[0, 2, 1],
[0, 0, 1]]],
[[[2, 0, 0],
[0, 0, 2]],
[[0, 2, 2],
[2, 0, 0]],
[[2, 2, 2],
[1, 0, 2]]],
[[[0, 2, 1],
[0, 0, 0]],
[[2, 0, 0],
[0, 0, 2]],
[[2, 0, 1],
[2, 2, 0]]]])
Теперь, если вы посмотрите внимательно, a будет таким же, как b [:, 0]. Причина - преобразование идентичности. Поэтому мы, конечно, не хотим сравнивать [0] с b [0]. A [1] = b [2,0], поэтому код должен удалить либо [1], либо [2], но не оба. Конечным результатом будет:
>>> output
array([[[0, 1, 2],
[0, 0, 2]],
[[2, 0, 0],
[0, 0, 2]]])
ИЛИ ЖЕ,
>>> output
array([[[0, 1, 2],
[0, 0, 2]],
[[0, 2, 1],
[0, 0, 0]]])
Первый золь. Золь. пока у меня есть это,
def giveuniquestructures_fast(marray, symarray, noofF):
""" Removes configurations ith (2d block of marray) which are found in symmarray at jth position such that i != j """
# noofF is the number of points in each configuration(i.e. noofF = len(marray[0])
# The shape of the two arrays is, marray 3D-array(positions, nofF, 3),
# symarray 4D-array(positions, symmetryopration, noofF, 3)
print("Sorting the input arrays:\\n")
symarray = sort4D(symarray) # sorting the symarray(4D-array)
marray = sorter3d_v1(marray) # sorting the marray(3D-array)
print("sorting is complete now comparison is starting: ")
delindex = np.empty(0, dtype=int)
delcheck = False
print("The total number of configurations are", len(marray))
# flattening the array to reduce one dimension
symarray = symarray.reshape(marray.shape[0],-1,3*noofF)
marray = marray.reshape(-1, 3*noofF)
bol = np.ones(symarray.shape[0], dtype=bool)
# boolean array for masking the symarray along 0-axis
for i in range(len(marray)):
print("checking %dth configuration for symmetrical equivalencey \\n" % i)
bol[i] = False
bol1 = marray[i] == symarray[bol]
bol1 = bol1.all(-1)
bol[i] = True # setting it back to true for next run
if bol1.any() :
delindex = np.append(delindex, i)
delcheck = True
if delcheck:
marray = np.delete(marray, delindex, 0)
print("Search for UNique configurations are ending now :\\n")
return marray.reshape(-1, noofF,3) # converting back to input shape
-----------just в случае, если u хочет видеть функции сортировки ------------
def sorter3d_v1(a):
"""sorts the 1D blocks within 2D blocks of array in order of first column, 2nd column, 3rd column"""
print("Input array is \\n", a)
print("shape of input array is ",a.shape)
ind = np.lexsort((a[:,:,2], a[:,:,1], a[:,:,0]), axis=1) # getting the sorter index
s = np.arange(len(a))[:,np.newaxis] # getting the evenly distributed number array based on length of ind to select the sorted
a = a[s,ind,:]
print("sorted array is \\n")
print(a)
return a
Как вы, наверное, догадались, проблема с этой функцией - это эффективность. Если входной массив имеет строки даже в 1/10 млн., Для запуска цикла требуется много времени. Фактическое узкое место лежит в заявлении, в котором используется функция np.all(), т.е.
bol1 = bol1.all(-1)
Любая помощь по его улучшению будет высоко оценена. Надеюсь, это не смущает.
Второе решение Второе решение, которое я смог кодировать с векторизации:
def giveuniquestructures_fast_v1(marray, symarray, noofF):
"""The new implementation of the previous function (uniquestructures_fast) """
# The shape of the two arrays is, marray 3D-array(positions, nofF, 3),
# symarray 4D-array(positions, symmetryopration, noofF, 3)
try:
if (len(marray) != len(symarray)):
raise Exception("The length of the two arrays doesn't match")
except Exception:
raise
print("Sorting the input arrays:\\n")
symarray = sort4D(symarray) # sorting the barray(4D-array)
marray = sorter3d_v1(marray) # sorting the marray(3D-array)
print("sorting is complete now comparison is starting: ")
print("The total number of configurations is", len(marray))
# flattening the array to reduce one dimension
symarray = symarray.reshape(symarray.shape[0], -1, 3 * noofF)
marray = marray.reshape(-1, 3 * noofF)
# Batch operation may give Memory error in case array is big!!!
bol = marray[:,np.newaxis,np.newaxis,:] == symarray # 4d array
maskindices = np.arange(len(bol)) # to falsify the identity matrix operaterated values
bol[maskindices[:,np.newaxis], maskindices[:,np.newaxis]] = False # setting the identity rows value to False
delindices = np.where(bol.all(-1)) # The first and second tuple entries are relevant for next step
# Need to check for swapping indices as possibility of removing both equal arrays may happen
# removing the configurations which are symmetrically equivalent
marray = np.delete(marray, np.unique(delindices,axis=-1)[0], 0)
# reverting the dimensions back to the input array dimensions
marray = marray.reshape(-1, noofF, 3)
print("Search for UNique configurations are ending now :\\n")
return marray
Проблема со вторым золем. Векторизация не помогает, когда массив становится достаточно большим, чтобы вызвать ошибку памяти. Есть идеи?!!
Если у вас достаточно памяти, вы можете напрямую проверить 3D-массив на 4d. Поскольку первый имеет форму (N,M,K)
а второй имеет форму (N,L,M,K)
, вы можете использовать
a == marray.transpose(1,0,2,3)
который является булевым по форме (L,N,M,K)
после трансляции. Если вы проверяете .all()
этого булева вдоль последние 3 осей вы получите массив формы (L,)
дают вам вторые индексы в marray
, где он идентичен. a
Поэтому вам нужно взять другие индексы, плюс первый (поскольку мы знаем, что первый элемент всегда даст нам копию a
):
inds_identical = (a == marray).all(axis=(1,2,3))
# keep indices where 'a' is transformed into something different
keep_inds = ~inds_identical
# keep identity as well to get a single copy of 'a'
keep_inds[0] = True
marray = marray[:, keep_inds, ...]
Обратите внимание, что это может стоить времени (a == marray.transpose(1,0,2,3)).all(axis=(1,2,3))
против (a == marray.transpose(1,0,2,3)).copy().all(axis=(1,2,3))
, так как несмежные шаги в первом могут привести к значительной разнице в производительности (но последняя версия копирует огромный массив, поэтому либо может быть быстрее).
Как всегда с векторизации, цена на скорость - это память. Если он подходит, он должен быть быстрее, чем ваш цикл.
Также обратите внимание, что, если ваши массивы не являются целыми, вам не нужно точно проверять их значения, а использовать np.isclose(a, marray.transpose(1,0,2,3))
чтобы допускать некоторые ошибки с плавающей запятой.