Numpy:向通道广播行值



我有一个数据集,其中前48个观测值是时间序列,其他12个是静态变量:

h1 h2 h3 h4 ... h48 v1 v2 v3 v4 v5 v6 .. vn
h1 h2 h3 h4 ... h48 v1 v2 v3 v4 v5 v6 .. vn

一个项目的形状是CCD_ 1。

我想将变量v1 v2 v3 v4 v5 v6 .. vn作为时间序列的附加通道传递,即创建形状为(367, 48, 13)的数组。我想马上做,因为完全转换的数据集不适合我的RAM。

我现在使用的代码效率很低(items是批处理的(:

def preprocessor(items):
items_new = np.zeros(shape=(items.shape[0], 367, 48, 13), dtype=np.float32)
for idx_item, item in enumerate(items):
train_data = item[:,:48]
train_vars = item[:,48:]
train_new = np.zeros((train_data.shape[0], train_data.shape[1],(train_vars.shape[1]+1)))
for idx_row, row in enumerate(train_data):
for idx_col, elem in enumerate(row):
train_new[idx_row, idx_col, :] = np.concatenate([[elem], train_vars[idx_row]])
items_new[idx_item] = train_new
return items_new

我能在没有循环的情况下做得更快吗?

编辑:

最小可重复性示例:

arr = np.random.randn(5,367,60)
arr2 = preprocessor(arr)
print(arr2.shape) # (5, 367, 48, 13)

方法#1

我们可以使用广播数组分配来实现矢量化解决方案-

def array_assign(items):    
L = 48 # slice at this column ID
N = items.shape[-1]
out = np.empty(shape= items.shape[:2] + (L,N-L+1), dtype=np.float32)
out[...,1:] = items[...,None,L:]
out[...,0] = items[...,:L]
return out

方法#2

我们也可以使用广播视图,然后连接-

def broadcast_concat(items):    
L = 48 # slice at this column ID
N = items.shape[-1]
a = items[...,:L,None]
shp_b = items.shape[:2] + (L,N-L)
b = np.broadcast_to(items[...,None,L:],shp_b)
out = np.concatenate((a,b),axis=-1)
return out

计时-

In [321]: items = np.random.rand(5,367,60)
In [322]: %timeit array_assign(items)
1000 loops, best of 3: 923 µs per loop
In [323]: %timeit broadcast_concat(items)
1000 loops, best of 3: 781 µs per loop

为了进行公平的比较,我们应该让第二种方法也使用更有效的float32dtype。让我们使用该数据类型来设置输入数据并再次测试-

In [335]: items = np.random.rand(5,367,60).astype(np.float32)
In [336]: %timeit array_assign(items)
1000 loops, best of 3: 897 µs per loop
In [337]: %timeit broadcast_concat(items)
1000 loops, best of 3: 348 µs per loop

因此,对于需要数据类型转换的情况下的最具性能的方法,我们可以在方法#2开始时使用items = np.asarray(items, dtype=np.float32)

这是另一个使用repeat和concatenate的解决方案。

a = items[:,:,:48, np.newaxis]
b = items[:,:,48:].repeat(a.shape[2], axis=1).reshape(*a.shape[:-1], -1)
return np.concatenate([a,b], axis=3)

最新更新