Python: slicing a multi-dimensional array
If you use numpy
, this is easy:
slice = arr[:2,:2]
or if you want the 0's,
slice = arr[0:2,0:2]
You'll get the same result.
*note that slice
is actually the name of a builtin-type. Generally, I would advise giving your object a different "name".
Another way, if you're working with lists of lists*:
slice = [arr[i][0:2] for i in range(0,2)]
(Note that the 0's here are unnecessary: [arr[i][:2] for i in range(2)]
would also work.).
What I did here is that I take each desired row 1 at a time (arr[i]
). I then slice the columns I want out of that row and add it to the list that I'm building.
If you naively try: arr[0:2]
You get the first 2 rows which if you then slice again arr[0:2][0:2]
, you're just slicing the first two rows over again.
*This actually works for numpy arrays too, but it will be slow compared to the "native" solution I posted above.
Numpy multi-dimensional array slicing
You can use np.r_
to concatenate slice objects:
newarr [:,:,1:10] = oldarr[:,:,np.r_[1:7,8:11]]
Example:
np.r_[1:4,6:8]
array([1, 2, 3, 6, 7])
How is multidimensional array slicing/indexing implemented in numpy?
We can verify your first level inferences with a simple class:
In [137]: class Foo():
...: def __getitem__(self,arg):
...: print(arg)
...: return None
...:
In [138]: f=Foo()
In [139]: f[1]
1
In [140]: f[::3]
slice(None, None, 3)
In [141]: f[,]
File "<ipython-input-141-d115e3c638fb>", line 1
f[,]
^
SyntaxError: invalid syntax
In [142]: f[:,]
(slice(None, None, None),)
In [143]: f[:,:3,[1,2,3]]
(slice(None, None, None), slice(None, 3, None), [1, 2, 3])
numpy
uses code like this in np.lib.index_tricks.py
to implement "functions" like np.r_
and np.s_
. They are actually class instances that use an index syntax.
It's worth noting that it's the comma, most so than the ()
that creates a tuple:
In [145]: 1,
Out[145]: (1,)
In [146]: 1,2
Out[146]: (1, 2)
In [147]: () # exception - empty tuple, no comma
Out[147]: ()
That explains the syntax. But the implementation details are left up to the object class. list
(and other sequences like string
) can work with integers and slice
objects, but give an error when given a tuple.
numpy
is happy with the tuple. In fact passing a tuple via getitem
was added years ago to base Python because numpy
needed it. No base classes use it (that I know of); but user classes can accept a tuple, as my example shows.
As for the numpy
details, that requires some knowledge of numpy
array storage, including the role of the shape
, strides
and data-buffer. I'm not sure if I want get into those now.
A few days ago I explored one example of multidimensional indexing, and discovered some nuances that I wasn't aware of (or ever seen documented)
view of numpy with 2D slicing
For most of us, understanding the how-to of indexing is more important than knowing the implementation details. I suspect there are textbooks, papers and even Wiki pages that describe 'strided' multidimensional indexing. numpy
isn't the only place that uses it.
https://numpy.org/doc/stable/reference/arrays.indexing.html
This looks like a nice intro to numpy arrays
https://ajcr.net/stride-guide-part-1/
Slicing multi-dimensional array with another array
You could do this:
Q[tuple(s)]
Or this:
np.take(Q, s)
Both of these yield array([0.58383736, 0.80486868])
.
I'm afraid I don't have a great intuition for exactly why the tuple version of s
works differently from indexing with s
itself. The other thing I intuitively tried is Q[*s]
but that's a syntax error.
tuple as index in multidimensional array together with slicing
You can do the following:
import numpy as np
A = np.arange(12).reshape((2, 3, 2))
print(A)
x = [1, 1]
print(A[(slice(None), *x)])
You can use slice(None)
instead of :
to build a tuple of slices. The tuple environment allows for value unpacking with the * operator.
Output:
[[[ 0 1]
[ 2 3]
[ 4 5]]
[[ 6 7]
[ 8 9]
[10 11]]]
[3 9]
To verify it matches:
import numpy as np
A = np.arange(12).reshape((2, 3, 2))
x = [1, 1]
s = (slice(None), *x)
print(np.allclose(A[s], A[:, 1, 1])) # True
*This is a modification of answers found here: Slicing a numpy array along a dynamically specified axis
Edit to reflect edit on question and comment:
To clarify, you can unpack any iterable you like in the tuple environment. The * operator functions normally in within the tuple. Order your elements however you like. Mix in different iterables, types, slice(None)
, how ever you want to build your slices, as long as you end up with a valid sequence of values, it will behave as expected.
import numpy as np
A = np.arange(12).reshape((2, 3, 2))
t = [True, False]
x = [1, 1]
print(np.allclose(A[(*t, *x)], A[True, False, 1, 1])) # True
You can also add full lists as well in the tuple:
print(np.allclose(A[(t, *x)], A[[True, False], 1, 1])) # True
Python array slicing -- How can 2D array slicing be implemented?
obj[,:3]
is not valid python so it will raise a SyntaxError
-- Therefore, you can't have that syntax in your source file. (It fails when you try to use it on a numpy
array as well)
Getting indices of different lengths to slice a multidimensional numpy array
I think this should work:
m = np.arange(F.shape[1]) < K
Rnew = R.copy()
Rnew[np.nonzero(m)[0], np.argsort(F)[m]] += 1
Since the first line uses broadcasting, np.tile()
is not needed.
Notice that there is a possible ambiguity of the results: since each row of F
has values that are repeated several times (e.g. 0.1 in the first row and -0.4 in the second) np.argsort()
may give different orderings of elements of F
, depending on how these equal values get sorted. This may change which entries of the matrix R
will get incremented. For example, instead of incrementing R[0, 7]
, R[0, 8]
, and R[1, 7]
, the code may increment the entries R[0, 2]
, R[0, 9]
and R[1, 1]
. To get unambiguous results you can specify that np.argsort()
must use a stable sorting algorithm, which will preserve the relative order of elements with equal values:
m = np.arange(F.shape[1]) < K
Rnew = R.copy()
Rnew[np.nonzero(m)[0], np.argsort(F, kind="stable")[m]] += 1
In this particular example this will increment the entries R[0, 2]
, R[0, 7]
and R[1, 1]
. You need to decide if this is the result that meets your needs.
Related Topics
About the Pil Error -- Ioerror: Decoder Zip Not Available
Python Command Line Input in a Process
Run Powershell Function from Python Script
Sorting a Dictionary with Lists as Values, According to an Element from the List
Why Does CSVwriter.Writerow() Put a Comma After Each Character
Importerror: No Module Named Tensorflow
Checking Odd/Even Numbers and Changing Outputs on Number Size
Loop Over a List Containing Path to Sound Files
Writing to a File in a for Loop Only Writes the Last Value
Search by Objectid in Mongodb with Pymongo
Populate a Pandas Sparsedataframe from a Scipy Sparse Matrix
Python - When to Use File VS Open
Python Parse Comma-Separated Number into Int
Python/Selenium Incognito/Private Mode
How to Return a Subset of a List That Matches a Condition