Pular para o conteúdo

Análise de dados

Carregar, limpar, agregar e descrever — o caminho de um conjunto de dados até a resposta.

Analisar dados é sempre a mesma sequência: carregar, conferir, limpar, agregar, responder. A linguagem traz as cinco etapas, e esta página é o caminho inteiro com um conjunto pequeno o bastante para caber na tela.

O quadro de dados#

Arcane.Analytics trabalha com um frame: um cluster de vaults, que é o que IO.read_csv(caminho, yes) devolve e o que Database.query devolve.

dataforge
adopt Arcane.Analytics as An

vendas := [
    {"produto": "cafe",   "regiao": "sul",   "valor": 120.0, "qtd": 4},
    {"produto": "cafe",   "regiao": "norte", "valor": 90.0,  "qtd": 3},
    {"produto": "cha",    "regiao": "sul",   "valor": 60.0,  "qtd": 2},
    {"produto": "cha",    "regiao": "norte", "valor": 45.0,  "qtd": 1},
    {"produto": "acucar", "regiao": "sul",   "valor": 30.0,  "qtd": 5}
]

out len(vendas), "registros"

1. Conferir antes de confiar#

A primeira coisa a fazer com um conjunto novo não é calcular — é olhar. Quantas linhas, quais colunas, o que está faltando:

dataforge
adopt Arcane.Analytics as An

action colunas_de(dados):
    yield keys(dados[0])

action faltando(dados, coluna):
    yield len([l cycle l in dados given (l[coluna] ?? void) is void])

out colunas_de(vendas)
out faltando(vendas, "valor"), "sem valor"

2. Limpar#

dataforge
action limpo(dados):
    yield [linha cycle linha in dados
           given (linha["valor"] ?? 0.0) > 0.0]

action com_total(dados):
    yield [linha with {"total": linha["valor"] * linha["qtd"]}
           cycle linha in dados]

Note que nada é mutado: cada etapa devolve um frame novo. É o que permite comparar o antes e o depois, e é o que faz um pipeline ser reexecutável.

3. Agregar#

dataforge
action somar_por(dados, chave, campo):
    totais := {}
    cycle linha in dados:
        grupo := linha[chave]
        totais[grupo] := (totais[grupo] ?? 0.0) + linha[campo]
    yield totais

out somar_por(vendas, "produto", "valor")
out somar_por(vendas, "regiao", "valor")
saída
{cafe: 210.0, cha: 105.0, acucar: 30.0}
{sul: 210.0, norte: 135.0}

O vault como acumulador é O(n): uma passada, e cada escrita é constante. A versão "óbvia" — para cada grupo, percorrer tudo filtrando — é O(n × grupos), e o `dataforge big-o` acusa.

4. Descrever#

dataforge
adopt Arcane.Analytics as An

valores := [v["valor"] cycle v in vendas]

out An.media(valores)
out An.mediana(valores)
out An.desvio_padrao(valores)
out min(valores), max(valores)

Média e mediana juntas dizem mais que qualquer uma sozinha. Quando as duas se afastam, há assimetria — um valor muito alto puxando a média —, e é o sinal de que a média não representa o conjunto.

5. Responder, e mostrar#

O resultado de uma análise termina de três formas, e cada uma tem o seu lugar:

Onde terminaCom o quê
no terminalout, ou o pacote `tabela`
num arquivoIO.write_csv, IO.write_json, `Arcane.Excel`
numa páginaVitrine — o mesmo .df vira painel com gráfico

Quando os dados não cabem na memória#

A regra prática: até alguns milhões de linhas, um cluster de vaults resolve. Acima disso, há três caminhos, e o primeiro costuma bastar:

  • Processar por partes, com stream actionO(1) de espaço, ver complexidade de espaço.
  • Deixar o banco agregarSUM e GROUP BY acontecem onde o dado já está, e volta só o resultado. Ver SQLite.
  • A ponte para o Pythonadopt Python.pandas as pd quando a conta é vetorizada e o volume justifica.
dataforge
adopt Python.numpy as np

a := np.array([1.0, 2.0, 3.0])
out (a * 2).tolist()        // a conta é do numpy, sem cópia na fronteira

Por onde seguir#