Python numpy.isin字符串元素的错误结果

Python numpy.isin字符串元素的错误结果,python,numpy,Python,Numpy,假设我想检查字符串x是否是字符串y的子字符串,例如,我可以使用成员操作符 x = 'a' y = 'abc' x in y >> True 但是现在,x和y都是字符串的numpy数组,我想按元素执行上面的操作。根据文件, isin是中python关键字的按元素的函数版本 所以我想 x = np.array(['a','b','c']) y = np.array(['ab','fgd','cdfsgfsdh']) np.isin(x,y) 将给出数组[True,False,True

假设我想检查字符串x是否是字符串y的子字符串,例如,我可以使用成员操作符

x = 'a'
y = 'abc'
x in y
>> True
但是现在,x和y都是字符串的numpy数组,我想按元素执行上面的操作。根据文件,

isin是中python关键字的按元素的函数版本

所以我想

x = np.array(['a','b','c'])
y = np.array(['ab','fgd','cdfsgfsdh'])
np.isin(x,y)
将给出数组[True,False,True],但实际上它给出了数组[False,False,False]

是我误解了文档还是它是一个bug?
执行这种元素操作的正确方法是什么?

是的,这是一种误解

如图中所述,np.isinx,y大致相当于:

np.array([item in y for item in x])
在本例中,y是一个数组,而不是数组y中的每个元素

您需要的是:

np.array([item in y[ind] for ind,item in enumerate(x)])
或者只是

[item in y[ind] for ind,item in enumerate(x)]
如果不需要是numpy阵列:

# mine + array conversion
>>> timeit.timeit('np.array([item in y[ind] for ind,item in enumerate(x)])', globals=globals(), number=1000000)
4.598 s

# @Divakar + array conversion
>>> timeit.timeit('np.array([i in j for (i,j) in zip(x,y)])', globals=globals(), number=1000000)
4.382 s

# @hpaulj
>>> timeit.timeit('np.frompyfunc(lambda a,b: a in b,2,1)(x,y)', globals=globals(), number=1000000)
4.184 s

# mine
>>> timeit.timeit('[item in y[ind] for ind,item in enumerate(x)]', globals=globals(), number=1000000)
3.452 s

# @Divakar
>>> timeit.timeit('[i in j for (i,j) in zip(x,y)]', globals=globals(), number=1000000)
3.344 s

是的,这是一个误会

如图中所述,np.isinx,y大致相当于:

np.array([item in y for item in x])
在本例中,y是一个数组,而不是数组y中的每个元素

您需要的是:

np.array([item in y[ind] for ind,item in enumerate(x)])
或者只是

[item in y[ind] for ind,item in enumerate(x)]
如果不需要是numpy阵列:

# mine + array conversion
>>> timeit.timeit('np.array([item in y[ind] for ind,item in enumerate(x)])', globals=globals(), number=1000000)
4.598 s

# @Divakar + array conversion
>>> timeit.timeit('np.array([i in j for (i,j) in zip(x,y)])', globals=globals(), number=1000000)
4.382 s

# @hpaulj
>>> timeit.timeit('np.frompyfunc(lambda a,b: a in b,2,1)(x,y)', globals=globals(), number=1000000)
4.184 s

# mine
>>> timeit.timeit('[item in y[ind] for ind,item in enumerate(x)]', globals=globals(), number=1000000)
3.452 s

# @Divakar
>>> timeit.timeit('[i in j for (i,j) in zip(x,y)]', globals=globals(), number=1000000)
3.344 s
np.char有一些将字符串方法应用于数组元素的函数。例如,可以使用字符串查找:

In [25]: x = np.array(['a','b','c']) 
    ...: y = np.array(['ab','fgd','cdfsgfsdh'])                                 
In [27]: np.char.find(y,x)                                                      
Out[27]: array([ 0, -1,  0])
在其他情况下的测试表明,这与列表理解的速度大致相同。numpy本身没有快速编译的字符串操作,因此它仍然依赖于逐个应用的字符串方法

如果只查看y字符串的第一个字符,可以执行以下操作:

In [28]: y.astype('U1')                                                         
Out[28]: array(['a', 'f', 'c'], dtype='<U1')
In [29]: y.astype('U1')==x                                                      
Out[29]: array([ True, False,  True])
有一些字符串元素的np数组函数可以应用于char。例如,可以使用字符串查找:

In [25]: x = np.array(['a','b','c']) 
    ...: y = np.array(['ab','fgd','cdfsgfsdh'])                                 
In [27]: np.char.find(y,x)                                                      
Out[27]: array([ 0, -1,  0])
在其他情况下的测试表明,这与列表理解的速度大致相同。numpy本身没有快速编译的字符串操作,因此它仍然依赖于逐个应用的字符串方法

如果只查看y字符串的第一个字符,可以执行以下操作:

In [28]: y.astype('U1')                                                         
Out[28]: array(['a', 'f', 'c'], dtype='<U1')
In [29]: y.astype('U1')==x                                                      
Out[29]: array([ True, False,  True])

通常NumPy在处理字符串时做得不好,尤其是在处理可变长度字符串时。现在,由于您希望以一种基本的方式来实现这一点,一种方法是使用列表理解-

使用给定样本和按比例放大的大型阵列上的计时-

In [235]: x = np.array(['a','b','c'])
     ...: y = np.array(['ab','fgd','cdfsgfsdh'])

In [237]: x = np.tile(x,10000)
     ...: y = np.tile(y,10000)

# @hpaulj's solution#1
In [238]: %timeit np.char.find(y,x)!=-1
18.5 ms ± 46.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# @hpaulj's solution#2
In [241]: %timeit np.frompyfunc(lambda a,b: a in b,2,1)(x,y)
4.15 ms ± 31.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# @Akaisteph7's soln
In [273]: %timeit [item in y[ind] for ind,item in enumerate(x)]
17.4 ms ± 1.35 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [239]: %timeit [i in j for (i,j) in zip(x,y)]
13.2 ms ± 15.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
特定情况:第一个字符匹配

如果x有所有的一个字符串,如果我们只比较y的第一个字符,我们可以优化很多。正如@hpaulj在他们的帖子中所显示的一样。我们还可以使用视图的概念来进一步改进。以下是大规模阵列的计时-

# @hpaulj's solution for first char match
In [295]: %timeit y.astype('U1')==x
305 µs ± 3.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [296]: %timeit x==y.view('U1')[::y.itemsize//x.itemsize]
217 µs ± 4.72 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

通常NumPy在处理字符串时做得不好,尤其是在处理可变长度字符串时。现在,由于您希望以一种基本的方式来实现这一点,一种方法是使用列表理解-

使用给定样本和按比例放大的大型阵列上的计时-

In [235]: x = np.array(['a','b','c'])
     ...: y = np.array(['ab','fgd','cdfsgfsdh'])

In [237]: x = np.tile(x,10000)
     ...: y = np.tile(y,10000)

# @hpaulj's solution#1
In [238]: %timeit np.char.find(y,x)!=-1
18.5 ms ± 46.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# @hpaulj's solution#2
In [241]: %timeit np.frompyfunc(lambda a,b: a in b,2,1)(x,y)
4.15 ms ± 31.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# @Akaisteph7's soln
In [273]: %timeit [item in y[ind] for ind,item in enumerate(x)]
17.4 ms ± 1.35 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [239]: %timeit [i in j for (i,j) in zip(x,y)]
13.2 ms ± 15.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
特定情况:第一个字符匹配

如果x有所有的一个字符串,如果我们只比较y的第一个字符,我们可以优化很多。正如@hpaulj在他们的帖子中所显示的一样。我们还可以使用视图的概念来进一步改进。以下是大规模阵列的计时-

# @hpaulj's solution for first char match
In [295]: %timeit y.astype('U1')==x
305 µs ± 3.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [296]: %timeit x==y.view('U1')[::y.itemsize//x.itemsize]
217 µs ± 4.72 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

谢谢,我知道它可以通过列表理解来完成,但它涉及到一个for循环,有没有任何方法可以将其矢量化以提高性能?谢谢,我知道它可以通过列表理解来完成,但它涉及到一个for循环,有没有任何方法可以将其矢量化以提高性能?我的解决方案最终与您的解决方案完全相同。我想你可能只是没有仔细阅读。@Akaisteph7啊,是的,我没有正确阅读。道歉。添加到计时部分。我的解决方案最终与您的解决方案完全相同。我想你可能只是没有仔细阅读。@Akaisteph7啊,是的,我没有正确阅读。道歉。添加到计时部分。发布的解决方案中有一个对您有效吗?发布的解决方案中有一个对您有效吗?