1

Essentially, I'm looking for an efficient piece of code to generate the following matrix:

[[1 2 3 4 5]
 [2 3 4 5 6]
 [3 4 5 6 7]
 [4 5 6 7 8]
 [5 6 7 8 9]]

I came up with the following, which works, but it's not particularly pretty, and I was thinking there's probably a way to really utilize numpy for this (beyond just creating the matrix and pretty-printing it):

import copy
import numpy as np

identity_count = 5
priority_matrix = np.identity(identity_count, dtype=int)

rating_start = 1
maximum_rating = identity_count * 2
rating_range = range(rating_start, maximum_rating)

priority_copy = copy.copy(priority_matrix)

for row_idx, row in enumerate(priority_copy):
    rating_pos = 0
    for col_idx, item in enumerate(row):
        priority_matrix[row_idx][col_idx] = rating_range[rating_pos]
        rating_pos += 1
    rating_start += 1
    rating_range = range(rating_start, maximum_rating)

print(np.matrix(priority_matrix))

There has to be a more efficient way of doing this (doesn't need to be with numpy).

Thank you!

HEADLESS_0NE
  • 3,416
  • 4
  • 32
  • 51

5 Answers5

4

You're apparently describing a type of Hankel matrix.

>>> from scipy.linalg import hankel
>>> hankel(c=range(1,6), r=range(5,10))
array([[1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6],
       [3, 4, 5, 6, 7],
       [4, 5, 6, 7, 8],
       [5, 6, 7, 8, 9]])

The Hankel matrix has constant anti-diagonals. The arguments c and r specify the first column and the last row, respectively.

wim
  • 338,267
  • 99
  • 616
  • 750
1

Here's an approach using NumPy strides -

a = np.arange(1,10)
W = 5              # Row length / Window size
nrows = a.size - W + 1
n = a.strides[0]
out = np.lib.stride_tricks.as_strided(a,shape=(nrows,W),strides=(n,n))

Another way with broadcasting -

np.arange(10-W)[:,None] + np.arange(1,W+1)
Divakar
  • 218,885
  • 19
  • 262
  • 358
1

You can achieve this in a simple one-liner with a list comprehension. I'm afraid that I don't know a numpy-specific way of doing this, but you could always convert to an array afterwards.

matrix = [[x for x in range(y,y+5)] for y in range(1,6)]

roganjosh
  • 12,594
  • 4
  • 29
  • 46
1

Just throwing out another numpy-based option:

In [21]: np.arange(1,26).reshape(5,5) - np.arange(0, 20, 4)[np.newaxis].T
Out[21]:
array([[1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6],
       [3, 4, 5, 6, 7],
       [4, 5, 6, 7, 8],
       [5, 6, 7, 8, 9]])

or generalized to an arbitrary size:

In [29]: N = 10

In [30]: np.arange(N**2).reshape(N,N) - np.arange(0, N*(N-1), N-1)[np.newaxis].T + 1
Out[30]:
array([[ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10],
       [ 2,  3,  4,  5,  6,  7,  8,  9, 10, 11],
       [ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12],
       [ 4,  5,  6,  7,  8,  9, 10, 11, 12, 13],
       [ 5,  6,  7,  8,  9, 10, 11, 12, 13, 14],
       [ 6,  7,  8,  9, 10, 11, 12, 13, 14, 15],
       [ 7,  8,  9, 10, 11, 12, 13, 14, 15, 16],
       [ 8,  9, 10, 11, 12, 13, 14, 15, 16, 17],
       [ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])
Randy
  • 14,349
  • 2
  • 36
  • 42
0

How about this? using map and np.vstack

N = 5
x = np.arange(1,2*N)
np.vstack(map(lambda i: np.roll(x, -i), range(N)))[:,0:N]
b3rt0
  • 769
  • 2
  • 6
  • 21