Python Numpy-如何将向量索引数组转换为掩码?

Python Numpy-如何将向量索引数组转换为掩码?,python,numpy,Python,Numpy,给定一个名为index的np.ndarray,每行有n行和可变长度向量,我想创建一个n行和m行的布尔掩码,其中m是一个已知值,等于索引中可能的最大值。 请注意,索引中指定的索引是指每行索引,而不是全局矩阵索引 例如,假设: index=np.array([ [2, 0], [0], [4, 7, 1] ]) #预期产量 打印(遮罩) [[True-False-False-False] [真假假假假] [假真假假假假真]] m是预先知道的(在mask中每行的最大长度),不需要从索引中推断出来 注

给定一个名为
index
np.ndarray
,每行有
n
行和可变长度向量,我想创建一个
n
行和
m
行的布尔掩码,其中
m
是一个已知值,等于
索引中可能的最大值。
请注意,
索引
中指定的索引是指每行索引,而不是全局矩阵索引

例如,假设:

index=np.array([
[2, 0],
[0],
[4, 7, 1]
])
#预期产量
打印(遮罩)
[[True-False-False-False]
[真假假假假]
[假真假假假假真]]
m
是预先知道的(在
mask
中每行的最大长度),不需要从
索引中推断出来

注意:这不同于将索引数组转换为掩码,其中索引引用生成的矩阵索引-

def mask_from_indices(indices, ncols=None):
    # Extract column indices
    col_idx = np.concatenate(indices)

    # If number of cols is not given, infer it based on max column index
    if ncols is None:
        ncols = col_idx.max()+1

    # Length of indices, to be used as no. of rows in o/p
    n = len(indices)

    # Initialize o/p array
    out = np.zeros((n,ncols), dtype=bool)

    # Lengths of each index element that represents each group of col indices
    lens = np.array(list(map(len,indices)))

    # Use np.repeat to generate all row indices
    row_idx = np.repeat(np.arange(len(lens)),lens)

    # Finally use row, col indices to set True values
    out[row_idx,col_idx] = 1
    return out    
样本运行-

In [89]: mask_from_indices(indices)
Out[89]: 
array([[ True, False,  True, False, False, False, False, False],
       [ True, False, False, False, False, False, False, False],
       [False,  True, False, False,  True, False, False,  True]])
以下是一个变体:

def create_mask(indices, m):
    mask = np.zeros((len(indices), m), dtype=bool)
    for i, idx in enumerate(indices):
        mask[i, idx] = True
    return mask
用法:

>>> create_mask(indices, 8)
array([[ True, False,  True, False, False, False, False, False],
       [ True, False, False, False, False, False, False, False],
       [False,  True, False, False,  True, False, False,  True]])

虽然没有以完全矢量化的方式直接实现这一点,但对于较大的输入,一次应用带有预先计算的完整索引列表的
屏蔽[完整行索引,完整列索引]
比多次应用
屏蔽[部分行索引,部分列索引]
更快。 内存方面,多个应用程序的要求也较低,因为不需要构建中间
全行索引
/
全列索引
。 当然,这通常取决于
索引的长度

为了了解不同解决方案的速度,我们对以下功能进行了测试:

将numpy导入为np
随机输入
def gen_mask_direct(列索引,列=无):
如果cols为无:
cols=np.max(np.concatenate(col_索引))+1
行=列(列索引)
掩码=np.0((行,列),数据类型=bool)
对于行索引,枚举中的列索引(列索引):
掩码[行索引,列索引]=真
返回掩码
def gen_掩码_循环(列索引,列=无):
行=列(列索引)
行索引=元组(i表示i,j表示枚举中的j(列索引)表示j中的u)
列索引=元组(和(列索引,())
如果cols为无:
cols=np.max(col_指数)+1
掩码=np.0((行,列),数据类型=bool)
掩码[行索引,列索引]=真
返回掩码
def gen_掩码_np_重复(列索引,列=无):
行=列(列索引)
长度=列表(映射(长度、列索引))
行索引=np.重复(np.排列(行),长度)
列索引=np.连接(列索引)
如果cols为无:
cols=np.max(col_指数)+1
掩码=np.0((行,列),数据类型=bool)
掩码[行索引,列索引]=真
返回掩码
def gen_mask_np_串联(列索引,列=无):
行=列(列索引)
行索引=元组(np.full(len(col_索引),i)表示i,枚举中的col_索引(col_索引))
行索引=np.连接(行索引)
列索引=np.连接(列索引)
如果cols为无:
cols=np.max(col_指数)+1
掩码=np.0((行,列),数据类型=bool)
掩码[行索引,列索引]=真
返回掩码
gen\u mask\u direct()
基本上实现了
mask[部分行索引,部分列索引]
的多种应用。 所有其他应用程序都实现了一次
屏蔽[全行索引,全列索引]
,使用不同的方法准备
全行索引和
全列索引

  • gen\u mask\u loops()
    使用直接循环
  • gen\u mask\u np\u repeat()
    使用
    np.repeat()
    (它与
  • gen\u mask\u np\u concatenate()
    使用
    np.full()
    np.concatenate()的组合

快速健康检查表明所有这些都是等效的:

funcs=gen\u mask\u direct、gen\u mask\u循环、gen\u mask\u np\u repeat、gen\u mask\u np\u concatenate
随机种子(0)
测试单元输入=[
(元组)(
元组(已排序(范围内(random.randint(1,n-1))的集合([random.randint(0,n-1))))
对于范围内的(random.randint(1,n-1)))
适用于范围(5,6)内的n
]
打印(测试输入)
# [((0, 2, 3, 4), (2, 3, 4), (1, 4), (0, 1, 4))]
对于func中的func:
打印('Func:',Func.\uuu name\uuuu)
对于测试输入中的测试输入:
打印(func(测试输入).astype(int))

以下是一些基准测试(使用中的代码):

并以最快的速度缩放:

支持这样一个总体陈述:通常,对于完整索引,单个应用
mask[…]
更快,对于部分索引,多个应用
mask[…]
更快


为完整起见,以下代码用于生成输入、比较输出、运行基准测试和准备绘图:

def发电机输入(n):
随机种子(0)
返回元组(
元组(已排序(集合([random.randint(0,n-1))用于范围内的uu(random.randint(n//2,n-1))))
对于范围内的u(random.randint(n//2,n-1)))
def均分输出(a、b):
返回np.all(a==b)
输入大小=范围(13)内i的元组(int(2**(2+(3*i)/4))
打印('输入大小:\n',输入大小'\n')
运行时、输入大小、标签、结果=基准(
funcs,gen_input=gen_input,equal_output=equal_output,
输入大小=输入大小)
绘图基准(运行时、输入大小、标签、单位='ms')
绘图基准(运行时、输入大小、标签、单位='ms',缩放速度=2)

你能把你的最后一句话说清楚一点吗?对我来说,这看起来像是你期望的结果。如果你有两个向量,你可以创建一个最大大小的零向量,然后使用索引来做一些事情
Func: gen_mask_direct
[[1 0 1 1 1]
 [0 0 1 1 1]
 [0 1 0 0 1]
 [1 1 0 0 1]]
Func: gen_mask_loops
[[1 0 1 1 1]
 [0 0 1 1 1]
 [0 1 0 0 1]
 [1 1 0 0 1]]
Func: gen_mask_np_repeat
[[1 0 1 1 1]
 [0 0 1 1 1]
 [0 1 0 0 1]
 [1 1 0 0 1]]
Func: gen_mask_np_concatenate
[[1 0 1 1 1]
 [0 0 1 1 1]
 [0 1 0 0 1]
 [1 1 0 0 1]]