Essa é uma pergunta bastante conceitual, mas eu esperava conseguir alguns bons conselhos sobre isso. Muita da programação que faço é com matrizes ( NumPy ); Frequentemente, tenho que combinar itens em duas ou mais matrizes de tamanhos diferentes e a primeira coisa a que vou é um loop for ou, pior ainda, um loop for aninhado. Eu quero evitar os loops, tanto quanto possível, porque eles são lentos (pelo menos em Python).
Eu sei que para muitas coisas com o NumPy existem comandos predefinidos que eu só preciso pesquisar, mas você (como programadores mais experientes) tem um processo de pensamento geral que vem à mente quando você precisa iterar algo?
Então, muitas vezes tenho algo assim, o que é horrível e quero evitá-lo:
small_array = np.array(["one", "two"])
big_array = np.array(["one", "two", "three", "one"])
for i in range(len(small_array)):
for p in range(len(big_array)):
if small_array[i] == big_array[p]:
print "This item is matched: ", small_array[i]
Eu sei que existem várias maneiras diferentes de conseguir isso em particular, mas estou interessado em um método geral de pensamento, se existir.
I want to avoid for-loops as much as possible because they are slow (at least in Python).
Parece que você está resolvendo o problema errado aqui. Se você precisar iterar sobre algo, precisará iterar sobre algo; você terá um desempenho semelhante, independentemente da construção do Python usada. Se seu código é lento, não é porque você temfor
loops; é porque você está fazendo um trabalho desnecessário ou no lado Python que pode ser feito no lado C. No seu exemplo, você está fazendo um trabalho extra; você poderia ter feito isso com um loop em vez de dois.Respostas:
Essa é uma dificuldade conceitual comum ao aprender a usar o NumPy com eficiência. Normalmente, o processamento de dados no Python é melhor expresso em termos de iteradores , para manter baixo o uso de memória, maximizar oportunidades de paralelismo com o sistema de E / S e fornecer reutilização e combinação de partes de algoritmos.
Mas o NumPy inverte tudo isso: a melhor abordagem é expressar o algoritmo como uma sequência de operações de toda a matriz , para minimizar a quantidade de tempo gasto no interpretador lento do Python e maximizar a quantidade de tempo gasto nas rotinas NumPy compiladas rapidamente.
Aqui está a abordagem geral que tomo:
Mantenha a versão original da função (que você acredita estar correta) para poder testá-la em relação às versões aprimoradas, tanto quanto à correção e à velocidade.
Trabalhe de dentro para fora: ou seja, comece com o loop mais interno e veja se pode ser vetorizado; quando você tiver feito isso, saia de um nível e continue.
Gaste muito tempo lendo a documentação do NumPy . Existem muitas funções e operações lá e elas nem sempre são nomeadas de maneira brilhante, por isso vale a pena conhecê-las. Em particular, se você estiver pensando, "se houvesse uma função que fizesse isso e aquilo", vale a pena gastar dez minutos procurando por ela. Geralmente está lá em algum lugar.
Não há substituto para a prática, então vou dar alguns exemplos de problemas. A meta para cada problema é reescrever a função para que ele é totalmente vectorizada : isto é, de modo que consiste em uma sequência de operações Numpy em matrizes de inteiros, sem alças nativas Python (nenhum
for
ouwhile
demonstrações, não há iterators ou comprehensions).Problema 1
Problema 2
Problema 3
Spoilers abaixo. Você obterá os melhores resultados se tentar antes de olhar para as minhas soluções!
resposta 1
Resposta 2
Resposta 3
fonte
list
Para tornar as coisas mais rápidas, você precisa ler suas estruturas de dados e usar as apropriadas.
Para tamanhos não triviais de matriz pequena e matriz grande (digamos, pequeno = 100 elementos e grande = 10.000 elementos), uma maneira de fazer isso é classificar a matriz pequena, iterar sobre a matriz grande e usar uma pesquisa binária para encontrar elementos correspondentes na pequena matriz.
Isso tornaria a complexidade de tempo máxima, O (N log N) (e para pequenas matrizes pequenas e muito grandes) é mais próxima de O (N)) onde sua solução de loop aninhado é O (N ^ 2)
Contudo. quais estruturas de dados são mais eficientes depende muito do problema real.
fonte
Você pode usar um dicionário para otimizar significativamente o desempenho
Este é outro exemplo:
fonte