比较和索引长度大于1的数组系列

3
标题听起来比实际情况复杂。鉴于数据。
data = [
    np.array(['x'], dtype='object'),
    np.array(['y'], dtype='object'),
    np.array(['z'], dtype='object'),
    np.array(['x', 'z', 'y'], dtype='object'),
    np.array(['y', 'x'], dtype='object'),
]    

s = pd.Series(data)

我想要获取数组 s 中满足条件 s == np.array(['x']) 的元素。显而易见的方法是:
c = np.array(['x'])
s[s==c]

无法工作,因为在比较中出现了一个 ValueError 错误,指责“'长度必须匹配才能进行比较',(5,),(1,)”。我还尝试过。
s[s=='x']

只有当的元素都只有一个元素时,才能起作用。 有没有一种方法可以检索所有的元素,其中 == c,而不需要将元素转换为字符串?
2个回答

2
使用列表推导式和 numpy.array_equal 函数:
c = np.array(['x'])

out = s[[np.array_equal(a, c) for a in s]]

如果你需要重复这个操作(使用更短的语法),可以使用一个带有partial函数的替代方法。
from functools import partial
eq_c = partial(np.array_equal, c)

out = s[map(eq_c, s)]

输出:

0    [x]
dtype: object

肯定有一种向量化的方法来做这个吧? - undefined
@Nick 我不这么认为,你需要先将数组集合转换为一个通用的结构,这个过程比起一开始就循环遍历要更加耗费资源。 - undefined
嗯...是的,我猜是这样的... - undefined
@Nick 你可以随时使用 eq_c = np.vectorize(lambda a: np.array_equal(a, c)) ; df[eq_c(s)],但这仍然是一个循环。 - undefined

2
如果我们使用循环,我认为这是一种更简单的方法。
out = s[s.apply(lambda x: x.tolist() == ['x'])]

出:

0    [x]
dtype: object

检查示例

import pandas as pd
import numpy as np

data1 = [
    np.array(['x'], dtype='object'),
    np.array(['y'], dtype='object'),
    np.array(['z'], dtype='object'),
    np.array(['x', 'z', 'y'], dtype='object'),
    np.array(['y', 'x'], dtype='object'),
]  * 1000000
s1 = pd.Series(data1)

5000000行
c = np.array(['x'], dtype='object')
d = c.tolist()

检查速度
>>> import timeit
>>> %timeit s1[s1.apply(lambda x: x.tolist() == d)]

1.38 s ± 106 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>> %timeit s1[[np.array_equal(a, c) for a in s1]]

22.2 s ± 754 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>> from functools import partial
>>> eq_c = partial(np.array_equal, c)
>>> %timeit s1[map(eq_c, s1)]


21.8 s ± 449 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

更短的语法并不意味着更简单的复杂度。将数组转换为列表是一项昂贵的操作。相比之下,np.array_equal(正如我所建议的)首先比较维度,如果形状不匹配,则立即返回False。在这里,无论将来是否使用列表,您都将其转换为列表。我猜等价的Python代码可能是c = ['x'] ; s.apply(lambda x: len(x)==len(c) and x.tolist()==c),即使在这里,与数组比较相比,这仍然更加昂贵。 - undefined
@mozway 我认为这种方法更简单的原因如下。语法更简单,代码更容易理解,可以在pandas中解决,并且结果不会很慢。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接