https://numpy.org/doc/1.18/reference/generated/numpy.vectorize.html
Este tutorial menciona que a implementação de vetorizar é essencialmente um loop for. Mas, até onde eu sei, uma função vetorizada usará
SIMD, então é correto dizer que a implementação de numpy.vectorize é essencialmente um loop for? Se verdadeiro, então é mais rápido do que funções não vetorizadas apenas porque é um loop implementado em linguagem C?
Muito obrigado antecipadamente.
Sim. No contexto de linguagens de programação de matriz numérica interpretada como Python (com numpy) e MATLAB ™, costumamos usar "vetorização" para nos referirmos à substituição de loops explícitos na linguagem de programação interpretada por uma função (ou operador) que cuida de todos os loop lógico internamente. Em numpy, os ufunc
s implementam essa lógica. Isso não está relacionado ao uso de "vetorização" para se referir ao uso de instruções de CPU SIMD que computam sobre várias entradas simultaneamente, exceto que ambos usam uma metáfora semelhante: eles são como suas contrapartes "escalares", mas realizam o cálculo sobre vários valores de entrada com uma única invocação.
Com numpy.vectorize()
, geralmente não há muitos benefícios de velocidade sobre o loop Python for
explícito. O objetivo principal disso é transformar a função Python em ufunc
, que implementa toda a semântica de transmissão e, portanto, lida com entradas de qualquer tamanho. A função Python que está sendo "vetorizada" ainda ocupa a maior parte do tempo, além de converter o valor bruto de cada elemento em um objeto Python para passar para a função. Você não esperaria que np.vectorize(lambda x, y: x + y)
fosse tão rápido quanto o ufunc np.add
, que é C tanto no loop quanto no conteúdo do loop.
Obrigado por sua explicação detalhada. Mas para ser claro, deixe-me dar um exemplo.
import pandas as pd
import numpy as np
df = pd.DataFrame({'a': range(100000), 'b': range(1, 1000001)})
# method1
df.loc[:, 'c'] = df.apply(lambda x: x['a'] + x['b'], axis=1)
# method2
df.loc[:, 'c'] = np.vectorize(lambda x, y: x + y)(df['a'], df['b'])
# method3
df.loc[:, 'c'] = np.add(df['a'], df['b'])
então com sua explicação, eu acho
método | loop em C | conteúdo do loop em C | usar SIMD
- | - | - | -
1 | × | × | ×
2 | √ | × | ×
3 | √ | √ | √
Direito?
np.add
é mais rápido do que np.vectorize(lambda x, y: x + y)
porque evita a conversão de C doubles em objetos Python e a sobrecarga de chamada de função Python. É possível que também use instruções SIMD, dependendo se você tem ou não
np.add
é mais rápido do quenp.vectorize(lambda x, y: x + y)
porque evita a conversão de C doubles em objetos Python e a sobrecarga de chamada de função Python. É possível que _também_ use instruções SIMD, dependendo se você tem ou não
Deixa comigo. Obrigado.
Você pode usar vectorize
de numba para produzir ufuncs que operam em paralelo sem sobrecargas do Python:
https://numba.pydata.org/numba-doc/latest/user/vectorize.html
Comentários muito úteis
Sim. No contexto de linguagens de programação de matriz numérica interpretada como Python (com numpy) e MATLAB ™, costumamos usar "vetorização" para nos referirmos à substituição de loops explícitos na linguagem de programação interpretada por uma função (ou operador) que cuida de todos os loop lógico internamente. Em numpy, os
ufunc
s implementam essa lógica. Isso não está relacionado ao uso de "vetorização" para se referir ao uso de instruções de CPU SIMD que computam sobre várias entradas simultaneamente, exceto que ambos usam uma metáfora semelhante: eles são como suas contrapartes "escalares", mas realizam o cálculo sobre vários valores de entrada com uma única invocação.Com
numpy.vectorize()
, geralmente não há muitos benefícios de velocidade sobre o loop Pythonfor
explícito. O objetivo principal disso é transformar a função Python emufunc
, que implementa toda a semântica de transmissão e, portanto, lida com entradas de qualquer tamanho. A função Python que está sendo "vetorizada" ainda ocupa a maior parte do tempo, além de converter o valor bruto de cada elemento em um objeto Python para passar para a função. Você não esperaria quenp.vectorize(lambda x, y: x + y)
fosse tão rápido quanto o ufuncnp.add
, que é C tanto no loop quanto no conteúdo do loop.