-
-
Notifications
You must be signed in to change notification settings - Fork 11k
ENH: add np.stack #5605
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: add np.stack #5605
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
from __future__ import division, absolute_import, print_function | ||
|
||
__all__ = ['atleast_1d', 'atleast_2d', 'atleast_3d', 'vstack', 'hstack'] | ||
__all__ = ['atleast_1d', 'atleast_2d', 'atleast_3d', 'vstack', 'hstack', | ||
'stack'] | ||
|
||
from . import numeric as _nx | ||
from .numeric import array, asanyarray, newaxis | ||
|
@@ -196,9 +197,10 @@ def vstack(tup): | |
|
||
See Also | ||
-------- | ||
stack : Join a sequence of arrays along a new axis. | ||
hstack : Stack arrays in sequence horizontally (column wise). | ||
dstack : Stack arrays in sequence depth wise (along third dimension). | ||
concatenate : Join a sequence of arrays together. | ||
concatenate : Join a sequence of arrays along an existing axis. | ||
vsplit : Split array into a list of multiple sub-arrays vertically. | ||
|
||
Notes | ||
|
@@ -246,9 +248,10 @@ def hstack(tup): | |
|
||
See Also | ||
-------- | ||
stack : Join a sequence of arrays along a new axis. | ||
vstack : Stack arrays in sequence vertically (row wise). | ||
dstack : Stack arrays in sequence depth wise (along third axis). | ||
concatenate : Join a sequence of arrays together. | ||
concatenate : Join a sequence of arrays along an existing axis. | ||
hsplit : Split array along second axis. | ||
|
||
Notes | ||
|
@@ -275,3 +278,73 @@ def hstack(tup): | |
return _nx.concatenate(arrs, 0) | ||
else: | ||
return _nx.concatenate(arrs, 1) | ||
|
||
def stack(arrays, axis=0): | ||
""" | ||
Join a sequence of arrays along a new axis. | ||
|
||
The `axis` parameter specifies the index of the new axis in the dimensions | ||
of the result. For example, if ``axis=0`` it will be the first dimension | ||
and if ``axis=-1`` it will be the last dimension. | ||
|
||
.. versionadded:: 1.10.0 | ||
|
||
Parameters | ||
---------- | ||
arrays : sequence of array_like | ||
Each array must have the same shape. | ||
axis : int, optional | ||
The axis in the result array along which the input arrays are stacked. | ||
|
||
Returns | ||
------- | ||
stacked : ndarray | ||
The stacked array has one more dimension than the input arrays. | ||
|
||
See Also | ||
-------- | ||
concatenate : Join a sequence of arrays along an existing axis. | ||
split : Split array into a list of multiple sub-arrays of equal size. | ||
|
||
Examples | ||
-------- | ||
>>> arrays = [np.random.randn(3, 4) for _ in range(10)] | ||
>>> np.stack(arrays, axis=0).shape | ||
(10, 3, 4) | ||
|
||
>>> np.stack(arrays, axis=1).shape | ||
(3, 10, 4) | ||
|
||
>>> np.stack(arrays, axis=2).shape | ||
(3, 4, 10) | ||
|
||
>>> a = np.array([1, 2, 3]) | ||
>>> b = np.array([2, 3, 4]) | ||
>>> np.stack((a, b)) | ||
array([[1, 2, 3], | ||
[2, 3, 4]]) | ||
|
||
>>> np.stack((a, b), axis=-1) | ||
array([[1, 2], | ||
[2, 3], | ||
[3, 4]]) | ||
|
||
""" | ||
arrays = [asanyarray(arr) for arr in arrays] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens with mixed subtypes? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could maybe check that all types are the same. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could do that by checking that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens for subtypes is mostly dictated by the behavior of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the type checking should be left for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to ot D7AF hers. Learn more. OK. |
||
if not arrays: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO this is idiomatic way to write this in Python (but I don't care too much either way) |
||
raise ValueError('need at least one array to stack') | ||
|
||
shapes = set(arr.shape for arr in arrays) | ||
if len(shapes) != 1: | ||
raise ValueError('all input arrays must have the same shape') | ||
|
||
result_ndim = arrays[0].ndim + 1 | ||
if not -result_ndim <= axis < result_ndim: | ||
msg = 'axis {0} out of bounds [-{1}, {1})'.format(axis, result_ndim) | ||
raise IndexError(msg) | ||
if axis < 0: | ||
axis += result_ndim | ||
|
||
sl = (slice(None),) * axis + (_nx.newaxis,) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An alternative method, once you have the shape of the arrays, is
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or, getting rid of
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like using slicing for this operation rather than reshape because I know that slicing will always using a view rather than a copy. Though I suppose |
||
expanded_arrays = [arr[sl] for arr in arrays] | ||
return _nx.concatenate(expanded_arrays, axis=axis) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need more explanation here. For instance, in the examples, it isn't clear why
np.stack((a, b))
is not the same asnp.stack((a, b), axis=-1)
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the missing explanation is that the
axis
argument refers to the axis position in the result array, not in the input arrays.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still needs a better explanation of where the new axis is located. It might also be better to follow the list insertion protocol.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although it is nice to indicate appending the axis with a simple
-1
. In the current case, an explanation of how negative axis values are handled would help. For the list version you could do something likeThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about