Análise de Atendimento Hospitalar com PySpark

Por Réulison Silva
Réulison Silva
Published on
Análise de Atendimento Hospitalar com PySpark

Este artigo é baseado no projeto de código aberto atendimento-hospitalar-pyspark, disponível no GitHub. É um projeto de estudo, mas as técnicas aqui demonstradas podem ter aplicabilidade real em hospitais e clínicas que enfrentam problemas de fila e ociosidade.

Introdução: por que analisar tempos de espera?

Todo mundo que já precisou de atendimento médico sabe como é frustrante esperar horas na fila. Mas o que talvez você não saiba é que essa espera não é só um problema para o paciente — é um problema financeiro gigantesco para o hospital.

Um estudo publicado no Jornal Brasileiro de Economia da Saúde revelou que ineficiências na gestão hospitalar podem ter representado até R2bilho~esemreceitasna~orealizadasentre2020e2024.Oprincipalvetordeperdaidentificadoestaˊnotempodepermane^nciahospitalar.Enquantooreferencialesperadoseriade2,9dias,ameˊdiaobservadafoide4,11dias,umdesvioque,isoladamente,representaumaoportunidadeestimadadeR 2 bilhões em receitas não realizadas entre 2020 e 2024. O principal vetor de perda identificado está no tempo de permanência hospitalar. Enquanto o referencial esperado seria de 2,9 dias, a média observada foi de 4,11 dias, um desvio que, isoladamente, representa uma oportunidade estimada de R 1,6 bilhão no período analisado.

A extensão das internações impacta diretamente a rotatividade de leitos e a capacidade de geração de receita, além de pressionar custos operacionais.

Outro fator relevante é a logística de alta hospitalar. Cerca de 30,69% das altas ocorreram fora do horário considerado adequado, gerando impacto adicional estimado em R474milho~es,associadoaˋmenoreficie^ncianousodaestruturahospitalar.Fonte:[Ineficie^nciahospitalarpodegerarperdasdeR 474 milhões, associado à menor eficiência no uso da estrutura hospitalar. Fonte: [Ineficiência hospitalar pode gerar perdas de R 2 bi](https://healthcare.grupomidia.com/ineficiencia-hospitalar-pode-gerar-perdas-de-r-2-bi/ "Ineficiência hospitalar pode gerar perdas de R$ 2 bi").

E isso sem falar no impacto clínico: quase 70 estudos mostram que a permanência prolongada em departamentos de emergência está associada a riscos elevados à saúde, atrasos no tratamento e aumento da probabilidade de morte.

Fonte: dados do estudo 2iM/JBES.
Fonte: dados do estudo 2iM/JBES.

No Brasil, a situação das filas do SUS é ainda mais dramática. Segundo reportagem do jornal O Globo de março de 2025, o tempo médio de espera para consultas no SUS atingiu um recorde histórico em 2024, com média de 57 dias — e pacientes aguardam até 634 dias por cirurgias eletivas. Para se ter uma ideia da escalada, em 2019 a média geral era de 31 dias; saltou para 51 dias em 2022 e chegou a 52 dias em 2023.

Mas não é só no setor público. Nos Estados Unidos, um estudo publicado na Annals of Emergency Medicine mostrou que o custo diário por paciente que fica "boarding" (esperando por um leito de internação) na emergência é de U1.856,quaseodobrodocustodeU 1.856, quase o dobro do custo de U 993 para clientes que já estão internados.

Esses números deixam claro: tempo de espera é dinheiro. E é exatamente isso que o projeto que vamos explorar neste artigo se propõe a investigar.

O que é PySpark e por que usá-lo?

A definição direta

PySpark é a API oficial do Apache Spark para Python. Se você já usou pandas para analisar dados, pode pensar no PySpark como um "pandas turbinado" — capaz de processar volumes de dados muito maiores, distribuindo o trabalho entre várias máquinas (ou núcleos de CPU). O Apache Spark, por sua vez, é um engine unificado de análise para processamento de dados em larga escala, com APIs de alto nível em Scala, Java, Python e R.

Quando usar PySpark em vez de pandas?

A regra prática é simples:

  • Pandas: dados que cabem na memória RAM de uma máquina (até alguns GB).
  • PySpark: dados que não cabem na memória, ou que você quer processar de forma distribuída e escalável.

No caso do nosso projeto, o dataset tem cerca de 30 mil linhas — um volume que o pandas daria conta tranquilamente. Mas o objetivo é estudar PySpark, então a escolha faz todo sentido: você treina com dados pequenos e depois aplica as mesmas técnicas em dados de produção (milhões de atendimentos) sem mudar o código.

Representação estrutural para comparar o pandas e o PySpark
Representação estrutural para comparar o pandas e o PySpark
Arquitetura de Processamento: pandas vs. PySpark
  • pandas (Máquina Única)

    • Ambiente: Executa localmente em um único computador ou notebook.
    • Limitação: O volume de dados fica estritamente restrito à memória RAM disponível no seu hardware.
    • Fluxo: Monolítico e sequencial (utiliza essencialmente um único núcleo da CPU por padrão).
  • PySpark (Processamento Distribuído)

    • Ambiente: Funciona em um cluster de computadores interligados em rede.
    • Escalabilidade: Divide os dados e as tarefas em múltiplos nós (computadores/servidores). Um nó principal (Driver) coordena o trabalho que é processado em paralelo pelos nós de execução (Workers).
    • Fluxo: Processamento massivo e distribuído na memória de várias máquinas simultaneamente.

    Como configurar o ambiente PySpark

A configuração do PySpark tem três pré-requisitos principais:

  1. Java (JDK/JRE): O Spark roda sobre a JVM (Java Virtual Machine). Você precisa do Java 8, 11 ou 17. No notebook do projeto, eu usei o JRE 8 por uma questão de compatibilidade no Windows (JDK 17 apresentou erro IllegalAccessError por causa do sistema de módulos).

  2. PySpark: Instale via pip:

pip install pyspark
  1. Variáveis de ambiente: É aqui que muita gente tropeça. Você precisa configurar:

    • JAVA_HOME: caminho da instalação do Java
    • SPARK_HOME: caminho da instalação do PySpark (geralmente dentro do site-packages)
    • PYSPARK_PYTHON: caminho do executável Python que o Spark vai usar

No notebook, fiz isso logo nas primeiras linhas:

Python
import os
os.environ['JAVA_HOME'] = r'C:\Program Files\Java\jre1.8.0_503'
os.environ['PATH'] = os.path.join(os.environ['JAVA_HOME'], 'bin') + ';' + os.environ['PATH']
os.environ['SPARK_HOME'] = r'...\Lib\site-packages\pyspark'
os.environ['PYSPARK_PYTHON'] = r'...\python.exe'

Dica: No Windows, evite instalar o projeto em caminhos com caracteres acentuados ou espaços. O launcher do Spark pode falhar ao montar o classpath do Java. Eu contornei isso usando caminhos curtos do Windows (ex.: RULISO~1 em vez de Réulison Silva).

Versão do Spark
Versão do Spark

O projeto: análise de atendimento hospitalar

Visão geral

O projeto atendimento-hospitalar-pyspark é uma análise exploratória de dados (EDA) de atendimentos hospitalares, com foco em tempo de espera e dimensionamento de equipe médica. Ele reproduz, usando PySpark, uma análise que originalmente seria feita em pandas puro.

O dataset principal vem do Kaggle: Hospital Patient Data, com cerca de 30 mil registros de atendimentos contendo informações como receitas, custos, tipo de médico, classe financeira do paciente e — o mais importante — os horários de entrada, pós-consulta e conclusão do atendimento.

As perguntas que o projeto responde

O notebook estrutura a análise em torno de perguntas de negócio bem concretas:

  • O tipo de paciente afeta o tempo de espera? Existe algum tipo específico de paciente que espera muito mais?
  • Estamos muito ocupados? Em quais horários e dias da semana o hospital está mais cheio?
  • Quanto tempo os pacientes esperam antes de serem atendidos pelo médico?
  • Que tipo de equipe precisamos e onde precisamos dela?
  • Como podemos resolver o problema de espera?
Fluxo de Análise e Perguntas de Negócio
Fluxo de Análise e Perguntas de Negócio

Estrutura do código: passo a passo

Ingestão de dados

O download do dataset é feito via kagglehub:

import kagglehub
path = kagglehub.dataset_download('abdulqaderasiirii/hospital-patient-data')

Depois, os dados são carregados com pandas e convertidos para um DataFrame PySpark. Essa ponte pandas → PySpark é comum quando o dataset não é gigante, mas você quer aproveitar a API do Spark para as transformações.

Criação da SparkSession

A SparkSession é o ponto de entrada para programar com Spark usando a API de DataFrame e Dataset. Com ela, você pode criar DataFrames, registrar tabelas, executar SQL, cachear tabelas e ler arquivos Parquet.

Python
spark = SparkSession.builder \
    .master("local") \
    .appName("atendimento-hospitalar") \
    .config("spark.sql.shuffle.partitions", "2") \
    .config("spark.driver.memory", "1g") \
    .getOrCreate()

Vamos detalhar cada parte:

  • .master("local"): Define que o Spark vai rodar em modo local (single-node). Em produção, você usaria yarn (Hadoop) ou spark://... (cluster standalone).
  • .appName("atendimento-hospitalar"): Nome da aplicação, aparece na UI do Spark.
  • .config("spark.sql.shuffle.partitions", "2"): Define o número de partições após operações de shuffle (como groupBy). O padrão é 200; reduzir para 2 faz sentido em ambiente local com dados pequenos.
  • .config("spark.driver.memory", "1g"): Memória alocada para o driver (o processo que coordena o trabalho).
  • .getOrCreate(): Cria uma nova sessão ou retorna uma existente.
Alocação de Parâmetros na Arquitetura
Alocação de Parâmetros na Arquitetura
Exploração inicial

O primeiro contato com os dados envolve métodos básicos mas essenciais:

df_wt.printSchema()          # Mostra a estrutura (schema) do DataFrame
n_linhas = df_wt.count()     # Conta o número de linhas
n_colunas = len(df_wt.columns)  # Conta o número de colunas

O printSchema() revelou que o dataset tem 11 colunas, incluindo date (timestamp), receitas e custos (double), tipos de médico e paciente (string), e os três horários-chave (string, no formato HH:mm:ss).

Limpeza e verificação de duplicatas
duplicadas = n_linhas - df_wt.dropDuplicates().count()

O dropDuplicates() remove linhas idênticas, e a diferença entre a contagem original e a nova revela quantas duplicatas existiam. Neste caso: 0 duplicatas — um dataset limpo.

df_wt.select([F.count(F.when(F.isnan(c) | F.col(c).isNull(), c)).alias(c) for c in df_wt.columns]).show()

Essa expressão usa uma list comprehension para iterar sobre todas as colunas e contar valores nulos (isNull()) ou NaN (isnan()). O resultado mostrou que as colunas de horário (entry_time, post_consultation_time, completion_time) e patient_id têm 13 valores nulos cada — provavelmente registros incompletos.

Valores distintos por coluna
df_wt.select([F.approx_count_distinct(c).alias(c) for c in df_wt.columns]).show()

O approx_count_distinct() é uma função de agregação que estima o número de valores distintos de forma muito mais rápida que o countDistinct() exato — usando o algoritmo HyperLogLog. Em datasets grandes, essa diferença de performance é brutal.

O HyperLogLog é um algoritmo probabilístico usado para estimar o número de elementos únicos (a cardinalidade) em um conjunto de dados muito grande, consumindo uma quantidade mínima de memória.

Renomeando colunas
df_wt = df_wt \
    .withColumnRenamed("Date", "date") \
    .withColumnRenamed("Medication Revenue", "medication_revenue") \
    ...

O withColumnRenamed() é encadeado para converter os nomes originais (com espaços e maiúsculas) para o padrão snake_case, típico de Python. Isso facilita a referência às colunas no código.

Criando métricas de tempo

Aqui está a parte mais interessante. O notebook calcula o tempo de espera e outros períodos a partir dos horários de entrada, pós-consulta e conclusão:

Python
entry_time_sec = F.unix_timestamp("entry_time", "HH:mm:ss")
post_consult_sec = F.unix_timestamp("post_consultation_time", "HH:mm:ss")
completion_sec = F.unix_timestamp("completion_time", "HH:mm:ss")

O unix_timestamp() converte strings de horário em segundos desde 1970-01-01. Isso permite fazer aritmética de tempo diretamente.

Python
def _segundos_apos(inicio, fim):
    diferenca = fim - inicio
    return F.when(diferenca < 0, diferenca + 24 * 3600).otherwise(diferenca)

Essa função trata o caso em que o horário final é "menor" que o inicial — o que acontece quando o atendimento atravessa a meia-noite. A solução é somar 24 horas (86.400 segundos) à diferença.

Python
df_wt = (
    df_wt
    .withColumn("waiting_ber_munets", F.round(_segundos_apos(entry_time_sec, completion_sec) / 60))
    .withColumn("consultation_period", F.round(_segundos_apos(entry_time_sec, post_consult_sec) / 60, 2))
    .withColumn("process_period", F.round(_segundos_apos(post_consult_sec, completion_sec) / 60, 2))
    .withColumn("weekday", weekday_map[F.date_format("date", "EEEE")])
    .withColumn("hours", F.hour(F.to_timestamp("entry_time", "HH:mm:ss")))
    .withColumn("consultation_perc", F.round(F.col("consultation_period") / F.col("waiting_ber_munets"), 2))
    .withColumn("process_perc", F.round(1 - F.col("consultation_perc"), 2))
)

Vamos destrinchar:

  • waiting_ber_munets: tempo total de espera (entrada até conclusão), em minutos. O nome tem um erro de digitação ("ber_munets" em vez de "waiting_minutes"), mas isso não afeta a lógica.
  • consultation_period: tempo da entrada até o fim da consulta (pós-consulta), em minutos.
  • process_period: tempo do fim da consulta até a conclusão (processamento administrativo), em minutos.
  • weekday: dia da semana em português. O notebook usa um create_map para traduzir de inglês para português.
  • hours: hora do dia em que o paciente entrou (0-23).
  • consultation_perc: proporção do tempo total gasta em consulta.
  • process_perc: proporção gasta em processamento.
Relação das Métricas na Linha do Tempo
Relação das Métricas na Linha do Tempo
Agrupamentos e análises

A partir daqui, o notebook usa groupBy para responder às perguntas de negócio:

Python
df_wt.groupBy("date").count().orderBy("date").show()
df_wt.groupBy("doctor_type").count().orderBy(F.desc("count")).show()
df_wt.groupBy("financial_class").count().orderBy(F.desc("count")).show()

O groupBy() agrupa linhas por um ou mais valores, e o count() conta quantas linhas há em cada grupo. O orderBy() ordena o resultado — com F.desc() para ordem decrescente.

Os resultados revelaram, por exemplo, que:

  • O dia 11/11/2019 teve o maior número de atendimentos: 3.617
  • Médicos do tipo ANCHOR (efetivos) realizaram 21.913 atendimentos, contra 6.789 dos LOCUM (temporários) e 1.296 dos FLOATING (que variam como efetivos e temporários)
  • A classe financeira mais comum é INSURANCE (convênio), com 9.931 atendimentos
Filtros com condições
Python
df.where(
    consultation_revenue.isNotNull() & ~F.isnan(consultation_revenue) &
    lab_cost.isNotNull() & ~F.isnan(lab_cost) &
    medication_revenue.isNotNull() & ~F.isnan(medication_revenue)
).orderBy(consultation_revenue.desc()).show(50)

O where() (equivalente a filter()) aplica condições para selecionar apenas as linhas que atendem a todos os critérios. As condições usam & (AND lógico) e ~ (NOT lógico). O resultado mostra os top 50 atendimentos por receita de consulta.

Machine Learning com RandomForestClassifier

O projeto também inclui uma etapa de Machine Learning usando RandomForestClassifier para identificar os fatores que mais influenciam as horas de "alta espera" e estimar quantos médicos adicionais seriam necessários para reduzir a espera em pelo menos 30%. O modelo é treinado com os dados do dataset do Kaggle combinados com uma escala de médicos (escala_medicos.csv) complementar.

Breve Resumo dos Insights obtidos
Breve Resumo dos Insights obtidos
  • Gargalo de Volume e Horário: Juntos, o Volume de Pacientes (33,1%) e a Hora do Dia (31,6%) acumulam quase 65% do peso de decisão do algoritmo para determinar janelas de alta espera. Isso valida estatisticamente a necessidade de dimensionar escalas dinâmicas de acordo com curvas de demanda horária. 
  • Ajuste Proposto: O cálculo complementar indica que o hospital opera em déficit em 68% das janelas observadas (140 de 206 horas analíticas), exigindo um reforço imediato de 22 médicos adicionais alocados estrategicamente nos momentos críticos para atingir a meta de redução de (30%) nas filas. 

Funções e métodos PySpark usados

A tabela abaixo consolida todas as funções e métodos PySpark utilizados no notebook, com uma descrição técnica e um exemplo de aplicação

Função / MétodoMódulo / ClasseDescriçãoExemplo no notebook
SparkSession.builderpyspark.sqlConstrutor para criar/configurar uma SparkSessionSparkSession.builder.master("local")
.master("local")SparkSession builderDefine o modo de execução (local, yarn, spark://).master("local")
.appName("...")SparkSession builderDefine o nome da aplicação.appName("atendimento-hospitalar")
.config(chave, valor)SparkSession builderDefine configurações da sessão.config("spark.sql.shuffle.partitions", "2")
.getOrCreate()SparkSession builderCria ou retorna a SparkSession existente.getOrCreate()
spark.versionSparkSessionRetorna a versão do Sparkprint(spark.version)
df.printSchema()DataFrameExibe a estrutura (schema) do DataFrame: colunas, tipos e nulabilidadedf_wt.printSchema()
df.count()DataFrameConta o número de linhasn_linhas = df_wt.count()
len(df.columns)DataFrame (atributo)Lista o nome das colunas; len() conta quantas sãolen(df_wt.columns)
df.dropDuplicates()DataFrameRemove linhas duplicadasdf_wt.dropDuplicates().count()
df.select()DataFrameSeleciona colunas ou expressõesdf_wt.select("patient_id", "weekday").show(5)
df.show(n)DataFrameExibe as primeiras n linhasdf_wt.show(2)
df.withColumnRenamed(antigo, novo)DataFrameRenomeia uma coluna.withColumnRenamed("Date", "date")
df.withColumn(nome, expressão)DataFrameCria ou substitui uma coluna.withColumn("weekday", weekday_map[...])
df.where(condição)DataFrameFiltra linhas por condiçãodf.where(F.col("lab_cost") > 100)
df.groupBy(colunas)DataFrameAgrupa por uma ou mais colunasdf_wt.groupBy("doctor_type")
df.orderBy(colunas)DataFrameOrdena o resultado.orderBy("date")
df.isNotNull()ColumnVerifica se o valor não é nuloF.col("x").isNotNull()
F.col(nome)pyspark.sql.functionsReferencia uma colunaF.col("Consultation Revenue")
F.isnan(coluna)functionsVerifica se o valor é NaN~F.isnan(consultation_revenue)
F.count(coluna)functionsConta valores não nulosF.count(F.when(...))
F.when(condição, valor)functionsExpressão condicional (tipo um "if" SQL)F.when(diferenca < 0, ...)
F.round(coluna, n)functionsArredonda para n casas decimaisF.round(valor / 60, 2)
F.desc(coluna)functionsOrdem decrescenteF.desc("count")
F.lit(valor)functionsCria uma coluna literalF.lit(x)
F.unix_timestamp(coluna, formato)functionsConverte string de data/hora em timestamp UnixF.unix_timestamp("entry_time", "HH:mm:ss")
F.to_timestamp(coluna, formato)functionsConverte string em timestampF.to_timestamp("entry_time", "HH:mm:ss")
F.hour(coluna)functionsExtrai a hora de um timestampF.hour(F.to_timestamp(...))
F.date_format(coluna, formato)functionsFormata data/hora como stringF.date_format("date", "EEEE")
F.create_map(pares)functionsCria um mapa (dicionário) como colunaF.create_map([F.lit(x) for pair in ...])
F.approx_count_distinct(coluna)functionsEstimativa rápida de valores distintosF.approx_count_distinct(c)
F.rand(seed)functionsGera número aleatório(usado na etapa de ML)

Aplicabilidade real: o que isso resolve?

Cenário atual: filas que custam caro

Voltemos aos dados. Um estudo da 2iM analisou quase 104 mil internações em sete hospitais de grande porte e identificou que o tempo de permanência hospitalar é o principal vetor de perda financeira: cada dia extra de internação impacta diretamente a rotatividade de leitos e a capacidade de geração de receita. Cerca de 30,69% das altas ocorreram fora do horário considerado adequado, gerando um impacto adicional estimado em R$ 474 milhões.

Distribuição do Impacto Financeiro Total
Distribuição do Impacto Financeiro Total
Detalhamento das Perdas Financeiras
  • Tempo de Permanência Excedente (69,31%): Representa o maior gargalo operacional do estudo, gerando um prejuízo estimado em R$ 1,07 bilhão decorrente da retenção indevida de leitos. 
  • Altas fora do Horário Adequado (30,69%): Corresponde a R$ 474 milhões em desperdícios operacionais causados pela falta de sincronia na liberação dos pacientes, atrasando novas admissões no mesmo dia.

Como o projeto se aplica na prática

Imagine que você é gestor de um hospital e recebe reclamações constantes sobre o tempo de espera. Com a abordagem do projeto, você poderia:

  1. Coletar dados de atendimento (horários de entrada, consulta e conclusão) do seu sistema de gestão.
  2. Carregar no PySpark — especialmente se o volume de dados for grande (milhões de registros ao longo de anos).
  3. Calcular os mesmos indicadores: tempo total de espera, período de consulta, período de processamento, distribuição por dia da semana e hora do dia.
  4. Identificar padrões: os horários de pico, os dias mais críticos, os tipos de paciente que mais esperam.
  5. Tomar decisões baseadas em dados: escalar mais médicos nos horários de pico, reorganizar o fluxo de processamento administrativo, criar filas preferenciais para determinados perfis.

O caso do boarding na emergência

Nos Estados Unidos, o boarding — quando um paciente já admitido fica "preso" na emergência esperando por um leito de internação — virou uma crise de saúde pública. Um estudo mostrou que o custo diário por paciente em boarding é de U1.856,quaseodobrodosU 1.856, quase o dobro dos U 993 para pacientes já internados.

E não para por aí: o mesmo estudo aponta que o boarding está associado a desvios de ambulância, erros médicos evitáveis, episódios de violência e burnout das equipes de cuidado.

Custo diário de internação hospitalar nos EUA
Custo diário de internação hospitalar nos EUA
Análise Comparativa do Impacto Financeiro
  • Gargalo na Emergência (Boarding): Manter um paciente estabilizado retido na emergência por falta de leito custa US$ 1.856 diários, onerando drasticamente o hospital devido ao consumo de recursos críticos do pronto-socorro.
  • Eficiência de Leito Regular: O fluxo normal de internação registra um custo operacional significativamente menor de US$ 993 diários, liberando espaço físico para que novos casos urgentes entrem nas salas de trauma e triagem sem interrupções.

Lições do notebook para o mundo real

O notebook do projeto, embora seja um estudo, demonstra uma metodologia que pode ser diretamente adaptada para ambientes de produção. A combinação de análise exploratória com PySpark e Machine Learning com RandomForest permite não só diagnosticar o problema, mas também simular cenários: "Se eu adicionar X médicos no horário Y, qual será a redução esperada no tempo de espera? Qual o impacto na receita?"

Essa é a diferença entre gerir por intuição e gerir por dados. E no setor hospitalar, onde cada minuto de espera pode significar vidas e milhões, essa diferença é crucial.

Contudo, não estou querendo dizer que se trata simplesmente de obter dados e aplicar na vida real. Gerir um hospital deve envolver centenas de outras variáveis que não capaz de incluir aqui, como o valor de plantão dos médicos e etc. Não é uma tarefa simples, mas o objetivo aqui é simplesmente o estudo do PySpark.

Conclusão

O projeto atendimento-hospitalar-pyspark é um excelente ponto de partida para quem quer aprender PySpark aplicado a dados reais de saúde. Ele cobre desde a configuração do ambiente (que, convenhamos, é a parte mais chata) até análise exploratória e Machine Learning.

Mais do que isso, ele nos lembra de uma verdade incômoda: as filas nos hospitais não são apenas um problema de saúde pública — são um problema de gestão de dados. O tempo de espera que o paciente sente na pele é o mesmo tempo que aparece como custo extra no balanço do hospital e como receita não realizada no final do mês.

Se você trabalha com dados na área da saúde — ou quer trabalhar — vale a pena clonar o repositório, rodar o notebook e explorar os dados por conta própria. O código está aberto, documentado e pronto para ser adaptado à sua realidade.

Referências

Fique ligado

Seja um Expert em Growth

Receba insights práticos sobre marketing, dados, performance e tecnologia direto no seu email.