python numpy left join rearray 具有重复的键值

标签 python python-2.7 numpy

我想左外连接两个重新排列。第一个是具有唯一键的实体列表。第二个是值列表,每个实体可以有 0 个或多个值。我的环境要求我使用 Python 2.7,但无法使用 Pandas。

这个问题之前已经被问过here但没有一个好的答案。

    import numpy as np
    import numpy.lib.recfunctions
    from pprint import pprint

    dtypes = [('point_index',int),('name','S50')] 
    recs = [(0,'Bob'),
            (1,'Bob'),
            (2,'Sue'),
            (3,'Sue'),
            (4,'Jim')]
    x = np.rec.fromrecords(recs,dtype=dtypes)

    dtypes = [('point_index',int),('type','S500'),('value',float)] 
    recs = [(0,'a',0.1),
            (0,'b',0.2),
            (1,'a',0.3),
            (2,'b',0.4),
            (2,'b',0.5),
            (4,'a',0.6),
            (4,'a',0.7),
            (4,'a',0.8)]
    y = np.rec.fromrecords(recs,dtype=dtypes)

    j = np.lib.recfunctions.join_by('point_index',x,y,jointype='leftouter',usemask=False,asrecarray=True)

    pprint(j.tolist())

我要

# [(0,'Bob','a',0.1),
#  (0,'Bob','b',0.2),
#  (1,'Bob','a',0.3),
#  (2,'Sue','b',0.4),
#  (2,'Sue','b',0.5),
#  (4,'Jim','a',0.6),
#  (4,'Jim','a',0.7),
#  (4,'Jim','a',0.8)]

但我明白了

[(0, 'Bob', 'a', 0.1),
 (0, 'Bob', 'b', 0.2),
 (1, 'Sue', 'a', 0.3),
 (2, 'Jim', 'b', 0.4),
 (2, 'N/A', 'b', 0.5),
 (3, 'Sue', 'N/A', 1e+20),
 (4, 'N/A', 'a', 0.6),
 (4, 'N/A', 'a', 0.7),
(4, 'N/A', 'a', 0.8)]

我知道为什么,这是来自 docs

Neither r1 nor r2 should have any duplicates along key: the presence of duplicates will make the output quite unreliable. Note that duplicates are not looked for by the algorithm.

所以,看来这个要求确实限制了这个函数的用处。看来我描述的左外连接类型是一个非常常见的操作,有人知道如何使用 numpy 实现它吗?

最佳答案

如果xpoint_index值按数字顺序排列,您可以通过简单的索引将它们与y匹配。

一种方法是构造一个新数组 z,并添加 names 字段。在这里,我使用结构化数组(rec 也可以工作,但我不需要它的额外功能):

In [419]: dtypes1 = [('point_index',int),('name','S50')]    
In [420]: dtypes
Out[420]: [('point_index', int), ('type', 'S500'), ('value', float)]
In [421]: dtypes2=dtypes1 + dtypes[1:]
In [422]: z=np.zeros(y.shape[0],dtype=dtypes2)

使用 y 中的匹配字段填充 z:

In [423]: for n in y.dtype.names:
    z[n] = y[n]

由于字段数通常远小于行数,因此这种复制并不昂贵。

通过简单索引选择名称:

In [424]: z['name']=x['name'][y['point_index']]

In [425]: z
Out[425]: 
array([(0, b'Bob', b'a', 0.1), (0, b'Bob', b'b', 0.2),
       (1, b'Bob', b'a', 0.3), (2, b'Sue', b'b', 0.4),
       (2, b'Sue', b'b', 0.5), (4, b'Jim', b'a', 0.6),
       (4, b'Jim', b'a', 0.7), (4, b'Jim', b'a', 0.8)], 
      dtype=[('point_index', '<i4'), ('name', 'S50'), ('type', 'S500'), ('value', '<f8')])

有更通用的方法来匹配x['point_index']y['point_index']。只需将它们视为需要匹配的两个数值数组(可能具有唯一性和排序)。或者甚至使用列表理解并查找。

或者在链接的答案中使用 append_fields 方法:

In [441]: import numpy.lib.recfunctions as nrec

In [442]: names=x['name'][y['point_index']]

In [443]: nrec.append_fields(y, 'name', names,
                         asrecarray=False, usemask=False)
Out[443]: 
array([(0, b'a', 0.1, b'Bob'), (0, b'b', 0.2, b'Bob'),
       (1, b'a', 0.3, b'Bob'), (2, b'b', 0.4, b'Sue'),
       (2, b'b', 0.5, b'Sue'), (4, b'a', 0.6, b'Jim'),
       (4, b'a', 0.7, b'Jim'), (4, b'a', 0.8, b'Jim')], 
      dtype=[('point_index', '<i4'), ('type', 'S500'), ('value', '<f8'), ('name', 'S50')])

append_fields 大致执行我之前编写的操作 - 使用新的 dtype 创建一个 output,然后填充基础数据和新数据中的值。它使用 recursive_fill_fields 来复制数据,对于简单的数据类型,它会执行相同的按名称复制。

nrec.recursive_fill_fields(y,z)

关于python numpy left join rearray 具有重复的键值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31774578/

相关文章:

python - 如何为非常相似的代码片段编写方法或 for 循环

python - 将 HTML 表单值解释为 Flask View 中的列表

python - 使用 python-openCV 读取视频并保存为 pgm 格式图像

python-3.x - Numpy 将两个不同的linspace组合成一个坐标矩阵

python - 如何用Python确定拟合参数的不确定性?

Python 构造函数链和多态性

python - 如何在 Python 2.7 中使 raw_input 容差更健壮?

用于两个嵌套 for 循环的 python 一个类轮代码

python-2.7 - 64位PC上找不到数据源名称或没有默认驱动程序的pyodbc错误

python - 根据组在 pandas 数据框中查找百分位