[英]Requesting NumPy/SciPy vectorization replacements of for loops and list comprehensions
我有兩個不同的數組處理問題,我想解決 AQAP(Q=quickly),以確保解決方案在我的過程中沒有速率限制(使用 NEAT 訓練視頻游戲機器人)。 在一種情況下,我想建立一個懲罰 function 來制造更大的柱高,而在另一種情況下,我想獎勵建立“具有共同價值的島嶼”。
操作從具有黑色/0 背景的灰度值的 26 行 x 6 列 numpy 數組開始。
對於已經實現了一些 numpy 的每個問題,我都有可行的解決方案,但我想推動對兩者都采用完全矢量化的方法。
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 實現中。
任何刪除這些步驟的幫助將不勝感激。
以下是我最終解決此問題的方法:
######## column height penalty calculation ########
# c_ncomponents is a simple count of the conected columns in labeled
columns, c_ncomponents = sp_label(unit_img, c_valid_conns)
# print(columns)
# throw out the falling block with .isin(x,x[-1]) combined with...
# the mask nonzero(x)
drop_falling = np.isin(columns, columns[-1][np.nonzero(columns[-1])])
col_hts = drop_falling.sum(axis=0)
# print(f'col_hts {col_hts}')
# calculate differentials for the (grounded) column heights
d_col_hts = np.sum(col_hts - col_hts_i)
# print(f'col_hts {col_hts} - col_hts_i {col_hts_i} ===> d_col_hts {d_col_hts}')
# set col_hts_i to current col_hts for next evaluation
col_hts_i = col_hts
# calculate penalty/bonus function
# col_pen = (col_hts**4 - 3**4).sum()
col_pen = np.where(d_col_hts > 0, (col_hts**4 - 3**4), 0).sum()
#
# if col_pen !=0:
# print(f'col_pen: {col_pen}')
######## end column height penalty calculation ########
######## color island bonus calculation ########
# mask the unit_img to remove the falling block
isle_img = drop_falling * unit_img
# print(isle_img)
# broadcast the game board to add a layer for each color
isle_imgs = np.broadcast_to(isle_img,(7,*isle_img.shape))
# define a mask to discriminate on color in each layer
isle_masked = isle_imgs*[isle_imgs==ind_grid[0]]
# reshape the array to return to 3 dimensions
isle_masked = isle_masked.reshape(isle_imgs.shape)
# generate the isle labels
isle_labels, isle_ncomps = sp_label(isle_masked, i_valid_conns)
# determine the island sizes (via return_counts) for all the unique labels
isle_inds, isle_sizes = np.unique(isle_labels, return_counts=True)
# zero out isle_sizes[0] to remove spike for background (500+ for near empty board)
isle_sizes[0] = 0
# evaluate difference to determine whether bonus applies
if isle_sizes_i.sum() != isle_sizes.sum():
# calculate bonus for all island sizes ater throwing away the 0 count
isle_bonus = (isle_sizes**3).sum()
else:
isle_bonus = 0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.