Python比较标记化列表

时间:2016-11-17 21:58:37

标签: python arrays list numpy sparse-matrix

我需要尽可能快地解决这个问题,因为它将应用于庞大的数据集:

鉴于此主列表:

create_disposition='CREATE_IF_NEEDED'

...以及此参考列表清单:

m=['abc','bcd','cde','def']

我想将r中的每个列表与主列表(m)进行比较,并生成新的列表列表。这个新对象将根据m的顺序为1匹配,对于非匹配则为0。因此,新对象(列表列表)将始终具有与m相同长度的列表。 以下是基于m和r的预期:

r=[['abc','def'],['bcd','cde'],['abc','def','bcd']]

因为r的第一个元素是[[1,0,0,1],[0,1,1,0],[1,1,0,1]] 并且匹配 使用m的第1和第4个元素,结果为['abc','def']

到目前为止,这是我的方法(可能太慢而且缺少零):

[1,0,0,1]

导致:

output=[]
for i in r:
    output.append([1 for x in m if x in i])

提前致谢!

5 个答案:

答案 0 :(得分:3)

您可以使用这样的嵌套列表解析:

>>> m = ['abc','bcd','cde','def']
>>> r = [['abc','def'],['bcd','cde'],['abc','def','bcd']]
>>> [[1 if mx in rx else 0 for mx in m] for rx in r]
[[1, 0, 0, 1], [0, 1, 1, 0], [1, 1, 0, 1]]

此外,您可以使用1 if ... else 0缩短int(...),并且可以将r的子列表转换为set,以便单个mx in rx查找更快。

>>> [[int(mx in rx) for mx in m] for rx in r]
[[1, 0, 0, 1], [0, 1, 1, 0], [1, 1, 0, 1]]
>>> [[int(mx in rx) for mx in m] for rx in map(set, r)]
[[1, 0, 0, 1], [0, 1, 1, 0], [1, 1, 0, 1]]

虽然int(...)1 if ... else 0稍短,但它似乎也较慢,所以你可能不应该使用它。在重复查找之前将r的子列表转换为set可以加快更长列表的速度,但对于非常简短的示例列表,它实际上比天真的方法慢。

>>> %timeit [[1 if mx in rx else 0 for mx in m] for rx in r]
100000 loops, best of 3: 4.74 µs per loop
>>> %timeit [[int(mx in rx) for mx in m] for rx in r]
100000 loops, best of 3: 8.07 µs per loop
>>> %timeit [[1 if mx in rx else 0 for mx in m] for rx in map(set, r)]
100000 loops, best of 3: 5.82 µs per loop

对于较长的列表,使用set变得更快,正如预期的那样:

>>> m = [random.randint(1, 100) for _ in range(50)]
>>> r = [[random.randint(1,100) for _ in range(10)] for _ in range(20)]
>>> %timeit [[1 if mx in rx else 0 for mx in m] for rx in r]
1000 loops, best of 3: 412 µs per loop
>>> %timeit [[1 if mx in rx else 0 for mx in m] for rx in map(set, r)]
10000 loops, best of 3: 208 µs per loop

答案 1 :(得分:1)

使用np.in1d一个循环的一种方法 -

np.array([np.in1d(m,i) for i in r]).astype(int)

使用显式循环,它看起来像这样 -

out = np.empty((len(r),len(m)),dtype=int)
for i,item in enumerate(r):
    out[i] = np.in1d(m,item)

我们可以使用dtype=bool来获取内存和性能。

示例运行 -

In [18]: m
Out[18]: ['abc', 'bcd', 'cde', 'def']

In [19]: r
Out[19]: [['abc', 'def'], ['bcd', 'cde'], ['abc', 'def', 'bcd']]

In [20]: np.array([np.in1d(m,i) for i in r]).astype(int)
Out[20]: 
array([[1, 0, 0, 1],
       [0, 1, 1, 0],
       [1, 1, 0, 1]])

如果r列表长度相等,我们可以使用完全向量化的方法。

答案 2 :(得分:1)

你快到了。

如果1x,则需要添加i,如果不是0则为xm

所以脚本听起来似乎是:1 if x in i else 0作为条件,for x in m

output = [[1 if x in i else 0 for x in m] for i in r]
print(output)

结果

[[1, 0, 0, 1], [0, 1, 1, 0], [1, 1, 0, 1]]

答案 3 :(得分:1)

没有numpy ,您可以使用嵌套列表理解执行此操作:

>>> m = ['abc','bcd','cde','def']
>>> r = [['abc','def'],['bcd','cde'],['abc','def','bcd']]

>>> [[int(mm in rr) for mm in m] for rr in r]
[[1, 0, 0, 1], [0, 1, 1, 0], [1, 1, 0, 1]]

实际上,您不需要对int进行类型转换,因为Python会将False视为0,将True视为1。此外,使用bool值可以提高内存效率。因此,您的表达式将如下所示:

>>> [[mm in rr for mm in m] for rr in r]
[[True, False, False, True], [False, True, True, False], [True, True, False, True]]

答案 4 :(得分:0)

多处理救援!

import multiprocessing as mp

def matcher(qIn, qOut):
    m = set(['abc','bcd','cde','def'])
    for i,L in iter(qIn.get, None):
        answer = [1 if e in m else 0 for e in L]
        qOut.put((i,answer))


def main(L):
    qIn, qOut = [mp.Queue() for _ in range(2)]
    procs = [mp.Process(target=matcher, args=(qIn, qOut)) for _ in range(mp.cpu_count()-1)]
    for p in procs: p.start()

    numElems = len(L)
    for t in enumerate(L): qIn.put(t)
    for p in procs: qIn.put(None)

    done = 0
    while done < numElems:
        i,answer = qIn.get()
        L[i] = answer
        done += 1

    for p in procs: p.terminate()

if __name__ == "__main__":
    L = [['abc','def'],['bcd','cde'],['abc','def','bcd']]
    main(L)
    # now L looks like the required output