Utilize Geradores para Pipelines de Stocksim

Beginner

This tutorial is from open-source community. Access the source code

Introdução

Neste laboratório, você aprenderá como aproveitar os geradores Python para construir pipelines de processamento de dados eficientes. Geradores são um recurso Python poderoso que permite a produção de dados sob demanda, eliminando a necessidade de armazenar todos os dados na memória simultaneamente. Você descobrirá como conectar geradores para criar fluxos de trabalho de processamento de dados semelhantes aos pipes Unix.

Os objetivos deste laboratório são entender os fundamentos dos pipelines de processamento baseados em geradores, criar fluxos de trabalho de processamento de dados usando geradores Python e filtrar e formatar fluxos de dados em tempo real. O arquivo ticker.py será criado durante este laboratório. Observe que, para este exercício, o programa stocksim.py deve estar em execução em segundo plano, e você usará a função follow() de um exercício anterior.

Pipeline de Gerador Básico com Dados CSV

Nesta etapa, vamos aprender como criar um pipeline de processamento básico usando geradores. Mas primeiro, vamos entender o que são geradores. Geradores são um tipo especial de iterador em Python. Ao contrário dos iteradores regulares que podem carregar todos os dados na memória de uma vez, os geradores geram valores sob demanda. Isso é extremamente útil ao lidar com grandes fluxos de dados, pois economiza memória. Em vez de ter que armazenar todo o conjunto de dados na memória, o gerador produz valores um por um conforme você precisa deles.

Entendendo Geradores

Um gerador é essencialmente uma função que retorna um iterador. Quando você itera sobre este iterador, ele produz uma sequência de valores. A maneira como você escreve uma função geradora é semelhante a uma função regular, mas há uma diferença fundamental. Em vez de usar a instrução return, uma função geradora usa a instrução yield. A instrução yield tem um comportamento único. Ela pausa a função e salva seu estado atual. Quando o próximo valor é solicitado, a função continua de onde parou. Isso permite que o gerador produza valores incrementalmente sem ter que começar do início toda vez.

Usando a Função follow()

A função follow() que você criou anteriormente funciona de maneira semelhante ao comando Unix tail -f. O comando tail -f monitora continuamente um arquivo em busca de novo conteúdo, e a função follow() faz o mesmo. Agora, vamos usá-la para criar um pipeline de processamento simples.

Passo 1: Abra uma nova janela de terminal

Primeiro, abra uma nova janela de terminal no WebIDE. Você pode fazer isso indo em Terminal → New Terminal. Este novo terminal será onde executaremos nossos comandos Python.

Passo 2: Inicie um shell interativo Python

Depois que o novo terminal estiver aberto, inicie um shell interativo Python. Você pode fazer isso digitando o seguinte comando no terminal:

python3

O shell interativo Python permite que você execute o código Python linha por linha e veja os resultados imediatamente.

Passo 3: Importe a função follow e configure o pipeline

Agora, importaremos a função follow e configuraremos um pipeline básico para ler os dados das ações. No shell interativo Python, digite o seguinte código:

>>> from follow import follow
>>> import csv
>>> lines = follow('stocklog.csv')
>>> rows = csv.reader(lines)
>>> for row in rows:
...     print(row)
...

Aqui está o que cada linha faz:

  • from follow import follow: Isso importa a função follow do módulo follow.
  • import csv: Isso importa o módulo csv, que é usado para ler e escrever arquivos CSV em Python.
  • lines = follow('stocklog.csv'): Isso chama a função follow com o nome do arquivo stocklog.csv. A função follow retorna um gerador que produz novas linhas à medida que são adicionadas ao arquivo.
  • rows = csv.reader(lines): A função csv.reader() pega as linhas geradas pela função follow e as analisa em linhas de dados CSV.
  • O loop for itera por essas linhas e imprime cada uma.

Passo 4: Verifique a saída

Após executar o código, você deve ver uma saída semelhante a esta (seus dados variarão):

['BA', '98.35', '6/11/2007', '09:41.07', '0.16', '98.25', '98.35', '98.31', '158148']
['AA', '39.63', '6/11/2007', '09:41.07', '-0.03', '39.67', '39.63', '39.31', '270224']
['XOM', '82.45', '6/11/2007', '09:41.07', '-0.23', '82.68', '82.64', '82.41', '748062']
['PG', '62.95', '6/11/2007', '09:41.08', '-0.12', '62.80', '62.97', '62.61', '454327']
...

Esta saída indica que você criou um pipeline de dados com sucesso. A função follow() gera linhas do arquivo, e essas linhas são então passadas para a função csv.reader(), que as analisa em linhas de dados.

Se você viu saída suficiente, pode parar a execução pressionando Ctrl+C.

O que está Acontecendo?

Vamos detalhar o que está acontecendo neste pipeline:

  1. follow('stocklog.csv') cria um gerador. Este gerador acompanha o arquivo stocklog.csv e produz novas linhas à medida que são adicionadas ao arquivo.
  2. csv.reader(lines) pega as linhas geradas pela função follow e as analisa em dados de linha CSV. Ele entende a estrutura dos arquivos CSV e divide as linhas em valores individuais.
  3. O loop for então itera por essas linhas, imprimindo cada uma. Isso permite que você veja os dados em um formato legível.

Este é um exemplo simples de um pipeline de processamento de dados usando geradores. Nas próximas etapas, construiremos pipelines mais complexos e úteis.

Criando a Classe Ticker

No processamento de dados, trabalhar com dados brutos pode ser bastante desafiador. Para tornar nosso trabalho com dados de ações mais organizado e eficiente, definiremos uma classe adequada para representar as cotações de ações. Essa classe servirá como um modelo para nossos dados de ações, tornando nosso pipeline de processamento de dados mais robusto e fácil de gerenciar.

Criando o Arquivo ticker.py

  1. Primeiro, precisamos criar um novo arquivo no WebIDE. Você pode fazer isso clicando no ícone "New File" ou clicando com o botão direito no explorador de arquivos e selecionando "New File". Nomeie este arquivo ticker.py. Este arquivo conterá o código para nossa classe Ticker.

  2. Agora, vamos adicionar o seguinte código ao seu arquivo ticker.py recém-criado. Este código definirá nossa classe Ticker e configurará um pipeline de processamento simples para testá-la.

## ticker.py

from structure import Structure, String, Float, Integer

class Ticker(Structure):
    name = String()
    price = Float()
    date = String()
    time = String()
    change = Float()
    open = Float()
    high = Float()
    low = Float()
    volume = Integer()

if __name__ == '__main__':
    from follow import follow
    import csv
    lines = follow('stocklog.csv')
    rows = csv.reader(lines)
    records = (Ticker.from_row(row) for row in rows)
    for record in records:
        print(record)
  1. Após adicionar o código, salve o arquivo. Você pode fazer isso pressionando Ctrl+S ou selecionando "File" → "Save" no menu. Salvar o arquivo garante que suas alterações sejam preservadas e possam ser executadas posteriormente.

Entendendo o Código

Vamos dar uma olhada mais de perto no que este código faz passo a passo:

  1. No início do código, estamos importando Structure e tipos de campo do módulo structure.py. Este módulo já foi configurado para você. Essas importações são essenciais porque fornecem os blocos de construção para nossa classe Ticker. A classe Structure será a classe base para nossa classe Ticker, e os tipos de campo como String, Float e Integer definirão os tipos de dados de nossos campos de dados de ações.

  2. Em seguida, definimos uma classe Ticker que herda de Structure. Esta classe tem vários campos que representam diferentes aspectos dos dados das ações:

    • name: Este campo armazena o símbolo da ação, como "IBM" ou "AAPL". Ele nos ajuda a identificar com qual ação da empresa estamos lidando.
    • price: Ele contém o preço atual da ação. Esta é uma informação crucial para os investidores.
    • date e time: Esses campos nos dizem quando a cotação da ação foi gerada. Saber a hora e a data é importante para analisar as tendências de preços das ações ao longo do tempo.
    • change: Isso representa a mudança de preço da ação. Ele mostra se o preço da ação subiu ou desceu em comparação com um ponto anterior.
    • open, high, low: Esses campos representam o preço de abertura, o preço mais alto e o preço mais baixo da ação durante um determinado período. Eles nos dão uma ideia da faixa de preço da ação.
    • volume: Este campo armazena o número de ações negociadas. Um alto volume de negociação pode indicar um forte interesse do mercado em uma ação específica.
  3. No bloco if __name__ == '__main__':, configuramos um pipeline de processamento. Este bloco de código será executado quando executarmos o arquivo ticker.py diretamente.

    • follow('stocklog.csv') é uma função que gera linhas do arquivo stocklog.csv. Ele nos permite ler o arquivo linha por linha.
    • csv.reader(lines) pega essas linhas e as analisa em dados de linha. CSV (Valores Separados por Vírgula) é um formato de arquivo comum para armazenar dados tabulares, e esta função nos ajuda a extrair os dados de cada linha.
    • (Ticker.from_row(row) for row in rows) é uma expressão geradora. Ele pega cada linha de dados e a converte em um objeto Ticker. Dessa forma, transformamos os dados CSV brutos em objetos estruturados que são mais fáceis de trabalhar.
    • O loop for itera sobre esses objetos Ticker e imprime cada um. Isso nos permite ver os dados estruturados em ação.

Executando o Código

Vamos executar o código para ver como ele funciona:

  1. Primeiro, precisamos ter certeza de que estamos no diretório do projeto no terminal. Se você ainda não estiver lá, use o seguinte comando para navegar até ele:

    cd /home/labex/project
  2. Depois de estar no diretório correto, execute o script ticker.py usando o seguinte comando:

    python3 ticker.py
  3. Após executar o script, você deve ver uma saída semelhante a esta (seus dados variarão):

    Ticker(IBM, 103.53, 6/11/2007, 09:53.59, 0.46, 102.87, 103.53, 102.77, 541633)
    Ticker(MSFT, 30.21, 6/11/2007, 09:54.01, 0.16, 30.05, 30.21, 29.95, 7562516)
    Ticker(AA, 40.01, 6/11/2007, 09:54.01, 0.35, 39.67, 40.15, 39.31, 576619)
    Ticker(T, 40.1, 6/11/2007, 09:54.08, -0.16, 40.2, 40.19, 39.87, 1312959)

Você pode parar a execução do script pressionando Ctrl+C quando tiver visto saída suficiente.

Observe como os dados CSV brutos foram transformados em objetos Ticker estruturados. Essa transformação torna os dados muito mais fáceis de trabalhar em nosso pipeline de processamento, pois agora podemos acessar e manipular os dados das ações usando os campos definidos na classe Ticker.

Construindo um Pipeline de Dados Mais Complexo

Agora, vamos levar nosso pipeline de dados para o próximo nível, adicionando filtragem e melhorando a apresentação dos dados. Isso tornará mais fácil analisar e entender as informações com as quais estamos trabalhando. Faremos alterações em nosso script ticker.py. A filtragem dos dados nos ajudará a nos concentrar nas informações específicas que nos interessam, e apresentá-los em uma tabela bem formatada tornará mais legível.

Atualizando o Arquivo ticker.py

  1. Primeiro, abra seu arquivo ticker.py no WebIDE. O WebIDE é uma ferramenta que permite escrever e editar código diretamente em seu navegador. Ele fornece um ambiente conveniente para fazer alterações em seus scripts Python.

  2. Em seguida, precisamos substituir o bloco if __name__ == '__main__': no arquivo ticker.py pelo seguinte código. Este bloco de código é o ponto de entrada do nosso script, e ao substituí-lo, estaremos alterando como o script processa e exibe os dados.

if __name__ == '__main__':
    from follow import follow
    import csv
    from tableformat import create_formatter, print_table

    formatter = create_formatter('text')

    lines = follow('stocklog.csv')
    rows = csv.reader(lines)
    records = (Ticker.from_row(row) for row in rows)
    negative = (rec for rec in records if rec.change < 0)
    print_table(negative, ['name', 'price', 'change'], formatter)
  1. Depois de fazer essas alterações, salve o arquivo. Você pode fazer isso pressionando Ctrl+S no teclado ou selecionando "File" → "Save" no menu. Salvar o arquivo garante que suas alterações sejam preservadas e possam ser executadas posteriormente.

Entendendo o Pipeline Aprimorado

Vamos dar uma olhada mais de perto no que este pipeline aprimorado faz. Entender cada etapa o ajudará a ver como as diferentes partes do código trabalham juntas para processar e exibir os dados.

  1. Começamos importando create_formatter e print_table do módulo tableformat. Este módulo já está configurado para você, e ele fornece funções que nos ajudam a formatar e imprimir os dados em uma tabela agradável.

  2. Em seguida, criamos um formatador de texto usando create_formatter('text'). Este formatador será usado para formatar os dados de uma forma que seja fácil de ler.

  3. Agora, vamos detalhar o pipeline passo a passo:

    • follow('stocklog.csv') é uma função que gera linhas do arquivo stocklog.csv. Ele monitora continuamente o arquivo em busca de novos dados e fornece as linhas uma por uma.
    • csv.reader(lines) pega as linhas geradas por follow e as analisa em dados de linha. Isso é necessário porque os dados no arquivo CSV estão em um formato de texto, e precisamos convertê-los em um formato estruturado com o qual possamos trabalhar.
    • (Ticker.from_row(row) for row in rows) é uma expressão geradora que converte cada linha de dados em um objeto Ticker. Um objeto Ticker representa uma ação e contém informações como o nome, preço e mudança da ação.
    • (rec for rec in records if rec.change < 0) é outra expressão geradora que filtra os objetos Ticker. Ele mantém apenas os objetos onde a mudança de preço da ação é negativa. Isso nos permite focar nas ações que diminuíram de preço.
    • print_table(negative, ['name', 'price', 'change'], formatter) pega os objetos Ticker filtrados e os formata em uma tabela usando o formatador que criamos anteriormente. Em seguida, ele imprime a tabela no console.

Este pipeline demonstra o poder dos geradores. Em vez de carregar todos os dados do arquivo na memória de uma vez, estamos encadeando várias operações (leitura, análise, conversão, filtragem) e processando os dados um item por vez. Isso economiza memória e torna o código mais eficiente.

Executando o Pipeline Aprimorado

Vamos executar o código atualizado para ver os resultados.

  1. Primeiro, certifique-se de estar no diretório do projeto no terminal. Se você ainda não estiver lá, pode navegar até ele usando o seguinte comando:

    cd /home/labex/project
  2. Depois de estar no diretório do projeto, execute o script ticker.py usando o seguinte comando:

    python3 ticker.py
  3. Após executar o script, você deve ver uma tabela bem formatada no terminal. Esta tabela mostra apenas as ações com mudanças de preço negativas.

           name      price     change
     ---------- ---------- ----------
              C      53.12      -0.21
            UTX      70.04      -0.19
            AXP      62.86      -0.18
            MMM      85.72      -0.22
            MCD      51.38      -0.03
            WMT      49.85      -0.23
             KO       51.6      -0.07
            AIG      71.39      -0.14
             PG      63.05      -0.02
             HD      37.76      -0.19

Se você viu saída suficiente e deseja interromper a execução do script, pode pressionar Ctrl+C no teclado.

O Poder dos Pipelines de Geradores

O que criamos aqui é um poderoso pipeline de processamento de dados. Vamos resumir o que ele faz:

  1. Ele monitora continuamente o arquivo stocklog.csv em busca de novos dados. Isso significa que, à medida que novos dados são adicionados ao arquivo, o pipeline os processará automaticamente.
  2. Ele analisa os dados CSV do arquivo em objetos Ticker estruturados. Isso torna mais fácil trabalhar com os dados e realizar operações neles.
  3. Ele filtra os dados com base em um critério específico, neste caso, mudanças de preço negativas. Isso nos permite focar nas ações que estão perdendo valor.
  4. Ele formata e apresenta os dados filtrados em uma tabela legível. Isso facilita a análise dos dados e a conclusão de conclusões.

Uma das principais vantagens de usar geradores neste pipeline é que ele usa memória mínima. Os geradores produzem valores sob demanda, o que significa que eles não armazenam todos os dados na memória de uma vez. Isso é semelhante aos pipes Unix, onde cada componente processa os dados e os passa para o próximo componente.

Você pode pensar nos geradores como blocos de Lego. Assim como você pode empilhar blocos de Lego para criar estruturas diferentes, você pode combinar geradores para criar fluxos de trabalho de processamento de dados poderosos. Essa abordagem modular permite que você construa sistemas complexos a partir de componentes simples e reutilizáveis.

Resumo

Neste laboratório, você aprendeu como usar geradores Python para construir pipelines de processamento de dados eficientes. Você concluiu várias tarefas importantes, como usar a função follow() para monitorar um arquivo em busca de novos dados, criar uma classe Ticker para representar cotações de ações e construir um pipeline de processamento de vários estágios que lê, analisa e filtra dados CSV, e então formata e exibe os resultados.

A abordagem baseada em geradores oferece múltiplas vantagens, incluindo eficiência de memória, pois os dados são processados sob demanda, modularidade, permitindo a fácil combinação e reutilização de componentes de pipeline, e simplicidade na expressão de fluxos de dados complexos. Esses conceitos são comumente aplicados no processamento de dados do mundo real, especialmente para grandes conjuntos de dados ou dados de streaming.