ruby-numo / numo-narray

Ruby/Numo::NArray - New NArray class library
http://ruby-numo.github.io/narray/
BSD 3-Clause "New" or "Revised" License
413 stars 41 forks source link

Way to get a range of sub-arrays similar to numpy's `x[a:b]` #218

Open jneen opened 2 months ago

jneen commented 2 months ago

Hey there! Thanks for this software.

I'm attempting to do some audio processing, which involves a lot of splitting a big 2d array into smaller chunks. My wave is of shape [big_number, 2], for 2-channel stereo audio, and I'm attempting to slice this to get a time range. I would expect, for example, wave[0...1024] to result in an array of shape [1024, 2], but it seems to treat the whole thing as flat and just return an array of shape [1024].

I had a search through the docs and examples and couldn't find anything like this - is there a way to take this kind of slice or do i have to math out the size and reshape afterwards?

jneen commented 2 months ago

Concrete example:

[10] pry(Spectrum)> @samples
=> Numo::SFloat#shape=[6513231,2]
[[0, 3.05185e-05], 
 [3.05185e-05, 6.1037e-05], 
 [6.1037e-05, 6.1037e-05], 
 [3.05185e-05, 0], 
 [0, -3.05185e-05], 
 [0, -3.05185e-05], 
 [0, -3.05185e-05], 
 [0, 0], 
 [3.05185e-05, 3.05185e-05], 
 [6.1037e-05, 3.05185e-05], 
 [9.15555e-05, 3.05185e-05], 
 [6.1037e-05, 3.05185e-05], 
 [-6.1037e-05, -6.1037e-05], 
 [-0.000152593, -9.15555e-05], 
 [-0.000152593, -9.15555e-05], 
 [-0.000122074, -6.1037e-05], 
 [0, 3.05185e-05], 
 [6.1037e-05, 3.05185e-05], 
 [0, -0.000152593], 
 [-3.05185e-05, -0.000244148], 
 ...
[11] pry(Spectrum)> @samples[0...1024]
=> Numo::SFloat(view)#shape=[1024]
[0, 3.05185e-05, 3.05185e-05, 6.1037e-05, 6.1037e-05, 6.1037e-05, ...]
jneen commented 2 months ago

I think the thing I would want (and how normal ruby arrays work) is more similar to this:

[4] pry(Spectrum)> @samples[0...2048].reshape(1024, 2)
=> Numo::SFloat#shape=[1024,2]
[[0, 3.05185e-05], 
 [3.05185e-05, 6.1037e-05], 
 [6.1037e-05, 6.1037e-05], 
 [3.05185e-05, 0], 
 [0, -3.05185e-05], 
 [0, -3.05185e-05], 
 [0, -3.05185e-05], 
 [0, 0], 
 [3.05185e-05, 3.05185e-05], 
 [6.1037e-05, 3.05185e-05], 
 [9.15555e-05, 3.05185e-05], 
 [6.1037e-05, 3.05185e-05], 
 [-6.1037e-05, -6.1037e-05], 
 [-0.000152593, -9.15555e-05], 
 [-0.000152593, -9.15555e-05], 
 [-0.000122074, -6.1037e-05], 
 [0, 3.05185e-05], 
 [6.1037e-05, 3.05185e-05], 
 [0, -0.000152593], 
 [-3.05185e-05, -0.000244148], 
 ...

But this feels like it leaks the abstraction of shapes a little bit and forces me to think of it as a totally flattened array.

kojix2 commented 2 months ago

Hi @jneen I'm not very familiar with NumPy, so I don't know if my answer is what you expect, but I think you can use true.

import numpy as np

x = np.array([[1, 2, 3, 4],
              [5, 6, 7, 8],
              [9, 10, 11, 12]])

x[1:3]
# array([[ 5,  6,  7,  8],
#       [ 9, 10, 11, 12]])
require 'numo/narray'

x = Numo::Int32[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
]

x[1...3, true]
# x[1..2, true]

# Numo::Int32(view)#shape=[2,4]
# [[5, 6, 7, 8], 
#  [9, 10, 11, 12]]

I'm glad you're interested in NArray.

jneen commented 2 months ago

Oh! That's... certainly an interesting way to do it. Thanks!