2017-04-04 64 views
2

您好我正在使用numpy为LSTM创建一个具有时间步长和多个功能的新阵列。使用Timesteps和多个功能创建一个新阵列,例如对于LSTM

我已经看过一些使用步幅和重塑的方法,但还没有设法找到一个有效的解决方案。

这是一个解决玩具问题的函数,但是我有30,000个样本,每个样本都有100个特征。

def make_timesteps(a, timesteps): 
     array = [] 
     for j in np.arange(len(a)): 
      unit = [] 
      for i in range(timesteps): 
       unit.append(np.roll(a, i, axis=0)[j]) 
      array.append(unit) 
     return np.array(array) 

inArr = np.array([[1, 2], [3,4], [5,6]])

inArr.shape =>(3,2)

outArr = make_timesteps(inArr, 2)

outArr.shape =>(3,2,2)

assert(np.array_equal(outArr, 
      np.array([[[1, 2], [3, 4]], [[3, 4], [5, 6]], [[5, 6], [1, 2]]]))) 

=>真

有没有更好的方式做到这一点(必须有!!)有人可以帮忙吗?

回答

1

一个窍门是将最后的L-1行附加到数组外并将这些行追加到数组的开头。那么,这将是一个简单的例子,使用非常高效的NumPy strides。对于那些想知道这个技巧的成本的人来说,正如我们稍后将通过时序测试所看到的那样,它没有任何好处。

诀窍领先的高达将支持在代码向前和向后跨步会是这个样子的最终目标 -

向后跨步:

def strided_axis0_backward(inArr, L = 2): 
    # INPUTS : 
    # a : Input array 
    # L : Length along rows to be cut to create per subarray 

    # Append the last row to the start. It just helps in keeping a view output. 
    a = np.vstack((inArr[-L+1:], inArr)) 

    # Store shape and strides info 
    m,n = a.shape 
    s0,s1 = a.strides 

    # Length of 3D output array along its axis=0 
    nd0 = m - L + 1 

    strided = np.lib.stride_tricks.as_strided  
    return strided(a[L-1:], shape=(nd0,L,n), strides=(s0,-s0,s1)) 

向前跨步:

def strided_axis0_forward(inArr, L = 2): 
    # INPUTS : 
    # a : Input array 
    # L : Length along rows to be cut to create per subarray 

    # Append the last row to the start. It just helps in keeping a view output. 
    a = np.vstack((inArr , inArr[:L-1])) 

    # Store shape and strides info 
    m,n = a.shape 
    s0,s1 = a.strides 

    # Length of 3D output array along its axis=0 
    nd0 = m - L + 1 

    strided = np.lib.stride_tricks.as_strided  
    return strided(a[:L-1], shape=(nd0,L,n), strides=(s0,s0,s1)) 

样品运行 -

In [42]: inArr 
Out[42]: 
array([[1, 2], 
     [3, 4], 
     [5, 6]]) 

In [43]: strided_axis0_backward(inArr, 2) 
Out[43]: 
array([[[1, 2], 
     [5, 6]], 

     [[3, 4], 
     [1, 2]], 

     [[5, 6], 
     [3, 4]]]) 

In [44]: strided_axis0_forward(inArr, 2) 
Out[44]: 
array([[[1, 2], 
     [3, 4]], 

     [[3, 4], 
     [5, 6]], 

     [[5, 6], 
     [1, 2]]]) 

运行试验 -

In [53]: inArr = np.random.randint(0,9,(1000,10)) 

In [54]: %timeit make_timesteps(inArr, 2) 
    ...: %timeit strided_axis0_forward(inArr, 2) 
    ...: %timeit strided_axis0_backward(inArr, 2) 
    ...: 
10 loops, best of 3: 33.9 ms per loop 
100000 loops, best of 3: 12.1 µs per loop 
100000 loops, best of 3: 12.2 µs per loop 

In [55]: %timeit make_timesteps(inArr, 10) 
    ...: %timeit strided_axis0_forward(inArr, 10) 
    ...: %timeit strided_axis0_backward(inArr, 10) 
    ...: 
1 loops, best of 3: 152 ms per loop 
100000 loops, best of 3: 12 µs per loop 
100000 loops, best of 3: 12.1 µs per loop 

In [56]: 152000/12.1 # Speedup figure 
Out[56]: 12561.98347107438 

strided_axis0的定时保持不变,甚至当我们增加子阵列的长度在输出中。这只是为了向我们展示strides带来的巨大收益,当然还有疯狂的加速也超过了原来的loopy版本。

截至一开始答应了,这里的一对堆叠成本时序与np.vstack -

In [417]: inArr = np.random.randint(0,9,(1000,10)) 

In [418]: L = 10 

In [419]: %timeit np.vstack((inArr[-L+1:], inArr)) 
100000 loops, best of 3: 5.41 µs per loop 

时序支持堆叠是一个很有效的一个的想法。

+0

非常感谢 - 这确实有所帮助,我曾看过as_strided,但直到您的示例和链接都无法理解它!为了获得相同的顺序,我用第一行加上最后一行,然后在第一行上加上np.flip。我编辑了这个问题来显示我的最终代码。 – nickyzee

+0

@nickyzee我不认为我明白你为什么需要'翻转“。你的'make_timesteps'是正确的,因为我编码试图产生与'make_timesteps'相同的结果。用你的翻页建议,我的代码产生的结果与'make_timesteps'不同。澄清这一点? – Divakar

+0

有趣 - 翻转是需要做出相同的输出,因为我从原来的。目视检查输出也证实了这一点。不知道为什么 - numpy @ latest和py3.5 - 我原来的返回数组([[[1,2], [3,4]], [[3,4], [5,6]] , [[5,6], [7,8], [[7,8], [1,2]]])' – nickyzee