从numpy结构化数组中删除列(数组中的元组列表)?

时间:2016-04-25 10:02:13

标签: python arrays python-2.7 numpy

我使用外部库函数返回一个numpy结构化数组。

cities_array
>>> array([ (1, [-122.46818353792992, 48.74387985436505], u'05280', u'Bellingham', u'53', u'Washington', u'5305280', u'city', u'N', -99, 52179),
       (2, [-109.67985528815007, 48.54381826401885], u'35050', u'Havre', u'30', u'Montana', u'3035050', u'city', u'N', 2494, 10201),
       (3, [-122.63068540357023, 48.49221584868184], u'01990', u'Anacortes', u'53', u'Washington', u'5301990', u'city', u'N', -99, 11451),
       ...,
       (3147, [-156.45657614262274, 20.870633142444376], u'22700', u'Kahului', u'15', u'Hawaii', u'1522700', u'census designated place', u'N', 7, 16889),
       (3148, [-156.45038252004554, 20.76059218396], u'36500', u'Kihei', u'15', u'Hawaii', u'1536500', u'census designated place', u'N', -99, 11107),
       (3149, [-155.08472452266503, 19.693112205773275], u'14650', u'Hilo', u'15', u'Hawaii', u'1514650', u'census designated place', u'N', 38, 37808)], 
      dtype=[('ID', '<i4'), ('Shape', '<f8', (2,)), ('CITY_FIPS', '<U5'), ('CITY_NAME', '<U40'), ('STATE_FIPS', '<U2'), ('STATE_NAME', '<U25'), ('STATE_CITY', '<U7'), ('TYPE', '<U25'), ('CAPITAL', '<U1'), ('ELEVATION', '<i4'), ('POP1990', '<i4')])

cities_array的类型为<type 'numpy.ndarray'>

我可以访问数组的各个列:

cities_array[['ID','CITY_NAME']]
>>> array([(1, u'Bellingham'), (2, u'Havre'), (3, u'Anacortes'), ...,
       (3147, u'Kahului'), (3148, u'Kihei'), (3149, u'Hilo')], 
      dtype=[('ID', '<i4'), ('CITY_NAME', '<U40')])

现在我要删除第一列IDhelpSO questions表示它应为numpy.delete

运行时:numpy.delete(cities_array,cities_array['ID'],1)我收到错误消息:

...in delete
    N = arr.shape[axis]
IndexError: tuple index out of range

我做错了什么?我应该对cities_array进行后期处理才能使用数组吗?

我使用的是Python 2.7.10和numpy 1.11.0

2 个答案:

答案 0 :(得分:2)

我认为这应该有效:

def delete_colum(array, *args):

    filtered = [x for x in array.dtype.names if x not in args]

    return array[filtered]

数组示例:

a
Out[9]: 
array([(1, [-122.46818353792992, 48.74387985436505])], 
      dtype=[('ID', '<i4'), ('Shape', '<f8', (2,))])

delete_colum(a,'ID')
Out[11]: 
array([([-122.46818353792992, 48.74387985436505],)], 
      dtype=[('Shape', '<f8', (2,))])

答案 1 :(得分:1)

你发表评论:

  

但这样的基本操作失败并不奇怪吗?只是一个简单的数组x = numpy.zeros(3, dtype={'names':['col1', 'col2'], 'formats':['i4','f4']})无法删除numpy.delete(x,0,1)的列。什么是这个问题的溃败原因,任何想法?

np.delete不是基本操作。看看它的代码。它的长度为5个屏幕(在Ipython上)。其中很多都处理了指定删除元素的不同方式。

有关     np.delete(x,0,axis = 1)

它使用特殊情况

    # optimization for a single value
    ...
    newshape[axis] -= 1
    new = empty(newshape, arr.dtype, arrorder)
    slobj[axis] = slice(None, obj)
    new[slobj] = arr[slobj]
    slobj[axis] = slice(obj, None)
    slobj2 = [slice(None)]*ndim
    slobj2[axis] = slice(obj+1, None)
    new[slobj] = arr[slobj2]

对于2d数组,轴= 1,它确实:

new = np.zeros((x.shape[0], x.shape[1]-1), dtype=x.dtype)
new[:, :obj] = x[:, :obj]
new[:, obj:] = x[:, obj+1:]

换句话说,它分配一个新的数组,其中列数少于1,然后将两个切片从原始数据复制到它。

有多个删除列和布尔obj,它需要其他路由。

请注意,该操作的基础是能够索引2个维度。

但是你不能用你的x索引。 x[0,1]出现too many indices错误。您必须使用x[0]['col1']。索引dtype的字段与索引二维数组的列有根本的不同。

recfunctions以常规dtype函数的方式操纵numpy字段。根据之前的研究,我猜测drop_field做了类似的事情:

In [57]: x    # your x with some values
Out[57]: 
array([(1, 3.0), (2, 2.0), (3, 1.0)], 
      dtype=[('col1', '<i4'), ('col2', '<f4')])

目标数组,具有不同的dtype(缺少一个字段)

In [58]: y=np.zeros(x.shape, dtype=x.dtype.descr[1:])

按字段复制值:

In [60]: for name in y.dtype.names:
    ...:     y[name]=x[name]
In [61]: y
Out[61]: 
array([(3.0,), (2.0,), (1.0,)], 
      dtype=[('col2', '<f4')])

常规n-d索引是围绕shapestrides属性构建的。通过这些(以及元素字节大小),它可以快速识别所需元素的data缓冲区中的位置。

使用复合dtype,形状和步幅的工作方式相同,但nbytes不同。在x案例中,i4f4字段各为24 - 12。因此,从一个24位记录到下一个记录的常规索引步骤。所以要选择&#39; col2&#39;字段,它进一步选择每个记录中的第二组4个字节。

在可能的情况下,我认为它将字段选择转换为常规索引。 __array_interface__是一个很好的数组基本属性字典。

In [70]: x.__array_interface__
Out[70]: 
{'data': (68826112, False),
 'descr': [('col1', '<i4'), ('col2', '<f4')],
 'shape': (3,),
 'strides': None,
 'typestr': '|V8',
 'version': 3}

In [71]: x['col2'].__array_interface__
Out[71]: 
{'data': (68826116, False),
 'descr': [('', '<f4')],
 'shape': (3,),
 'strides': (8,),
 'typestr': '<f4',
 'version': 3}

第二个数组指向相同的数据缓冲区,但进一步指向4个字节(第一个col2值)。实际上它是一种观点。

np.transpose是另一个不在dtype边界内运作的函数。)

===================

这里是drop_fields的代码(摘要):

In [74]: from numpy.lib import recfunctions  # separate import statement
In [75]: recfunctions.drop_fields??

def drop_fields(base, drop_names, usemask=True, asrecarray=False):
    .... # define `drop_descr function
    newdtype = _drop_descr(base.dtype, drop_names)
    output = np.empty(base.shape, dtype=newdtype)
    output = recursive_fill_fields(base, output)
    return output

recursive_fill_fields按名称字段副本执行名称,并且能够处理定义字段中字段的dtypes(递归部分)。

In [81]: recfunctions.drop_fields(x, 'col1')
Out[81]: 
array([(3.0,), (2.0,), (1.0,)], 
      dtype=[('col2', '<f4')])

In [82]: x[['col2']]  # multifield selection that David suggests
Out[82]: 
array([(3.0,), (2.0,), (1.0,)], 
      dtype=[('col2', '<f4')])

In [83]: x['col2']     # single field view
Out[83]: array([ 3.,  2.,  1.], dtype=float32)

drop_field产生与@David建议的多字段索引类似的结果。但是,多字段索引编写得很糟糕,正如您将尝试进行某种分配一样。