3

I have an array, e.g. arr = [1, 2, 3, 4], and m = 3. I want to make a matrix with m rows, repeating that array. The output of the example would be

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

How can I do this? I tried by

np.vstack((arr, arr, arr))

However, as I understood it, this only works if I effectively hardcore m.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
Katenn
  • 41
  • 4
  • The last sentence of your question is throwing me off. Up until then, it sounds like you're just trying to print the same array M times. What is the stack for? – hgs3 Jan 28 '21 at 20:46
  • @hgs3, If I print the same array several times the output would be the same? – Katenn Jan 28 '21 at 20:48

3 Answers3

5

There are a number of options in numpy:

  1. The simplest is np.stack, with the new axis set to 0:

    result = np.stack((arr,) * m, axis=0)
    

    This is a generalization of np.vstack, which can accept a variable m in the same way:

    result = np.vstack((arr,) * m)
    
  2. Since you are looking to expand the first dimension and not the second, you can use np.tile:

    result = np.tile(arr, [m, 1])
    
  3. For this simple case, you can repeat the elements individually for the same result using np.repeat. This is a bit hacky, but it works just as well:

    result = np.repeat([arr], m, axis=0)
    

    If arr is already a numpy array, you can add the leading dimension more explicitly:

    result = np.repeat(arr[None, :], m, axis=0)
    
  4. A slightly more convoluted method, but which showcases what is going on under the hood better is using np.concatenate:

    np.concatenate(([arr],) * m, axis=0)
    
  5. In the same spirit as concatenate, you can use the constructor np.array directly:

    np.array([arr] * m)
    
  6. An ugly method is to use muliplication (combined with broadcasting):

    result = arr * np.ones((m, 1), dtype=np.int8)
    

    Setting the dtype to a very small integer type pretty much ensures that the result will be promoted to the actual type of your array.

  7. The previous methods copy the array multiple times to get the 2D data. But since the data is repeated, you don't actually need to copy it. Instead, you can make a view that creates a fake first dimension using broadcasting. Specifically, the np.broadcast_to function will do exactly what you want:

     result = np.broadcast_to(arr, [m, len(arr)])
    
  8. There is a more general approach even than the previous to making views is np.lib.stride_tricks.as_strided.

    First, let's reiterate the warning from the documentation:

    Warning

    This function has to be used with extreme care, see notes.

    Unless you know the byte-size of the dtype you plan on using ahead of time, it's a good idea to ensure that arr is a numpy array to get the strides from it:

    arr = np.asanyarray(arr)
    result = np.lib.stride_tricks.as_strided(arr, shape=(m, arr.size), strides=(0,) + arr.strides)
    

In the last two cases, if you want to expand the view into a full buffer that contains a proper copy for each element, you can copy the data:

result = result.copy()

If you don't do the expansion, you will effectively be simulating the behavior of multiple references to the same list, where modifying any element changes all elements in the same column.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
1

You can use:

import numpy as np
arr, m = [1,2,3,4], 3

np.vstack([arr]*m)

Output:

array([[1, 2, 3, 4],
       [1, 2, 3, 4],
       [1, 2, 3, 4]])

On another note, why do you need to create such a matrix? You may be looking for numpy broadcasting without the need of repeating your array.

ti7
  • 16,375
  • 6
  • 40
  • 68
Quang Hoang
  • 146,074
  • 10
  • 56
  • 74
0

You can do:

n = [1,2,3,4]
m = 3

i = 0; 
array = []

while(i<m):
    array.append(n)
    i+=1

print(array)

=> [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]

  • 2
    This is actually a common trap! `list` objects are by-reference, so the lists are a collection of pointers; try changing one `array[1][2] = 10`: `[[1, 2, 10, 4], [1, 2, 10, 4], [1, 2, 10, 4]]` **@Quang Hoang**'s answer gets around this because it's not a list, but a [`numpy.array`](https://numpy.org/doc/stable/reference/generated/numpy.array.html) – ti7 Jan 28 '21 at 20:55
  • Ah ok, thank you for this reply! You‘r absolutely right – Schwarztrinker Jan 28 '21 at 21:07
  • @Schwarztrinker. You can simulate the list behavior using numpy stride magic too, as in the last two methods I show in my answer – Mad Physicist Jan 28 '21 at 21:30