2017-10-01 8 views
2

J'ai la matrice de ligne numpy suivante.Quelle est la meilleure façon de créer une matrice de blocs à partir d'un vecteur ligne?

X = np.array([1,2,3]) 

Je veux créer une matrice de bloc comme suit:

1 0 0 
2 1 0 
3 2 1 
0 3 2 
0 0 3 

Comment puis-je faire cela en utilisant numpy?

+0

Quelle est la relation de ces deux? Convolution? –

+3

Le dernier élément (ligne 5, col-3) est-il vraiment '1'? – Divakar

+1

Peut-être essayer https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.roll.html –

Répondre

1

Approche # 1: L'utilisation np.lib.stride_tricks.as_strided -

from numpy.lib.stride_tricks import as_strided as strided 

def zeropad_arr_v1(X): 
    n = len(X) 
    z = np.zeros(len(X)-1,dtype=X.dtype) 
    X_ext = np.concatenate((z, X, z)) 

    s = X_ext.strides[0] 
    return strided(X_ext[n-1:], (2*n-1,n), (s,-s), writeable=False) 

Notez que cela crée une sortie read-only. Si vous avez besoin d'écrire plus tard, faites simplement une copie en ajoutant .copy() à la fin.

Approche # 2: en utilisant la concaténation avec des zéros puis écrêtage/découpage -

def zeropad_arr_v2(X): 
    n = len(X) 
    X_ext = np.concatenate((X, np.zeros(n,dtype=X.dtype))) 
    return np.tile(X_ext, n)[:-n].reshape(-1,n,order='F') 

Approche # 1 étant une méthode basée sur les progrès devrait être très efficace sur la performance.

runs exemples -

In [559]: X = np.array([1,2,3]) 

In [560]: zeropad_arr_v1(X) 
Out[560]: 
array([[1, 0, 0], 
     [2, 1, 0], 
     [3, 2, 1], 
     [0, 3, 2], 
     [0, 0, 3]]) 

In [561]: zeropad_arr_v2(X) 
Out[561]: 
array([[1, 0, 0], 
     [2, 1, 0], 
     [3, 2, 1], 
     [0, 3, 2], 
     [0, 0, 3]]) 

tests Runtime

In [611]: X = np.random.randint(0,9,(1000)) 

# Approach #1 (read-only) 
In [612]: %timeit zeropad_arr_v1(X) 
100000 loops, best of 3: 8.74 µs per loop 

# Approach #1 (writable) 
In [613]: %timeit zeropad_arr_v1(X).copy() 
1000 loops, best of 3: 1.05 ms per loop 

# Approach #2 
In [614]: %timeit zeropad_arr_v2(X) 
1000 loops, best of 3: 705 µs per loop 

# @user8153's solution 
In [615]: %timeit hstack_app(X) 
100 loops, best of 3: 2.26 ms per loop 
2

Si vous lisez la matrice de sortie souhaitée de haut en bas, puis de gauche à droite, vous voyez le motif 1,2,3, 0,0,0, 1,2,3, 0,0,0, 1, 2,3. Vous pouvez utiliser ce modèle pour créer facilement un réseau linéaire, puis remodeler dans la forme à deux dimensions:

import numpy as np 
X = np.array([1,2,3]) 
N = len(X) 
zeros = np.zeros_like(X) 
m = np.hstack((np.tile(np.hstack((X,zeros)),N-1),X)).reshape(N,-1).T 
print m 

donne

[[1 0 0] 
[2 1 0] 
[3 2 1] 
[0 3 2] 
[0 0 3]] 
1

Une autre solution inscriptibles:

def block(X): 
    n=X.size 
    zeros=np.zeros((2*n-1,n),X.dtype) 
    zeros[::2]=X 
    return zeros.reshape(n,-1).T 

essayer:

In [2]: %timeit block(X) 
600 µs ± 33 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)