使用 numpy 进行 elementwise "in" 的 Pythonic 和有效方法
Pythonic and efficient way to do an elementwise "in" using numpy
我正在寻找一种有效获取布尔数组的方法,其中给定两个大小相等的数组 a
和 b
,如果 [= 的相应元素,则每个元素为真14=]出现in
对应的元素是b
.
例如下面的程序:
a = numpy.array([1, 2, 3, 4])
b = numpy.array([[1, 2, 13], [2, 8, 9], [5, 6], [7]])
print(numpy.magic_function(a, b))
应该打印
[True, True, False, False]
记住这个函数应该等同于
[x in y for x, y in zip(a, b)]
仅 numpy
-针对 a
和 b
较大且 b
的每个元素都相当小的情况进行了优化。
b
中小列表的长度是否有上限?如果是这样,也许您可以使 b
成为 1000x5 的矩阵,并使用 nan
来填补太短的子数组的空白。然后你可以使用 numpy.any 来得到你想要的答案,像这样:
In [42]: a = np.array([1, 2, 3, 4])
...: b = np.array([[1, 2, 13], [2, 8, 9], [5, 6], [7]])
In [43]: bb = np.full((len(b), max(len(i) for i in b)), np.nan)
In [44]: for irow, row in enumerate(b):
...: bb[irow, :len(row)] = row
In [45]: bb
Out[45]:
array([[ 1., 2., 13.],
[ 2., 8., 9.],
[ 5., 6., nan],
[ 7., nan, nan]])
In [46]: a[:,np.newaxis] == bb
Out[46]:
array([[ True, False, False],
[ True, False, False],
[False, False, False],
[False, False, False]], dtype=bool)
In [47]: np.any(a[:,np.newaxis] == bb, axis=1)
Out[47]: array([ True, True, False, False], dtype=bool)
不知道这对您的数据来说是否更快。
总结
Sauldo Castro 的方法在目前 posted 中运行最快。原始 post 中的生成器表达式是第二快的。
生成测试数据的代码:
import numpy
import random
alength = 100
a = numpy.array([random.randint(1, 6) for i in range(alength)])
b = []
for i in range(alength):
length = random.randint(1, 5)
element = []
for i in range(length):
element.append(random.randint(1, 6))
b.append(element)
b = numpy.array(b)
print a, b
选项:
from itertools import izip_longest
def magic_function1(a, b): # From OP Martin Fixman
return [x in y for x, y in zip(a, b)]
def magic_function2(a, b): # What I thought might be better.
bools = []
for x, y in zip(a,b):
found = False
for j in y:
if x == j:
found=True
break
bools.append(found)
def magic_function3(a, b): # What I tried first
bools = []
for i in range(len(a)):
found = False
for j in range(len(b[i])):
if a[i] == b[i][j]:
found=True
break
bools.append(found)
def magic_function4(a, b): # From Bas Swinkels
bb = numpy.full((len(b), max(len(i) for i in b)), numpy.nan)
for irow, row in enumerate(b):
bb[irow, :len(row)] = row
a[:,numpy.newaxis] == bb
return numpy.any(a[:,numpy.newaxis] == bb, axis=1)
def magic_function5(a, b): # From Sauldo Castro, revised version
c = numpy.array(list(izip_longest(*b))).astype(float)
return numpy.isclose(c, a), axis=0)
时间n_executions
n_executions = 100
clock = timeit.Timer(stmt="magic_function1(a, b)", setup="from __main__ import magic_function1, a, b")
print clock.timeit(n_executions), "seconds"
# Repeat with each candidate function
结果:
- 0.158078225475 秒 magic_function1
- 0.181080926835 秒 magic_function2
- 0.259621047822 秒 magic_function3
- 0.287054750224 秒 magic_function4
- 0.0839162196207 秒 magic_function5
要利用 NumPy 的 broadcasting 规则,您应该首先对数组 b
进行平方,这可以使用 itertools.izip_longest
:
来实现
from itertools import izip_longest
c = np.array(list(izip_longest(*b))).astype(float)
导致:
array([[ 1., 2., 5., 7.],
[ 2., 8., 6., nan],
[ 13., 9., nan, nan]])
然后,通过执行 np.isclose(c, a)
,您将获得一个二维布尔数组,显示每个 c[:, i]
和 a[i]
之间的差异,根据广播规则,给出:
array([[ True, True, False, False],
[False, False, False, False],
[False, False, False, False]], dtype=bool)
可以用来获取你的答案:
np.any(np.isclose(c, a), axis=0)
#array([ True, True, False, False], dtype=bool)
我正在寻找一种有效获取布尔数组的方法,其中给定两个大小相等的数组 a
和 b
,如果 [= 的相应元素,则每个元素为真14=]出现in
对应的元素是b
.
例如下面的程序:
a = numpy.array([1, 2, 3, 4])
b = numpy.array([[1, 2, 13], [2, 8, 9], [5, 6], [7]])
print(numpy.magic_function(a, b))
应该打印
[True, True, False, False]
记住这个函数应该等同于
[x in y for x, y in zip(a, b)]
仅 numpy
-针对 a
和 b
较大且 b
的每个元素都相当小的情况进行了优化。
b
中小列表的长度是否有上限?如果是这样,也许您可以使 b
成为 1000x5 的矩阵,并使用 nan
来填补太短的子数组的空白。然后你可以使用 numpy.any 来得到你想要的答案,像这样:
In [42]: a = np.array([1, 2, 3, 4])
...: b = np.array([[1, 2, 13], [2, 8, 9], [5, 6], [7]])
In [43]: bb = np.full((len(b), max(len(i) for i in b)), np.nan)
In [44]: for irow, row in enumerate(b):
...: bb[irow, :len(row)] = row
In [45]: bb
Out[45]:
array([[ 1., 2., 13.],
[ 2., 8., 9.],
[ 5., 6., nan],
[ 7., nan, nan]])
In [46]: a[:,np.newaxis] == bb
Out[46]:
array([[ True, False, False],
[ True, False, False],
[False, False, False],
[False, False, False]], dtype=bool)
In [47]: np.any(a[:,np.newaxis] == bb, axis=1)
Out[47]: array([ True, True, False, False], dtype=bool)
不知道这对您的数据来说是否更快。
总结
Sauldo Castro 的方法在目前 posted 中运行最快。原始 post 中的生成器表达式是第二快的。
生成测试数据的代码:
import numpy
import random
alength = 100
a = numpy.array([random.randint(1, 6) for i in range(alength)])
b = []
for i in range(alength):
length = random.randint(1, 5)
element = []
for i in range(length):
element.append(random.randint(1, 6))
b.append(element)
b = numpy.array(b)
print a, b
选项:
from itertools import izip_longest
def magic_function1(a, b): # From OP Martin Fixman
return [x in y for x, y in zip(a, b)]
def magic_function2(a, b): # What I thought might be better.
bools = []
for x, y in zip(a,b):
found = False
for j in y:
if x == j:
found=True
break
bools.append(found)
def magic_function3(a, b): # What I tried first
bools = []
for i in range(len(a)):
found = False
for j in range(len(b[i])):
if a[i] == b[i][j]:
found=True
break
bools.append(found)
def magic_function4(a, b): # From Bas Swinkels
bb = numpy.full((len(b), max(len(i) for i in b)), numpy.nan)
for irow, row in enumerate(b):
bb[irow, :len(row)] = row
a[:,numpy.newaxis] == bb
return numpy.any(a[:,numpy.newaxis] == bb, axis=1)
def magic_function5(a, b): # From Sauldo Castro, revised version
c = numpy.array(list(izip_longest(*b))).astype(float)
return numpy.isclose(c, a), axis=0)
时间n_executions
n_executions = 100
clock = timeit.Timer(stmt="magic_function1(a, b)", setup="from __main__ import magic_function1, a, b")
print clock.timeit(n_executions), "seconds"
# Repeat with each candidate function
结果:
- 0.158078225475 秒 magic_function1
- 0.181080926835 秒 magic_function2
- 0.259621047822 秒 magic_function3
- 0.287054750224 秒 magic_function4
- 0.0839162196207 秒 magic_function5
要利用 NumPy 的 broadcasting 规则,您应该首先对数组 b
进行平方,这可以使用 itertools.izip_longest
:
from itertools import izip_longest
c = np.array(list(izip_longest(*b))).astype(float)
导致:
array([[ 1., 2., 5., 7.],
[ 2., 8., 6., nan],
[ 13., 9., nan, nan]])
然后,通过执行 np.isclose(c, a)
,您将获得一个二维布尔数组,显示每个 c[:, i]
和 a[i]
之间的差异,根据广播规则,给出:
array([[ True, True, False, False],
[False, False, False, False],
[False, False, False, False]], dtype=bool)
可以用来获取你的答案:
np.any(np.isclose(c, a), axis=0)
#array([ True, True, False, False], dtype=bool)