Let A
, x
, y
and z
be some vectors or matrices of appropriate size. Then in MATLAB one can build a "super matrix" B
out of them very easily:
A = [1 2;3 4];
x = [4;5];
y = [1 2];
z = 4;
B = [A x;y z];
The output is:
>> B
B =
1 2 4
3 4 5
1 2 4
What is the best way to achieve the same effect in NumPy?
You can use numpy.block
:
In [27]: a
Out[27]:
array([[1, 2],
[3, 4]])
In [28]: x
Out[28]:
array([[4],
[5]])
In [29]: y
Out[29]: array([1, 2])
In [30]: z
Out[30]: 4
In [31]: np.block([[a, x], [y, z]])
Out[31]:
array([[1, 2, 4],
[3, 4, 5],
[1, 2, 4]])
You can achieve this by using the concatenate function. From the official documentation, here you are a pretty self-explanatory example:
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
np.concatenate((a, b), axis=0)
array([[1, 2],
[3, 4],
[5, 6]])
np.concatenate((a, b.T), axis=1)
array([[1, 2, 5],
[3, 4, 6]])
The most literal copy of MATLAB notation is:
In [166]: A = np.matrix('1 2;3 4')
...: x = np.matrix('4;5')
...: y = np.matrix('1 2')
...: z = np.matrix('4')
...:
In [167]: A
Out[167]:
matrix([[1, 2],
[3, 4]])
In [168]: x
Out[168]:
matrix([[4],
[5]])
In [169]: y
Out[169]: matrix([[1, 2]])
In [170]: z
Out[170]: matrix([[4]])
In [171]: np.bmat('A x; y z')
Out[171]:
matrix([[1, 2, 4],
[3, 4, 5],
[1, 2, 4]])
With string input like this bmat
has to look up the corresponding variables in the workspace, and so on. It has a MATLAB like feel, but is awkward Python. Note that np.matrix
is always 2d, just like the original MATLAB.
Using a more conventional nested list input:
In [173]: np.block([[A,x],[y,z]])
Out[173]:
matrix([[1, 2, 4],
[3, 4, 5],
[1, 2, 4]])
block
also works with np.array
objects:
In [174]: np.block([[A.A,x.A],[y.A,z.A]])
Out[174]:
array([[1, 2, 4],
[3, 4, 5],
[1, 2, 4]])
With proper Python/numpy syntax:
In [181]: Aa = np.array([[1, 2],[3, 4]])
...: xa = np.array([[4],[5]])
...: ya = np.array([1, 2])
...: za = np.array([4])
In [187]: np.block([[Aa, xa],[ya, za]])
Out[187]:
array([[1, 2, 4],
[3, 4, 5],
[1, 2, 4]])
Internally block
uses concatenate
. I think it used to use hstack
and vstack
, now it works its way down recursively.
In [190]: np.vstack([np.hstack([Aa, xa]),np.hstack([ya, za])])
Out[190]:
array([[1, 2, 4],
[3, 4, 5],
[1, 2, 4]])
@Mad asked about r_
and c_
. Those are versions of the concatenate
family that use a [] syntax (because they are actually class objects with a getitem
method). For the 2d matrix inputs, this works (and is relatively pretty):
In [214]: np.r_[np.c_[A, x], np.c_[y, z]]
Out[214]:
matrix([[1, 2, 4],
[3, 4, 5],
[1, 2, 4]])
np.r_[np.c_[A.A, x.A], np.c_[y.A, z.A]]
also works.
For the arrays that are a mix of 2d and 1d I have to use:
np.r_[np.r_['1,2', Aa, xa], np.r_['1,2', ya, za]]
The string '2' tells it to expand the elements to 2d before concatenating. I haven't used that string argument much, and had to experiment before I got it right.
The last expression is doing:
np.concatenate([np.concatenate([Aa, xa], axis=1),
np.concatenate([ya[None,:], za[None,:]], axis=1)],
axis=0)
While I'm at it, another version:
np.r_['0,2', np.c_[Aa, xa], np.r_[ya, za]]
Eveything that hstack
, vstack
, r_
and c_
can do can be done just as fast with concatenate
and a few dimension adjustments.
test