部分复制NumPy数组

时间:2017-03-27 15:24:25

标签: python numpy lambda list-comprehension

我有一个NumPy数组,其中包含40多列。我的目标只是创建另一个数组,其中包含这些列的子集并附加数据。

我的代码是:

RecDtypes = []
RecColIds = ['REC*','GLOBAL*']
for name in Reconciliation.dtype.names:
    for Id in RecColIds:    
        if fnmatch.fnmatch(name,Id):
            RecDtypes.append(name)
#Change column names
if RecDtypes:
    Rec = Reconciliation[RecDtypes]
    newnames=[]    
    for oldname in Rec.dtype.names:
        for Id in RecColIds:    
            if fnmatch.fnmatch(oldname,Id):
                newnames.append(oldname[len(Id):])
    Rec.dtype.names=newnames

此处Rec = new arrayReconciliation = old array。第一个循环从第一个数组中提取出我想要的列。第二个循环重命名列名。

这是一种更简单/有效/简洁的方法吗?

2 个答案:

答案 0 :(得分:1)

根据您对问题的描述,我不知道这将是多么紧张的计算(40列= 40个字符串来测试和移动)。你可以通过组合你的两个循环消除一些混乱,因为它们有效地循环在相同的列表上。这也可能会带来轻微的性能优势,但从我的第一句话来看,这可能是微不足道的。

RecDtypes = []
newnames = []
RecColIds = ['REC*','GLOBAL*']
for name in Reconciliation.dtype.names:
    for Id in RecColIds:    
        if fnmatch.fnmatch(name,Id):
            RecDtypes.append(name)
            newnames.append(name[len(Id):])
#Change column names
if RecDtypes:
    Rec = Reconciliation[RecDtypes]
    Rec.dtype.names=newnames

答案 1 :(得分:1)

这看起来像是复制和重命名任务:

In [95]: dt = np.dtype('i,i,i,i')
In [96]: arr = np.zeros((2,), dtype=dt)
In [97]: arr[0]=np.arange(4)
In [98]: arr[1]=np.arange(4,8)
In [99]: arr
Out[99]: 
array([(0, 1, 2, 3), (4, 5, 6, 7)], 
      dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4')])

获取符合某种模式的名称列表:

In [100]: alist = [name for name in dt.names if name[1] in ['1','3']]
In [101]: alist
Out[101]: ['f1', 'f3']

按字段名称进行直接复制:

In [102]: arr1 = arr[alist]
In [103]: arr1
Out[103]: 
array([(1, 3), (5, 7)], 
      dtype=[('f1', '<i4'), ('f3', '<i4')])

直接改变字段名称:

In [104]: arr1.dtype.names = ['one','three']
In [105]: arr1
Out[105]: 
array([(1, 3), (5, 7)], 
      dtype=[('one', '<i4'), ('three', '<i4')])

如果您打算修改值,则需要使用arr1 = arr[alist].copy()

In [107]: arr1['one'] += 1
/usr/local/bin/ipython3:1: FutureWarning: Numpy has detected that you (may be) writing to an array returned
by numpy.diagonal or by selecting multiple fields in a structured
array. This code will likely break in a future numpy release --
see numpy.diagonal or arrays.indexing reference docs for details.
The quick fix is to make an explicit copy (e.g., do
arr.diagonal().copy() or arr[['f0','f1']].copy()).
  #!/usr/bin/python3

(早期答案 - 可能仍然有用)

子模块numpy.lib.recfunctions具有复制和修改结构化数组及其名称的功能。通常,这些函数的工作原理是创建一个具有所需形状和dtype的空目标数组,然后按字段名称将值从old复制到new。这似乎就是你在做什么。

通常,结构化数组将包含许多行,并且字段相对较少。因此,字段的迭代复制并不昂贵。

您可以使用名称列表

一次访问多个字段
arr[['f0','f1']]

编辑 - 您的Reconciliation[RecDtypes]正是这样做的。一次取出几个字段。

但是如果你做了什么而不是阅读这些值,你可能会收到警告,建议你添加copy。最近的numpy发行说明有关于按位置从副本更改为按位置复制的内容。

按字段名称说明副本:

In [128]: alist
Out[128]: ['f1', 'f3']
In [129]: arr
Out[129]: 
array([(0, 1, 2, 3), (4, 5, 6, 7)], 
      dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4')])
In [130]: dt.descr
Out[130]: [('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4')]
In [131]: dt1 = [item for item in dt.descr if item[0] in alist]
In [132]: dt1
Out[132]: [('f1', '<i4'), ('f3', '<i4')]
In [133]: res = np.zeros(arr.shape, dtype=dt1)
In [134]: for name in alist:
     ...:     res[name] = arr[name]   
In [135]: res
Out[135]: 
array([(1, 3), (5, 7)], 
      dtype=[('f1', '<i4'), ('f3', '<i4')])

arr[alist].copy()更简单,可能更快。