英文:
How can I efficiently stretch a one-dimensional array to an arbitrary size without interpolating?
问题
我正在尝试将一维数组拉伸到任意大小而不进行插值。
例如:
>>> my_array
*[0,1,8,4]*
>>> stretch(my_array, 7)
*[0,0,1,1,8,8,4]*
或者
>>> my_array
*[6,3,7,1]*
>>> stretch(my_array, 10)
*[6,6,3,3,3,7,7,7,1,1]*
等等。
我的天真方法确切地实现了我想要的功能。
def interp(list, length):
out = np.zeros(length, dtype=np.uint)
for x in range(length):
out[x] = list[int(x * (len(list)/length))]
return out
然而,这被证明是非常慢的;我尝试在每帧中执行几十次/几百次这样的操作。
numpy.interp 方法对于连续函数很好用,但我也想处理非连续的数据(就像示例中那样)。
numpy.repeat 接近,但只能将数组拉伸到某个整数倍数。
谢谢阅读!
编辑:为了澄清,我想做的是一维最近邻插值。
例如:
[ 5| 5| 7| 7| 7| 9| 9]
[ 5 | 7 | 9 ]
我尝试从底部数组到顶部,对于任意大小。
目标数组的每个单元格映射到输入数组中的最近邻居。
英文:
I'm trying to stretch a one-dimensional array to an arbitrary size without interpolating.
Ex:
>>> my_array
*[0,1,8,4]*
>>> stretch(my_array, 7)
*[0,0,1,1,8,8,4]*
or
>>> my_array
*[6,3,7,1]*
>>> stretch(my_array, 10)
*[6,6,3,3,3,7,7,7,1,1]*
etc.
My naive approach does exactly what I want.
def interp(list, length):
out = np.zeros(length, dtype=np.uint)
for x in range(length):
out[x] = list[int(x * (len(list)/length))]
return out
However, this has proven to be extremely slow; I'm trying to do this dozens/hundreds of times per frame.
numpy.interp method works fine for a continuous function, but I'm trying to manipulate non-continuous data as well. (as in the examples)
numpy.repeat is close, but can only stretch an array by some whole number multiple.
Thanks for reading!
EDIT: To clarify, I guess I'm trying to do nearest-neighbor interpolation in one dimension.
Ex:
[ 5| 5| 7| 7| 7| 9| 9]
[ 5 | 7 | 9 ]
I'm trying to get from the bottom array to the top, for any arbitrary size.
Each cell of the target array maps to its nearest neighbor in the input array.
答案1
得分: 1
精确的逻辑不清楚,但可能的矢量解决方案是使用numpy.repeat
和切片:
my_array = np.array([0,1,8,4])
def stretch(a, n):
return np.repeat(a, np.ceil(n/len(a)))[:n]
stretch(my_array, 7)
# array([0, 0, 1, 1, 8, 8, 4])
stretch(my_array, 10)
# array([0, 0, 0, 1, 1, 1, 8, 8, 8, 4])
您可以根据您的期望规则调整切片部分。
英文:
The exact logic is unclear, but a vectorial solution might be to use numpy.repeat
and slicing:
my_array = np.array([0,1,8,4])
def stretch(a, n):
return np.repeat(a, np.ceil(n/len(a)))[:n]
stretch(my_array, 7)
# array([0, 0, 1, 1, 8, 8, 4])
stretch(my_array, 10)
# array([0, 0, 0, 1, 1, 1, 8, 8, 8, 4])
You can adapt the slicing part with your desired rule
答案2
得分: 1
Create a list of m
indexes running from 0
to n-1
, by the formula k * n // m
, and generate a new list by dereferencing the initial list, using an implicit loop.
E.g.
[6, 3, 7, 1] -> [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3] -> [6, 6, 6, 3, 3, 3, 7, 7, 7, 1, 1]
One-liner:
print([a[k * n // m] for k in range(m)])
Two-liner:
i= [k * n // m for k in range(m)]
print([a[i[k]] for k in range(m)])
If n
and m
are constant, you compute the indexes once for all. I doubt one can do much better.
OpenCV's resize
does just that in the INTER_NEAREST
mode. If done on a single image row, the overhead will probably be unbearable. If done on multiple rows, that might be faster.
英文:
Create a list of m
indexes running from 0
to n-1
, by the formula k * n // m
, and generate a new list by dereferencing the initial list, using an implicit loop.
E.g.
[6, 3, 7, 1] -> [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3] -> [6, 6, 6, 3, 3, 3, 7, 7, 7, 1, 1]
One-liner:
print([a[k * n // m] for k in range(m)])
Two-liner:
i= [k * n // m for k in range(m)]
print([a[i[k]] for k in range(m)])
If n
and m
are constant, you compute the indexes once for all. I doubt one can do much better.
OpenCV's resize
does just that in the INTER_NEAREST
mode. If done on a single image row, the overhead will probably be unbearable. If done on multiple rows, that might be faster.
答案3
得分: 0
使用np.linspace
生成索引的方法与Yves方法类似。
import numpy as np
def stretch(arr, length):
idx = np.linspace(0, len(arr), length, endpoint=False).astype(np.int64)
return arr[idx]
np.random.seed(1234)
arr = np.random.randint(0, 10, 10)
stretch(arr, 15)
时间性能比较:
%timeit [arr[k * len(arr) // 1000000] for k in range(1000000)]
%timeit stretch(arr, 1000000)
将10个元素拉伸到1,000,000个元素时,使用stretch方法比普通方法快40倍。
英文:
Similar to Yves method but using np.linspace
to generate the indices.
import numpy as np
def stretch( arr, length ):
idx = np.linspace( 0, len(arr), length, endpoint = False).astype( np.int64 )
# endpoint = False to get the final index as len(arr) - 1
# print( idx )
# print( arr[idx] )
return arr[idx]
np.random.seed( 1234 )
arr = np.random.randint( 0, 10, 10 )
arr
# array([3, 6, 5, 4, 8, 9, 1, 7, 9, 6])
stretch( arr, 15 )
# array([3, 3, 6, 5, 5, 4, 8, 8, 9, 1, 1, 7, 9, 9, 6])
Timings
%timeit [arr[k * len(arr) // 1000000] for k in range(1000000)]
284 ms ± 3.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit stretch( arr, 1000000 )
6.37 ms ± 18.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Stretching 10 elements to a 1,000,000 is 40 times as fast with stretch.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论