如何从结构化的numpy数组*中删除列而不复制它??

时间:2016-05-06 18:31:00

标签: python arrays numpy

给定一个结构化的numpy数组,我想按名称删除某些列而不复制数组。 我知道我可以这样做:

names = list(a.dtype.names)
if name_to_remove in names:
    names.remove(name_to_remove)
a = a[names]

但是这会创建一个我想避免的数组的临时副本,因为我正在处理的数组可能非常大。

有没有好办法呢?

1 个答案:

答案 0 :(得分:5)

您可以创建一个仅包含所需字段的新数据类型,使用相同的字段偏移量和与原始数组的数据类型相同的itemsize,然后使用此新数据类型创建原始数组的视图。 dtype函数处理多种格式的参数;相关的一个在名为"Specifying and constructing data types"的文档部分中描述。向下滚动到以

开头的小节
{'names': ..., 'formats': ..., 'offsets': ..., 'titles': ..., 'itemsize': ...}

以下是一些使用这种想法的便利功能。

import numpy as np


def view_fields(a, names):
    """
    `a` must be a numpy structured array.
    `names` is the collection of field names to keep.

    Returns a view of the array `a` (not a copy).
    """
    dt = a.dtype
    formats = [dt.fields[name][0] for name in names]
    offsets = [dt.fields[name][1] for name in names]
    itemsize = a.dtype.itemsize
    newdt = np.dtype(dict(names=names,
                          formats=formats,
                          offsets=offsets,
                          itemsize=itemsize))
    b = a.view(newdt)
    return b


def remove_fields(a, names):
    """
    `a` must be a numpy structured array.
    `names` is the collection of field names to remove.

    Returns a view of the array `a` (not a copy).
    """
    dt = a.dtype
    keep_names = [name for name in dt.names if name not in names]
    return view_fields(a, keep_names)

例如,

In [297]: a
Out[297]: 
array([(10.0, 13.5, 1248, -2), (20.0, 0.0, 0, 0), (30.0, 0.0, 0, 0),
       (40.0, 0.0, 0, 0), (50.0, 0.0, 0, 999)], 
      dtype=[('x', '<f8'), ('y', '<f8'), ('i', '<i8'), ('j', '<i8')])

In [298]: b = remove_fields(a, ['i', 'j'])

In [299]: b
Out[299]: 
array([(10.0, 13.5), (20.0, 0.0), (30.0, 0.0), (40.0, 0.0), (50.0, 0.0)], 
      dtype={'names':['x','y'], 'formats':['<f8','<f8'], 'offsets':[0,8], 'itemsize':32})

通过更改b ...

验证ab[0]['x']的视图(不是副本)
In [300]: b[0]['x'] = 3.14

并且看到a也发生了变化:

In [301]: a[0]
Out[301]: (3.14, 13.5, 1248, -2)