Python numpy recarray:可以使用指针算法获取不同字段的视图吗?

时间:2012-08-02 08:59:42

标签: python numpy recarray

我有一个以下形式的numpy结构化数组:

x = np.array([(1,2,3)]*2, [('t', np.int16), ('x', np.int8), ('y', np.int8)])

我现在希望为此数组生成视图,该数组与't''x'合并'y'。通常的语法创建一个副本:

v_copy = x[['t', 'y']]
v_copy
#array([(1, 3), (1, 3)], 
#     dtype=[('t', '<i2'), ('y', '|i1')])

v_copy.base is None
#True

这并不意外,因为选择两个字段是“花式索引”,此时numpy放弃并复制。由于我的实际记录很大,我想不惜一切代价避免复制。

在numpy的跨步内存模型中无法访问所需的元素,这一点都不正确。查看内存中的各个字节:

x.view(np.int8)
#array([1, 0, 2, 3, 1, 0, 2, 3], dtype=int8)

可以找出必要的进步:

v = np.recarray((2,2), [('b', np.int8)], buf=x, strides=(4,3))
v
#rec.array([[(1,), (3,)],
#    [(1,), (3,)]], 
#    dtype=[('b', '|i1')])
v.base is x
#True

显然,v指向内存中的正确位置而未创建副本。不幸的是,numpy不允许我将这些内存位置重新解释为原始数据类型:

v_view = v.view([('t', np.int16), ('y', np.int8)])
#ValueError: new type not compatible with array.

有没有办法欺骗numpy做这个演员,以便创建一个等同于v_view的数组v_copy,但没有制作副本?也许直接在v.__array_interface__上工作,就像np.lib.stride_tricks.as_strided()

中所做的那样

2 个答案:

答案 0 :(得分:1)

你可以像这样构建一个合适的dtype

dt2 = np.dtype(dict(names=('t', 'x'), formats=(np.int16, np.int8), offsets=(0, 2)))

然后再做

y = np.recarray(x.shape, buf=x, strides=x.strides, dtype=dt2)

在未来的Numpy版本(&gt; 1.6)中,您也可以

dt2 = np.dtype(dict(names=('t', 'x'), formats=(np.int16, np.int8), offsets=(0, 2), itemsize=4))
y = x.view(dt2)

答案 1 :(得分:0)

这适用于numpy 1.6.x并避免创建recarray

dt2 = {'t': (np.int16, 0), 'y': (np.int8, 3)}
v_view = np.ndarray(x.shape, dtype=dt2, buffer=x, strides=x.strides)
v_view
#array([(1, 3), (1, 3)], 
#    dtype=[('t', '<i2'), ('', '|V1'), ('y', '|i1')])
v_view.base is x
#True

可以将它包装在类重载np.ndarray

class arrayview(np.ndarray):
    def __new__(subtype, x, fields):
        dtype = {f: x.dtype.fields[f] for f in fields}
        return np.ndarray.__new__(subtype, x.shape, dtype,
                                  buffer=x, strides=x.strides)

v_view = arrayview(x, ('t', 'y'))
v_view
#arrayview([(1, 3), (1, 3)], 
#    dtype=[('t', '<i2'), ('', '|V1'), ('y', '|i1')])
v_view.base is x
#True