numpy 的矢量化有什么作用?

What does numpy's vectorize do?

我有一个清理一组停用词文本的功能:

def clean_text(raw_text, stopwords_set):
    # removing everything which is not a letter
    letters_only = re.sub("[^a-zA-Z]", " ", raw_text)
    # lower case + split --> list of words
    words = letters_only.lower().split()             
    # now remove the stop words
    meaningful_words = [w for w in words if not w in stopwords_set]
    # join the remaining words together to get the cleaned tweet
    return " ".join(meaningful_words)

以及 pandas 数据框中包含 160 万条推特推文的数据集。如果我只是 apply 这个函数到数据框,就像这样:

dataframe['clean_text'] = dataframe.apply(
    lambda text: clean_text(text, set(stopwords.words('english'))),
    axis = 1)

计算需要 2 分钟(大约)完成。但是,当我这样使用 np.vectorize 时:

dataframe['clean_text'] = np.vectorize(clean_text)(
    dataframe['text'], set(stopwords.words('english')))

计算在 10 秒(大约)后完成。

这本身就不足为奇,如果不是这两种方法都只使用我机器上的一个内核的话。我假设,使用矢量化,它会自动使用多个内核来更快地完成并通过这种方式获得更快的速度,但它似乎做了一些不同的事情。

"magic" numpy 的“向量化”是做什么的?

我想知道 vectorize 如何处理这些输入。它旨在获取数组输入,将它们相互广播,并将所有元素作为标量提供给您的函数。我特别想知道它是如何处理 set 的。

有了你的函数,再加上 print(stop_words),我得到了

In [98]: words = set('one two three four five'.split())
In [99]: f=np.vectorize(clean_text)
In [100]: f(['this is one line with two words'],words)
{'five', 'four', 'three', 'one', 'two'}
{'five', 'four', 'three', 'one', 'two'}
Out[100]: 
array(['this is line with words'], 
      dtype='<U23')

该集合显示两次,因为 vectorize 运行测试用例以确定 return 数组的 dtype。但与我担心的相反,它将整个集合传递给函数。这是因为将 set 包装在数组中只会创建 0d 对象数组:

In [101]: np.array(words)
Out[101]: array({'five', 'four', 'three', 'one', 'two'}, dtype=object)

因为我们不希望向量化函数迭代第二个参数,所以我们真的应该使用 excluded 参数。速度差异可能可以忽略不计。

In [104]: f=np.vectorize(clean_text, excluded=[1])
In [105]: f(['this is one line with two words'],words)

但是只有一个数组或数据系列要迭代,vectorize 只不过是 1d 迭代或列表理解:

In [111]: text = ['this is one line with two words']
In [112]: [clean_text(t, words) for t in text]
Out[112]: ['this is line with words']

如果我使文本列表更长 (10000):

In [121]: timeit [clean_text(t, words) for t in text]
10 loops, best of 3: 98.2 ms per loop
In [122]: f=np.vectorize(clean_text, excluded=[1])
In [123]: timeit f(text,words)
10 loops, best of 3: 158 ms per loop
In [124]: f=np.vectorize(clean_text)
In [125]: timeit f(text,words)
10 loops, best of 3: 108 ms per loop

excluded 实际上会减慢 vectorize 的速度;没有它,列表理解和向量化执行相同。

所以如果 pandas apply 慢得多,那不是因为 vectorize 很神奇。这是因为 apply 很慢。