Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

ENH: Allow 0-d indexes in np.take #2725

Merged
merged 1 commit into from

3 participants

@seberg
Owner

The TakeFrom already supported this. This removes the check which made it not possible and adds some tests for take.

There may well be a good reason for it, and maybe this is too central function to make it suddenly work where it used to not work. But it puzzled me, since take accepts N-d array but specifically not 0-d.

numpy/core/tests/test_item_selection.py
@@ -0,0 +1,43 @@
+import numpy as np
+from numpy.testing import *
+import sys, warnings
+
+def test_take(level=1):
@njsmith Owner
njsmith added a note

What is the level=1 argument?

@seberg Owner
seberg added a note

woops, I was wondering what level was and forgot to remove it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@njsmith
Owner

Also, just to check that I understand, with this change we will have

>>> np.take([10, 20, 30], 1)
20

(and not an error as now, and also not anything like

>>> np.take([10, 20, 30], 1)
[20]

?)

@seberg
Owner

yes exactly.

numpy/core/tests/test_item_selection.py
((6 lines not shown))
+ a = [[1, 2], [3, 4]]
+ a_str = [['1','2'],['3','4']]
+ modes = ['raise', 'wrap', 'clip']
+ indices = [-1, 4]
+ index_arrays = [np.empty(0, dtype=np.intp),
+ np.empty(tuple(), dtype=np.intp),
+ np.empty((1,1), dtype=np.intp)]
+ real_indices = {}
+ real_indices['raise'] = {-1:1, 4:IndexError}
+ real_indices['wrap'] = {-1:1, 4:0}
+ real_indices['clip'] = {-1:0, 4:1}
+ # Currently all types but object, use the same function
+ # generation. So it should not be necessary to test all.
+ types = np.int, np.object
+ for t in types:
+ ta = np.array(a if issubclass(t, np.number) else a_str, dtype=t)
@njsmith Owner
njsmith added a note

Travis failure is legitimate: https://travis-ci.org/numpy/numpy/jobs/3172720

The ternary operator here isn't supported in Python 2.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@charris
Owner

Looks good to me. The documentation needs a note about the change, maybe in the indices parameter, with .. versionadded:: 1.8.0. You can grep on versionadded for examples. Also add something to doc/release/1.8.0-notes.rst. I don't see how adding this functionality will cause problems, so I'm inclined to put it in.

@seberg
Owner

@charris thanks started on that, just got a bit of a question. I somewhat expected things take to always return an array and not a scalar. However it actually has the code in place to convert the 0-d array to a scalar on the python side (not that it could have had an effect before this). So I guess I will just leave that, or does anyone think that np.take should always return an array, which would be different from fancy-indices?

@njsmith
Owner
@seberg seberg ENH: Allow 0-d indexes in np.take
The TakeFrom already supported this. This removes the check which
made it not possible and adds some tests for take.

Also add documentation and information to the release notes.
cde76b4
@seberg
Owner

OK, back then there was almost no response, so I guess it should return a scalar (as it does with this). There is one small unless here, and that is: unless we want to guarantee returning an array if the input is a 0-d array. This is something numpy never does (also for indexing):

In [1]: type(np.ones(10)[0])
Out[1]: numpy.float64

In [2]: type(np.ones(10)[np.array(0)])
Out[2]: numpy.float64

And quite honestly its not really worth the trouble to conserve arrays, 0-d arrays should be so rare and are so rarely conserved. This is only maybe something to maybe keep in mind if the scalar machinery gets reworked anyway.

So what I am saying I think behaving like indexing in this regard is the right thing. (Otherwise the sentence in the release notes is changed and the python 2.4 support removed in the rebase)

@njsmith
Owner

:+1:

@seberg
Owner

btw. did that :+1: mean I should/can press the big green button? :)

@njsmith
Owner

well, I guess no-one else has objected, so, yes :-)

@seberg seberg merged commit dce1018 into from
@seberg seberg deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 6, 2013
  1. @seberg

    ENH: Allow 0-d indexes in np.take

    seberg authored
    The TakeFrom already supported this. This removes the check which
    made it not possible and adds some tests for take.
    
    Also add documentation and information to the release notes.
This page is out of date. Refresh to see the latest.
View
1  doc/release/1.8.0-notes.rst
@@ -37,6 +37,7 @@ Changes
General
-------
+The function np.take now allows 0-d arrays as indices.
Deprecations
============
View
9 numpy/core/fromnumeric.py
@@ -57,6 +57,10 @@ def take(a, indices, axis=None, out=None, mode='raise'):
The source array.
indices : array_like
The indices of the values to extract.
+
+ .. versionadded:: 1.8.0
+
+ Also allow scalars for indices.
axis : int, optional
The axis over which to select values. By default, the flattened
input array is used.
@@ -96,6 +100,11 @@ def take(a, indices, axis=None, out=None, mode='raise'):
>>> a[indices]
array([4, 3, 6])
+ If `indices` is not one dimensional, the output also has these dimensions.
+
+ >>> np.take(a, [[0, 1], [2, 3]])
+ array([[4, 3],
+ [5, 7]])
"""
try:
take = a.take
View
4 numpy/core/src/multiarray/item_selection.c
@@ -44,13 +44,11 @@ PyArray_TakeFrom(PyArrayObject *self0, PyObject *indices0, int axis,
}
indices = (PyArrayObject *)PyArray_ContiguousFromAny(indices0,
NPY_INTP,
- 1, 0);
+ 0, 0);
if (indices == NULL) {
goto fail;
}
-
-
n = m = chunk = 1;
nd = PyArray_NDIM(self) + PyArray_NDIM(indices) - 1;
for (i = 0; i < nd; i++) {
View
43 numpy/core/tests/test_item_selection.py
@@ -0,0 +1,43 @@
+import numpy as np
+from numpy.testing import *
+import sys, warnings
+
+def test_take():
+ a = [[1, 2], [3, 4]]
+ a_str = [['1','2'],['3','4']]
+ modes = ['raise', 'wrap', 'clip']
+ indices = [-1, 4]
+ index_arrays = [np.empty(0, dtype=np.intp),
+ np.empty(tuple(), dtype=np.intp),
+ np.empty((1,1), dtype=np.intp)]
+ real_indices = {}
+ real_indices['raise'] = {-1:1, 4:IndexError}
+ real_indices['wrap'] = {-1:1, 4:0}
+ real_indices['clip'] = {-1:0, 4:1}
+ # Currently all types but object, use the same function generation.
+ # So it should not be necessary to test all, but the code does support it.
+ types = np.int, np.object
+ for t in types:
+ ta = np.array(a if issubclass(t, np.number) else a_str, dtype=t)
+ tresult = list(ta.T.copy())
+ for index_array in index_arrays:
+ if index_array.size != 0:
+ tresult[0].shape = (2,) + index_array.shape
+ tresult[1].shape = (2,) + index_array.shape
+ for mode in modes:
+ for index in indices:
+ real_index = real_indices[mode][index]
+ if real_index is IndexError and index_array.size != 0:
+ index_array.put(0, index)
+ assert_raises(IndexError, ta.take, index_array,
+ mode=mode, axis=1)
+ elif index_array.size != 0:
+ index_array.put(0, index)
+ res = ta.take(index_array, mode=mode, axis=1)
+ assert_array_equal(res, tresult[real_index])
+ else:
+ res = ta.take(index_array, mode=mode, axis=1)
+ assert_(res.shape == (2,) + index_array.shape)
+
+if __name__ == "__main__":
+ run_module_suite()
Something went wrong with that request. Please try again.