Python 比较标记化列表
Python Compare Tokenized Lists
我需要这个问题的最快解决方案,因为它将应用于一个巨大的数据集:
鉴于此主列表:
m=['abc','bcd','cde','def']
...以及此列表的参考列表:
r=[['abc','def'],['bcd','cde'],['abc','def','bcd']]
我想将 r 中的每个列表与主列表 (m) 进行比较,并生成一个新的列表列表。这个新对象将根据 m 中的顺序为匹配项设置 1,不匹配项设置为 0。因此新对象(列表的列表)将始终具有与 m 相同长度的列表。
这是我基于上面的 m 和 r 的期望:
[[1,0,0,1],[0,1,1,0],[1,1,0,1]]
因为r的第一个元素是['abc','def']
并且有匹配
使用 m 的第 1 个和第 4 个元素,结果是 [1,0,0,1]
.
这是我目前的方法(可能太慢并且缺少零):
output=[]
for i in r:
output.append([1 for x in m if x in i])
导致:
[[1, 1], [1, 1], [1, 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
有等长的列表,我们可以使用完全矢量化的方法。
你快到了。
如果 x
在 i
中,您想添加 1
,如果不在 x
中,则添加 0
,对于 [=17 中的每个 x
=].
所以脚本听起来像: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]]
如果没有 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]]
您可以像这样使用嵌套列表理解:
>>> 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]]
此外,您可以使用 int(...)
缩短 1 if ... else 0
,并且可以将 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
多处理来拯救!
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
我需要这个问题的最快解决方案,因为它将应用于一个巨大的数据集:
鉴于此主列表:
m=['abc','bcd','cde','def']
...以及此列表的参考列表:
r=[['abc','def'],['bcd','cde'],['abc','def','bcd']]
我想将 r 中的每个列表与主列表 (m) 进行比较,并生成一个新的列表列表。这个新对象将根据 m 中的顺序为匹配项设置 1,不匹配项设置为 0。因此新对象(列表的列表)将始终具有与 m 相同长度的列表。 这是我基于上面的 m 和 r 的期望:
[[1,0,0,1],[0,1,1,0],[1,1,0,1]]
因为r的第一个元素是['abc','def']
并且有匹配
使用 m 的第 1 个和第 4 个元素,结果是 [1,0,0,1]
.
这是我目前的方法(可能太慢并且缺少零):
output=[]
for i in r:
output.append([1 for x in m if x in i])
导致:
[[1, 1], [1, 1], [1, 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
有等长的列表,我们可以使用完全矢量化的方法。
你快到了。
如果 x
在 i
中,您想添加 1
,如果不在 x
中,则添加 0
,对于 [=17 中的每个 x
=].
所以脚本听起来像: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]]
如果没有 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]]
您可以像这样使用嵌套列表理解:
>>> 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]]
此外,您可以使用 int(...)
缩短 1 if ... else 0
,并且可以将 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
多处理来拯救!
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