У меня есть две разные проблемы с обработкой массивов, которые я хотел бы решить AQAP (Q = быстро), чтобы гарантировать, что решения не ограничивают скорость в моем процессе (используя NEAT для обучения бота видеоигры). В одном случае я хочу создать функцию штрафа за увеличение высоты столбцов, а в другом - вознаграждение за создание «островков общего значения».
Операции начинаются с массива столбцов размером 26 строк и 6 столбцов. значений в градациях серого с черным / 0 фоном.
У меня есть рабочие решения для каждой проблемы, в которых уже реализован какой-то клочок, но я хотел бы настаивать на полностью векторизованном подходе к обоим.
import numpy as np,
from scipy.ndimage.measurements import label as sp_label
from math import ceil
Обе проблемы начинаются с массива, подобного следующему:
img= np.array([[ 0., 0., 0., 12., 0., 0.],
[ 0., 0., 0., 14., 0., 0.],
[ 0., 0., 0., 14., 0., 0.],
[ 0., 0., 0., 14., 0., 0.],
[16., 0., 0., 14., 0., 0.],
[16., 0., 0., 12., 0., 0.],
[12., 0., 11., 0., 0., 0.],
[12., 0., 11., 0., 0., 0.],
[16., 0., 15., 0., 15., 0.],
[16., 0., 15., 0., 15., 0.],
[14., 0., 12., 0., 11., 0.],
[14., 0., 12., 0., 11., 0.],
[14., 15., 11., 0., 11., 0.],
[14., 15., 11., 0., 11., 0.],
[13., 16., 12., 0., 13., 0.],
[13., 16., 12., 0., 13., 0.],
[13., 14., 16., 0., 16., 0.],
[13., 14., 16., 0., 16., 0.],
[16., 14., 15., 0., 14., 0.],
[16., 14., 15., 0., 14., 0.],
[14., 16., 14., 0., 11., 0.],
[14., 16., 14., 0., 11., 0.],
[11., 13., 14., 16., 12., 13.],
[11., 13., 14., 16., 12., 13.],
[12., 12., 15., 14., 15., 11.],
[12., 12., 15., 14., 15., 11.]])
Первая (высота столбца) проблема в настоящее время решается с помощью:
# define valid connection directions for sp_label
c_valid_conns = np.array((0,1,0,0,1,0,0,1,0,), dtype=np.int).reshape((3,3))
# run the island labeling function sp_label
# c_ncomponents is a simple count of the conected columns in labeled
columns, c_ncomponents = sp_label(img, c_valid_conns)
# calculate out the column lengths
col_lengths = np.array([(columns[columns == n]/n).sum() for n in range(1, c_ncomponents+1)])
col_lengths
, чтобы получить этот массив: [6. 22. 20. 18. 14. 4. 4.]
(бонус, если код постоянно игнорирует помеченную область, которая «не содержит» нижней части массива (индекс строки 25 / -1))
Вторая проблема включает маскирование для каждого уникального значения и вычисление смежных тел в каждом маскированном массиве, чтобы получить размер смежных тел:
# initial values to start the ball rolling
values = [11, 12, 13, 14, 15, 16]
isle_avgs_i = [1.25, 2, 0, 1,5, 2.25, 1]
# apply filter masks to img to isolate each value
# Could these masks be pushed out into a third array dimension instead?
masks = [(img == g) for g in np.unique(values)]
# define the valid connectivities (8-way) for the sp_label function
m_valid_conns = np.ones((3,3), dtype=np.int)
# initialize islanding lists
# I'd love to do away with these when I no longer need the .append() method)
mask_isle_avgs, isle_avgs = [],[]
# for each mask in the image:
for i, mask in enumerate(masks):
# run the island labeling function sp_label
# m_labeled is the array containing the sequentially labeled islands
# m_ncomponents is a simple count of the islands in m_labeled
m_labeled, m_ncomponents = sp_label(mask, m_valid_conns)
# collect the average (island size-1)s (halving to account for...
# ... y resolution) for each island into mask_isle_avgs list
# I'd like to vectorize this step
mask_isle_avgs.append((sum([ceil((m_labeled[m_labeled == n]/n).sum()/2)-1
for n in range(1, m_ncomponents+1)]))/(m_ncomponents+1))
# add up the mask isle averages for all the islands...
# ... and collect into isle_avgs list
# I'd like to vectorize this step
isle_avgs.append(sum(mask_isle_avgs))
# initialize a difference list for the isle averages (I also want to do away with this step)
d_avgs = []
# evaluate whether isle_avgs is greater for the current frame or the...
# ... previous frame (isle_avgs_i) and append either the current...
# ... element or 0, depending on whether the delta is non-negative
# I want this command vectorized
[d_avgs.append(isle_avgs[j])
if (isle_avgs[j]-isle_avgs_i[j])>=0
else d_avgs.append(0) for j in range(len(isle_avgs))]
d_avgs
, чтобы дать мне этот массив d_avgs: [0,0, 0,46785714285714286, 1,8678571428571429, 0, 0]
(еще раз, если код постоянно игнорирует помеченную область, которая не "содержит" нижнюю часть массива (индекс строки 25 / -1), чтобы вместо этого дать этомассив:
[0, 0, 0.43452380952380953, 1.6345238095238095, 0, 0])
Я ищу, чтобы удалить все операции со списками и их понимания и переместить их в полностью векторизованную реализацию numpy / scipy сте же результаты.
Любая помощь в удалении любого из этих шагов будет принята с благодарностью.