跳过numpy数组的每个第n个索引

7
为了进行K折验证,我想使用切片numpy数组的方法,这样就可以创建原始数组的视图,但每隔n个元素就会被删除。
例如:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

如果 n = 4,那么结果将会是:
[1, 2, 4, 5, 6, 8, 9]

注意:numpy的要求是由于这被用于一个机器学习作业,其中依赖关系已经固定。

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - sascha
我同意Sascha的观点。特别是,请查看交叉验证迭代器。http://scikit-learn.org/stable/modules/cross_validation.html#cross-validation-iterators - juanpa.arrivillaga
@sascha 我同意使用现有的库会更好,但是我应该提到这是一个机器学习作业,所以我只能使用numpy作为依赖。为了实现随机性,我正在使用np.random.shuffle来洗牌行。 - Ben Hazelwood
我明白。但是在洗牌之后,无论您选择每4个或前N/4个值都没有关系。后者可能更容易实现。 - sascha
3个回答

13

使用模数的方法#1

a[np.mod(np.arange(a.size),4)!=0]

运行示例 -

In [255]: a
Out[255]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [256]: a[np.mod(np.arange(a.size),4)!=0]
Out[256]: array([1, 2, 3, 5, 6, 7, 9])

使用掩码的方法#2:将需求作为“视图”

考虑到“视图”的要求,如果想要节省内存,我们可以在Linux系统上存储等效的布尔数组,这将占用8倍更少的内存。因此,使用掩码的方法会像这样 -

# Create mask
mask = np.ones(a.size, dtype=bool)
mask[::4] = 0

以下是内存需求的统计信息 -

In [311]: mask.itemsize
Out[311]: 1

In [312]: a.itemsize
Out[312]: 8

那么,我们可以将布尔索引视为一种查看方式 -

In [313]: a
Out[313]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [314]: a[mask] = 10

In [315]: a
Out[315]: array([ 0, 10, 10, 10,  4, 10, 10, 10,  8, 10])

使用NumPy数组步幅的第三种方法:将要求作为视图

如果输入数组的长度是n的倍数,则可以使用np.lib.stride_tricks.as_strided创建这样的视图。 如果不是倍数,则仍然可以工作,但不是安全的做法,因为我们将超出为输入数组分配的内存。 请注意,因此创建的视图将是2D

因此,获取这样的视图的实现方法如下:

def skipped_view(a, n):
    s = a.strides[0]
    strided = np.lib.stride_tricks.as_strided
    return strided(a,shape=((a.size+n-1)//n,n),strides=(n*s,s))[:,1:]

示例运行:

In [50]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) # Input array

In [51]: a_out = skipped_view(a, 4)

In [52]: a_out
Out[52]: 
array([[ 1,  2,  3],
       [ 5,  6,  7],
       [ 9, 10, 11]])

In [53]: a_out[:] = 100 # Let's prove output is a view indeed

In [54]: a
Out[54]: array([  0, 100, 100, 100,   4, 100, 100, 100,   8, 100, 100, 100])

非常好的答案,谢谢@Divakar #2看起来是最适合我的解决方案。 - Ben Hazelwood
@BenHazelwood 我同意,那是一个通用的解决方案。 - Divakar

2

numpy.delete :

In [18]: arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [19]: arr = np.delete(arr, np.arange(0, arr.size, 4))

In [20]: arr
Out[20]: array([1, 2, 3, 5, 6, 7, 9])

1
那看起来不像是一个视图。 - sascha
我同意@sascha的观点,如果存在更节省内存的方法,那将是更好的选择。 - Ben Hazelwood

0
我找到的最简洁的答案是使用 delete 和 i,其中 i 是您要跳过的第 n 个索引:
del list[i-1::i]

例子:

In [1]: a = list([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [2]: del a[4-1::4]
In [3]: print(a)
Out[3]: [0, 1, 2, 4, 5, 6, 8, 9]

如果你也想跳过第一个值,可以使用 a[1:]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接