Ускорьте измерения scipy ndimage, примененные к numpy 3-ий
У меня есть несколько больших помеченных numpy 2d массив (10 000x10 000). Для каждой метки (подключенных ячеек с одинаковым номером) я хочу рассчитать несколько измерений на основе значений другого массива 3-й ноль (среднее, стандартное, максимальное и т. Д.). Это возможно с помощью инструмента scipy.ndimage.labeled_comprehension, если 3-й numpy преобразуется в 2-й. Однако, поскольку количество меток и размер массивов довольно велико, вычисления занимают довольно много времени. Мой текущий код кажется избыточным, так как теперь я перебираю одни и те же метки для каждого третьего измерения входного изображения. Мне интересно, есть ли способы ускорить мой код (например, объединяя три вычисления scipy.ndimage.labeled_comprehension в один расчет).
Используя тестовый набор данных формы (4200,3000,3) и 283047 меток, расчеты заняли 10:34 минуты.
Тестовые данные
example_labels=np.array([[1, 1, 3, 3],
[1, 2, 2, 3],
[2, 2, 4, 4],
[5, 5, 5, 4]])
unique_labels=np.unique(example_labels)
value_array=np.arange(48).reshape(4,4,3)
Текущий код и желаемый вывод
def mean_std_measurement(x):
xmean = x.mean()
xstd = x.std()
vals.append([xmean,xstd])
def calculate_measurements(labels, unique_labels, value_arr):
global vals
vals=[]
ndimage.labeled_comprehension(value_array[:,:,0],labels,unique_labels,mean_std_measurement,float,-1)
val1=np.array(vals)
vals=[]
ndimage.labeled_comprehension(value_array[:,:,1],labels,unique_labels,mean_std_measurement,float,-1)
val2=np.array(vals)
vals=[]
ndimage.labeled_comprehension(value_array[:,:,2],labels,unique_labels,mean_std_measurement,float,-1)
val3=np.array(vals)
return np.column_stack((unique_labels,val1,val2,val3))
>>> print calculate_measurements(example_labels,unique_labels,value_array)
array([[ 1. , 5. , 5.09901951, 6. ,
5.09901951, 7. , 5.09901951],
[ 2. , 21. , 4.74341649, 22. ,
4.74341649, 23. , 4.74341649],
[ 3. , 12. , 6.4807407 , 13. ,
6.4807407 , 14. , 6.4807407 ],
[ 4. , 36. , 6.4807407 , 37. ,
6.4807407 , 38. , 6.4807407 ],
[ 5. , 39. , 2.44948974, 40. ,
2.44948974, 41. , 2.44948974]])
1 ответ
Список, добавленный в mean_std_measurement, вероятно, создает узкое место при работе с большими массивами. labeled_comprehension
вернет массив самостоятельно, поэтому первым делом нужно просто позволить scipy обработать конструкцию массива под капотом.
labeled_comprehension
можно применять только функции, которые выводят одно значение - я подозреваю, что именно поэтому вы использовали конструкцию списка - но мы можем обмануть это, если функция выведет комплексное значение. Другой вариант - использовать структурированные типы данных в качестве выходных данных, что было бы необходимо, если бы мы возвращали более двух значений.
import numpy as np
from scipy import ndimage
example_labels=np.array([[1, 1, 3, 3],
[1, 2, 2, 3],
[2, 2, 4, 4],
[5, 5, 5, 4]])
unique_labels=np.unique(example_labels)
value_array=np.arange(48).reshape(4,4,3)
# return a complex number to get around labled_comprehension limitations
def mean_std_measurement(x):
xmean = x.mean()
xstd = x.std()
return np.complex(xmean, xstd)
def calculate_measurements(labels, unique_labels, value_array):
val1 = ndimage.labeled_comprehension(value_array[:,:,0],labels,unique_labels,mean_std_measurement,np.complex,-1)
val2 = ndimage.labeled_comprehension(value_array[:,:,1],labels,unique_labels,mean_std_measurement,np.complex,-1)
val3 = ndimage.labeled_comprehension(value_array[:,:,2],labels,unique_labels,mean_std_measurement,np.complex,-1)
# convert the complex numbers back into reals
return np.column_stack((np.unique(labels),
val1.real,val1.imag,
val2.real,val2.imag,
val3.real,val3.imag))