是否有一种智能且简单的方法将两个切片操作合并为一个?
说我有类似
的东西arange(1000)[::2][10:20]
>>> array([20, 22, 24, 26, 28, 30, 32, 34, 36, 38])
当然在这个例子中这不是问题,但如果数组非常大,我非常想避免创建中间数组(或者没有?)。我认为应该可以将两个切片结合起来,但也许我正在监督一些事情。 所以这个想法就像是:
arange(1000)[ slice(None,None,2) + slice(10,20,None) ]
这当然不起作用,但我想做的。是否有任何组合切片对象? (尽管我努力,但我找不到任何东西)。
答案 0 :(得分:3)
slice
子类化,以实现切片的叠加。只需覆盖__add__
(或__mul__
- 数学家肯定更喜欢*
符号来叠加)。但它会引用一些数学。顺便说一句,你可以用这些东西制作一个漂亮的Python包; - )<强> P上。 S。通常,可以使用多个切片来使代码更好,更清晰。即使是以下其中一行之间的简单选择:
v = A[::2][10:20]
v = A[20:40][::2]
v = A[20:40:2]
可以深刻反映程序逻辑,使代码自我记录。
还有一个例子:如果你有一个平坦的NumPy数组并且想要提取长度为position
的位置length
的子数组,你可以这样做
v = A[position : position + length]
或
v = A[position:][:length]
自己决定哪个选项看起来更好。 ; - )
答案 1 :(得分:0)
你可以使用islice
,它可能不会更快,但会通过作为生成器来避免中间条目:
arange = range(1000)
from itertools import islice
islice(islice(arange, None, None, 2), 10, 20)
%timeit list(islice(islice(arange, None, None, 2), 10, 20))
100000 loops, best of 3: 2 us per loop
%timeit arange[::2][10:20]
100000 loops, best of 3: 2.64 us per loop
所以,快一点。
答案 2 :(得分:0)
正如@Tigran所说,使用Numpy数组时切片成本没有。但是,通常我们可以使用来自slice.indices的信息将两个切片组合在一起,其中
从切片对象切片中检索[s]开始,停止和步长索引,假定长度为一系列长度
我们可以减少
x[slice1][slice2]
到
x[combined]
第一次切片返回一个新对象,然后通过第二次切片将其切片。因此,我们还需要数据对象的长度来正确组合切片。 (第一个维度中的长度)
所以,我们可以写
def slice_combine(slice1, slice2, length):
"""
returns a slice that is a combination of the two slices.
As in
x[slice1][slice2]
becomes
combined_slice = slice_combine(slice1, slice2, len(x))
x[combined_slice]
:param slice1: The first slice
:param slice2: The second slice
:param length: The length of the first dimension of data being sliced. (eg len(x))
"""
# First get the step sizes of the two slices.
slice1_step = (slice1.step if slice1.step is not None else 1)
slice2_step = (slice2.step if slice2.step is not None else 1)
# The final step size
step = slice1_step * slice2_step
# Use slice1.indices to get the actual indices returned from slicing with slice1
slice1_indices = slice1.indices(length)
# We calculate the length of the first slice
slice1_length = (abs(slice1_indices[1] - slice1_indices[0]) - 1) // abs(slice1_indices[2])
# If we step in the same direction as the start,stop, we get at least one datapoint
if (slice1_indices[1] - slice1_indices[0]) * slice1_step > 0:
slice1_length += 1
else:
# Otherwise, The slice is zero length.
return slice(0,0,step)
# Use the length after the first slice to get the indices returned from a
# second slice starting at 0.
slice2_indices = slice2.indices(slice1_length)
# if the final range length = 0, return
if not (slice2_indices[1] - slice2_indices[0]) * slice2_step > 0:
return slice(0,0,step)
# We shift slice2_indices by the starting index in slice1 and the
# step size of slice1
start = slice1_indices[0] + slice2_indices[0] * slice1_step
stop = slice1_indices[0] + slice2_indices[1] * slice1_step
# slice.indices will return -1 as the stop index when slice.stop should be set to None.
if start > stop:
if stop < 0:
stop = None
return slice(start, stop, step)
然后,让我们进行一些测试
import sys
import numpy as np
# Make a 1D dataset
x = np.arange(100)
l = len(x)
# Make a (100, 10) dataset
x2 = np.arange(1000)
x2 = x2.reshape((100,10))
l2 = len(x2)
# Test indices and steps
indices = [None, -1000, -100, -99, -50, -10, -1, 0, 1, 10, 50, 99, 100, 1000]
steps = [-1000, -99, -50, -10, -3, -2, -1, 1, 2, 3, 10, 50, 99, 1000]
indices_l = len(indices)
steps_l = len(steps)
count = 0
total = 2 * indices_l**4 * steps_l**2
for i in range(indices_l):
for j in range(indices_l):
for k in range(steps_l):
for q in range(indices_l):
for r in range(indices_l):
for s in range(steps_l):
# Print the progress. There are a lot of combinations.
if count % 5197 == 0:
sys.stdout.write("\rPROGRESS: {0:,}/{1:,} ({2:.0f}%)".format(count, total, float(count) / float(total) * 100))
sys.stdout.flush()
slice1 = slice(indices[i], indices[j], steps[k])
slice2 = slice(indices[q], indices[r], steps[s])
combined = slice_combine(slice1, slice2, l)
combined2 = slice_combine(slice1, slice2, l2)
np.testing.assert_array_equal(x[slice1][slice2], x[combined],
err_msg="For 1D, slice1: {0},\tslice2: {1},\tcombined: {2}\tCOUNT: {3}".format(slice1, slice2, combined, count))
np.testing.assert_array_equal(x2[slice1][slice2], x2[combined2],
err_msg="For 2D, slice1: {0},\tslice2: {1},\tcombined: {2}\tCOUNT: {3}".format(slice1, slice2, combined2, count))
# 2 tests per loop
count += 2
print("\n-----------------")
print("All {0:,} tests passed!".format(count))
谢天谢地,我们
所有15059,072次测试都通过了!
答案 3 :(得分:-1)
非常简单:
arange(1000)[20:40:2]
应该