1

I would like to translate a matlab code into a python one. The matlab code is equivalent to the following toy example:

a = [1 2 3; 4 5 6; 7 8 9]
b = a(:, ones(1,3))

It returns

a =

 1     2     3
 4     5     6
 7     8     9

b =

 1     1     1
 4     4     4
 7     7     7

I tried to translate it like this:

from numpy import array
from numpy import ones

a = array([ [1,2,3], [4,5,6], [7,8,9] ])
b = a[:][ones((1,3))]

but it returns the following error message:

Traceback (most recent call last): File "example_slice.py", line 6, in b =a[:, ones((1,3))] IndexError: arrays used as indices must be of integer (or boolean) type

EDIT: maybe ones should be replaced by zeros in this particular case but it is not the problem here. The question deals with the problem of giving a list containing the same index many times to the array a in order to get the same array b as the one computed with Matlab.

Aleph
  • 1,343
  • 1
  • 12
  • 27
  • That would be `import numpy as np ; b = np.repeat(a[:,0,None],3,axis=1)`. – Divakar May 06 '19 at 17:10
  • 1
    To replicate the identical behavior, you need to index. So, something like - `idx = np.zeros((1,3),dtype=int)`; `b = np.take_along_axis(a,idx,axis=1)`. – Divakar May 06 '19 at 17:16
  • `a[:]` does nothing. `np.ones()` has default `float` dtype. By `ones` do you want index `one` or `True` boolean? – hpaulj May 06 '19 at 18:18

3 Answers3

2

The MATLAB code can also be written (more idiomatically and more clearly) as:

b = repmat(a(:,1),1,3);

In NumPy you'd write:

b = np.tile(a[:,None,0],(1,3))

(Note the None needed to preserve the orientation of the vector extracted).

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • Your answer sounds great but it returns [[1 4 7 1 4 7 1 4 7]] instead of the expected two dimensional array. Do you know how to fix it? – Aleph May 06 '19 at 17:27
  • Ok, I got it. Just switch 1 and 3 here. – Aleph May 06 '19 at 17:28
  • According to your comment, `b=numpy.matlib.repmat(a[:,0], 3, 1)` seems to be a more elegant solution, right? – Aleph May 06 '19 at 17:35
  • 2
    @Aleph: You are right, it always trips me up that NumPy changes the orientation of vectors extracted from a matrix. See edit. Your `numpy.matlab.repmat` solution is good too, I guess, I got error messages using that, maybe my NumPy is too old. :) – Cris Luengo May 06 '19 at 17:39
1

You could use list comprehension with np.full() to create arrays of certain values.

import numpy as np

a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
b = np.array([np.full(len(i), i[0]) for i in a])

print(b)

Output:

[[1 1 1]
 [4 4 4]
 [7 7 7]]
Filip Młynarski
  • 3,534
  • 1
  • 10
  • 22
  • Glad to have been of help! Feel free to [accept one of the answers](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) if you feel it was useful to you. :) – Filip Młynarski May 06 '19 at 17:33
  • Yes, I am comparing the different solutions and I will mark one as the answer but all answers seem good! :) – Aleph May 06 '19 at 17:36
1
In [568]: a = np.array([ [1,2,3], [4,5,6], [7,8,9] ])                                
In [569]: a[:,0]                                                                     
Out[569]: array([1, 4, 7])
In [570]: a[:,[0,0,0]]                                                               
Out[570]: 
array([[1, 1, 1],
       [4, 4, 4],
       [7, 7, 7]])

In [571]: a[:, np.zeros(3, dtype=int)]  # int dtype to avoid your error                                       
Out[571]: 
array([[1, 1, 1],
       [4, 4, 4],
       [7, 7, 7]])

====

In [572]: np.zeros(3)                                                                
Out[572]: array([0., 0., 0.])
In [573]: np.zeros(3, int)                                                           
Out[573]: array([0, 0, 0])

Earlier numpy versions allowed float indices, but newer ones have tightened the requirement.

hpaulj
  • 221,503
  • 14
  • 230
  • 353