Python 如何用指定列表的索引替换数组的所有项?

Python 如何用指定列表的索引替换数组的所有项?,python,numpy,list-comprehension,Python,Numpy,List Comprehension,我想用ID替换序列中的所有项,这些ID告诉它们在哪个标签机列表中。假设所有值在序列和标签中都是不同的,并且标签列表的联合与序列具有相同的项lsizes对应于labeller中的列表大小,对于Pythonic解决方案是多余的,但对于完全矢量化的解决方案可能是强制性的 sequence = [1, 2, 10, 5, 6, 4, 3, 8, 7, 9], labeller = [[1, 2, 10], [3, 4, 5, 6, 7], [8, 9]] lsizes = [3, 5, 2] 我知道如

我想用ID替换
序列中的所有项,这些ID告诉它们在哪个标签机列表中。假设所有值在
序列
标签
中都是不同的,并且
标签
列表的联合与
序列
具有相同的项
lsizes
对应于
labeller
中的列表大小,对于Pythonic解决方案是多余的,但对于完全矢量化的解决方案可能是强制性的

sequence = [1, 2, 10, 5, 6, 4, 3, 8, 7, 9],
labeller = [[1, 2, 10], [3, 4, 5, 6, 7], [8, 9]]
lsizes = [3, 5, 2]
我知道如何用一种简单的方法解决它:

idx = {u:i for i, label in enumerate(labeller) for u in label}
tags = [idx[u] for u in sequence]
输出为:

tags = [0, 0, 0, 1, 1, 1, 1, 2, 1, 2]
在那之后,我把我所有的努力都用矢量化的方式来做。这对我来说相当复杂。这是我的尝试,只是猜测而已,但不幸的是,它没有通过我所有的测试。我希望我很接近:

sequence = np.array(sequence)
cl = np.concatenate(labeller)
_, cl_idx = np.unique(cl, return_index=True)
_, idx = np.unique(sequence[cl_idx], return_index=True)
tags = np.repeat(np.arange(len(lsizes)), lsizes)[idx]
#output: [0 0 1 1 0 1 1 1 2 2]
我怎样才能完成它?我也希望看到严谨的解释,它做什么以及如何更好地理解它。欢迎任何来源。

方法#1

对于那些追溯问题的人来说,似乎是一种方法,在这里也很有效,重新使用你的
cl
-

cl = np.concatenate(labeller)
sidx = cl.argsort()
idx = np.searchsorted(cl, sequence, sorter=sidx)
idx0 = sidx[idx]

l = list(map(len, labeller))
r = np.repeat(np.arange(len(l)), l)
out = r[idx0]
l
使用
lsizes
可使其完全矢量化。但是,我怀疑连接步骤可能很繁重。这是否值得,在很大程度上取决于子阵列的长度

方法#2

对于正数,这里有一个数组索引作为散列机制-

N = max(map(max, labeller))+1
id_ar = np.zeros(N, dtype=int) # use np.empty for perf. boost
for i,l in enumerate(labeller):
    id_ar[l] = i
out = id_ar[sequence]
备选方案:

label_df = pd.DataFrame({'label':labeller_array, 'index':index_array})
seq_df = pd.DataFrame({'seq':sequence_array})
seq_df.merge(label_df, left_on = 'seq', right_on = 'label')['index'].tolist()
#output: [0, 0, 0, 1, 1, 1, 1, 2, 1, 2]

老实说,我认为python方法并没有那么糟糕。也会对纯numpy的矢量化解决方案感兴趣。尽管您的数据是纯python列表,但将它们转换为numpy数组的运行时开销可能已经与纯python解决方案几乎相同。我很好奇,如果性能是目标,这是否可以超过python方法。这是否更快(即使没有考虑到转换为数组的开销)?@Ehsan我认为app#2会,因为与给定的Python解决方案相比,它跳过了第二个循环。在app#1上,我希望,如果我们不考虑连接部分,如果有足够多的子数组,我也认为第二个比最初提出的散列更好,如果值对于内存问题来说不是太大的话。我对numpyic方法和pythonic方法很好奇。
label_df = pd.DataFrame({'label':labeller_array, 'index':index_array})
seq_df = pd.DataFrame({'seq':sequence_array})
seq_df.merge(label_df, left_on = 'seq', right_on = 'label')['index'].tolist()
#output: [0, 0, 0, 1, 1, 1, 1, 2, 1, 2]