Skip to content

add point slicing to dask.array.core - #439

Merged
mrocklin merged 14 commits into
dask:masterfrom
mrocklin:point-slice
Jul 31, 2015
Merged

mrocklin merged 14 commits into
dask:masterfrom
mrocklin:point-slice

Conversation

@mrocklin

Copy link
Copy Markdown
Member

This is equivalent to numpy slicing with multiple input lists.

We could use a better name. cc @shoyer @jhamman

Example

>>> x = np.arange(56).reshape((7, 8))
>>> x
array([[ 0,  1,  2,  3,  4,  5,  6,  7],
       [ 8,  9, 10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29, 30, 31],
       [32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47],
       [48, 49, 50, 51, 52, 53, 54, 55]])

>>> d = from_array(x, chunks=(3, 4))
>>> result = isel(d, [0, 1, 6, 0], [0, 1, 0, 7])
>>> result.compute()
array([ 0,  9, 48,  7])

Fixes #433

@shoyer

shoyer commented Jul 17, 2015

Copy link
Copy Markdown
Member

I think vindex is definitely a better name than isel (which in xray usually actually means outer indexing, not vectorized indexing).

What happens if I index into a higher dimensional array? e.g., along two axes of a 3D array -- where does the new dimension go? This is assuredly the first thing that we'll try to do in xray :).

@mrocklin

Copy link
Copy Markdown
Member Author

That case is definitely not handled with the PR as is. Looks a bit tricker but doable.

@jhamman

jhamman commented Jul 17, 2015

Copy link
Copy Markdown
Member

vindex is fine by me. Two use cases that I'm interested if we can add here:

First, as @shoyer mentions - indexing a 3+d array with 2 indexers.

The second takes that a bit further - how will we handle the case where we're indexing on the 1st and 3rd dims:

# numpy syntax / behavior
>>> x = np.arange(60).reshape((5, 4, 3))
>>> x[[1, 2, 3], :, [1, 2, 2]]
array([[13, 16, 19, 22],
       [26, 29, 32, 35],
       [38, 41, 44, 47]])

will vindex(x, [1, 2, 3], slice(None), [1, 2, 2]) work?

@mrocklin

Copy link
Copy Markdown
Member Author

Sorry to delay on this. This might require some thought and time which are in unfortunately short supply until next week.

@shoyer

shoyer commented Jul 28, 2015

Copy link
Copy Markdown
Member

I just realized that because vectorized indexing (if slice objects are omitted) is equivalent to broadcasting, we can probably write the fully general form of vectorized indexing using atop/elemwise:

import dask.array as da
import numpy as np

a = np.arange(25).reshape(5, 5)
x = da.from_array(a, chunks=3)

idx = da.from_array(np.arange(5), chunks=3)

da.core.elemwise(lambda *args: np.asarray(x)[args], idx, idx).compute()
# array([ 0,  6, 12, 18, 24])

@shoyer

shoyer commented Jul 28, 2015

Copy link
Copy Markdown
Member

On further consideration, vectorized indexing with top seems much harder than made it out to be in my last comment. Time for me to go to bed, I think...

mrocklin added 4 commits July 28, 2015 15:07
This is equivalent to numpy slicing with multiple input lists.

We could use a better name.  cc @shoyer @jhamman

Example
-------

>>> x = np.arange(56).reshape((7, 8))
>>> x
array([[ 0,  1,  2,  3,  4,  5,  6,  7],
       [ 8,  9, 10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29, 30, 31],
       [32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47],
       [48, 49, 50, 51, 52, 53, 54, 55]])

>>> d = from_array(x, chunks=(3, 4))
>>> result = isel(d, [0, 1, 6, 0], [0, 1, 0, 7])
>>> result.compute()
array([ 0,  9, 48,  7])

Fixes dask#433
@mrocklin

Copy link
Copy Markdown
Member Author

OK. This seems to work. It was hard.

I'll implement a vindex getter.

@mrocklin

Copy link
Copy Markdown
Member Author
In [1]: import dask.array as da

In [2]: import numpy as np

In [3]: x = np.arange(10*10*10).reshape((10, 10, 10))

In [4]: d = da.from_array(x, chunks=(4, 5, 6))

In [5]: d.vindex[[0, 5, 9], :, [0, 5, 9]]
Out[5]: dask.array<vindex-merge-2, shape=(3, 10), chunks=((3,), (5, 5)), dtype=int64>

In [6]: d.vindex[[0, 5, 9], :, [0, 5, 9]].compute()
Out[6]: 
array([[  0,  10,  20,  30,  40,  50,  60,  70,  80,  90],
       [505, 515, 525, 535, 545, 555, 565, 575, 585, 595],
       [909, 919, 929, 939, 949, 959, 969, 979, 989, 999]])

In [7]: d.vindex[:, [0, 5, 9], [0, 5, 9]].compute()
Out[7]: 
array([[  0,  55,  99],
       [100, 155, 199],
       [200, 255, 299],
       [300, 355, 399],
       [400, 455, 499],
       [500, 555, 599],
       [600, 655, 699],
       [700, 755, 799],
       [800, 855, 899],
       [900, 955, 999]])

@mrocklin

Copy link
Copy Markdown
Member Author

The only qualm that I have with this PR is that the code is not particularly clear. Doing this properly was non-trivial and I do not envy the next person who has to come along (quite possibly also me).

To this end further test cases are very welcome. Lets extend the amount of time until the next time someone needs to touch this.

@mrocklin

Copy link
Copy Markdown
Member Author

@jcrist points out that this doesn't yet support numpy arrays

@mrocklin

Copy link
Copy Markdown
Member Author

Fixed

Comment thread dask/array/core.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be clear: this will fail for multi-dimensional indexers, right? if so, we should catch that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now raise on multi-dimensional indexers

Comment thread dask/array/core.py Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this being used?

@mrocklin

Copy link
Copy Markdown
Member Author
In [1]: import dask.array as da

In [2]: import numpy as np

In [3]: x = np.arange(10*10*10).reshape((10, 10, 10))

In [4]: d = da.from_array(x, chunks=(4, 5, 6))

In [5]: d.vindex[[0, 5, 9], :, [0, 5, 9]]
Out[5]: dask.array<vindex-merge-2, shape=(3, 10), chunks=((3,), (5, 5)), dtype=int64>

In [6]: d.vindex[[0, 5, 9], :, [0, 5, 9]].compute()
Out[6]: 
array([[  0,  10,  20,  30,  40,  50,  60,  70,  80,  90],
       [505, 515, 525, 535, 545, 555, 565, 575, 585, 595],
       [909, 919, 929, 939, 949, 959, 969, 979, 989, 999]])

In [7]: d.vindex[:, [0, 5, 9], [0, 5, 9]].compute()
Out[7]: 
array([[  0, 100, 200, 300, 400, 500, 600, 700, 800, 900],
       [ 55, 155, 255, 355, 455, 555, 655, 755, 855, 955],
       [ 99, 199, 299, 399, 499, 599, 699, 799, 899, 999]])

@shoyer

shoyer commented Jul 31, 2015

Copy link
Copy Markdown
Member

This example is broken:

import dask.array as da
import numpy as np

a = np.arange(125).reshape(5, 5, 5)
x = da.from_array(a, chunks=3)
x.vindex[[0, 1, 2, 3], [3, 2, 1, 4]] 
# has the wrong shape (4,) and an error is raised when you compute it

@shoyer

shoyer commented Jul 31, 2015

Copy link
Copy Markdown
Member

This should raise an exception, but doesn't:

x.vindex[:, [0, 1, 2, 3], [0, 1, 2]]

@mrocklin

Copy link
Copy Markdown
Member Author

Fixed the two recent issues in two recent commits.

@mrocklin

Copy link
Copy Markdown
Member Author

Any further comments on this?

@jhamman

jhamman commented Jul 31, 2015

Copy link
Copy Markdown
Member

@mrocklin - Thanks for putting this together. I just gave it a once over and the original use case seems to be well taken care of.

@shoyer

shoyer commented Jul 31, 2015

Copy link
Copy Markdown
Member

Looks good to me

@mrocklin

Copy link
Copy Markdown
Member Author

Woot. Thanks for the detailed feedback all.

mrocklin added a commit that referenced this pull request Jul 31, 2015
add point slicing to dask.array.core
@mrocklin
mrocklin merged commit a598670 into dask:master Jul 31, 2015
@mrocklin
mrocklin deleted the point-slice branch July 31, 2015 23:29
phofl pushed a commit to phofl/dask that referenced this pull request Dec 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants