Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Sugestão] Forma de criar coluna condicional mais performatica

Tem uma forma mais rápida de criar a coluna com numpy

import numpy as np

dados['possui_suite'] = np.where(dados['Suites'] > 0, 'sim', 'não')

Numa base de dados grande é bem mais performatico que apply.

2 respostas
solução!

Oi, Marcelo! Como vai?

Agradeço por compartilhar essa sugestão com a comunidade Alura. Sua observação sobre a forma de criar coluna condicional com numpy é relevante e vale ser destacada para todos que trabalham com bases de dados grandes.

O uso do np.where() realmente traz um ganho significativo de performance em bases maiores quando comparado ao apply(). Ao importar numpy com import numpy as np e aplicar o np.where(), como no exemplo abaixo, você aproveita operações vetorizadas que processam os dados de forma mais rápida e eficiente:

dados['possui_suite'] = np.where(dados['Suites'] > 0, 'sim', 'não')

Essa abordagem é bastante utilizada em cenários de análise de dados com Pandas e NumPy, quando trabalhamos com grandes volumes de informação.

Uma dica complementar é usar o método astype() para criar colunas binárias de forma simples e igualmente performatica. Veja este exemplo:

dados['possui_suite'] = (dados['Suites'] > 0).astype(str)

Nesse caso, o código verifica se o valor da coluna Suites é maior que 0 e transforma o resultado em texto. Essa técnica também evita loops explícitos e melhora bastante o desempenho em uma base grande, sendo uma alternativa rápida e elegante ao apply().

Ótima contribuição, Marcelo. Dicas como essa enriquecem muito o aprendizado coletivo da comunidade.

Você já chegou a comparar o tempo de execução entre o np.where(), o astype() e o apply() em alguma base de dados grande para medir a diferença real de performance?

Alura Conte com o apoio da comunidade Alura na sua jornada. Abraços e bons estudos!

Oi Monalisa,

Obrigado pelo feedback, esta forma que você mostrou eu penso que tem um overhead de transformar para "sim"/ "não" com um np.where depois ou map, então penso que não é mais performático. e talvez sem o astype sendo puramente bool pode ser mais performático, vamos fazer o teste que, desafio aceito:

import pandas as pd
import numpy as np
import timeit

# 10 milhões de linhas com numeros aleatorios
n = 10_000_000
df = pd.DataFrame({'numero': np.random.randint(-1, 2, size=n)})

# Teste com np.where
def test_np_where():
    return np.where(df['numero'] > 0, 'sim', 'não')

# Teste com astype (Note: para mapear para 'sim'/'não' exige um passo extra)
def test_astype():
    # .astype(str) apenas converte True/False para "True"/"False" strings, 
    # se você quer "sim"/"não", o np.where ou .map é necessário.
    # Vamos testar a conversão direta para comparação:
    return (df['numero'] > 0).astype(str)

# Teste com astype (Note: para mapear para 'sim'/'não' exige um passo extra)
def test_sem_astype():
    # .astype(str) apenas converte True/False para "True"/"False" strings, 
    # se você quer "sim"/"não", o np.where ou .map é necessário.
    # Vamos testar a conversão direta para comparação:
    return (df['numero'] > 0)


# Teste com .apply()
def test_apply():
    return df['numero'].apply(lambda x: 'sim' if x > 0 else 'não')

# Executando os testes
print(f"Executando benchmarks com {n:,} linhas...\n")

t1 = timeit.timeit(test_np_where, number=3)
print(f"np.where:      {t1/3:.4f} segundos (média de 3 execuções)")

t2 = timeit.timeit(test_astype, number=3)
print(f"astype:        {t2/3:.4f} segundos (média de 3 execuções)")

t3 = timeit.timeit(test_sem_astype, number=3)
print(f"Sem astype:    {t3/3:.4f} segundos (média de 3 execuções)")

t4 = timeit.timeit(test_apply, number=3)
print(f"apply:         {t4/3:.4f} segundos (média de 3 execuções)")

Resultados:

Executando benchmarks com 10,000,000 linhas...

np.where:        0.2719 segundos (média de 3 execuções)
astype:             2.7610 segundos (média de 3 execuções)
Sem astype:    0.0109 segundos (média de 3 execuções)
apply:               2.4380 segundos (média de 3 execuções)

Se pegarmos o método mais lento como referencia, vemos o impacto da forma vetorizada e do processamento linha a linha.

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Deste teste simples podemos concluir que:

  • Sem AsType a comparação direta é mais performática, usaria isso se fosse pra ser transformação direta e manter o campo bool ( se tiver que transformar tem custo de outra função como np.where ou map)
  • np.where é o segundo mais rápido e esta transformando a coluna em "Sim"/"Não" então eu escolheria essa para transformação
  • apply fica claro que tem overhead
  • astype pior de todos, mas aqui ele esta convertendo e precisa de muita memória fara uma cópia.

E talvez, no caso de arquivos grandes talvez outra ferramenta seja mais adequada.

Valeu o feedback, espero ter contribuido humildemente aqui, algum colega pode ser melhor forma de ver isso elevar o nível.

ps: Será que o que colcoamos aqui no fórum alimentar o RAG da LURI ou de alguma IA de resposta automática?