Interoperabilidade com Python/pandas
Mova tabelas entre Rust e Python com Apache Arrow - evite serialização JSON lenta e preserve dtypes.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
use polars::prelude::*;
use std::fs::File;
fn export_arrow_ipc(df: &mut DataFrame, path: &str) -> PolarsResult<()> {
let mut file = File::create(path)?;
IpcWriter::new(&mut file).finish(df)?;
Ok(())
}import pyarrow as pa
import pyarrow.ipc as ipc
with pa.memory_map("/tmp/frame.arrow", "r") as source:
table = ipc.open_file(source).read_all()
df = table.to_pandas()Quando usar isso:
- Núcleo ETL Rust com notebooks Python para exploração
- Servindo features construídas em Rust para downstream pandas/sklearn
- Validando saída do Polars no Jupyter sem viagem de ida e volta CSV
- Migração gradual de gargalos do pandas
Exemplo de Trabalho
O lado Rust escreve IPC; Python lê em pandas sem analisar CSV.
use polars::prelude::*;
fn main() -> PolarsResult<()> {
let mut df = df! {
"user_id" => [1i64, 2, 3],
"score" => [0.9, 0.4, 0.7],
}?;
let mut f = std::fs::File::create("/tmp/users.arrow")?;
IpcWriter::new(&mut f).finish(&mut df)?;
Ok(())
}import pandas as pd
import pyarrow.ipc as ipc
with open("/tmp/users.arrow", "rb") as f:
reader = ipc.open_file(f)
table = reader.read_all()
pdf = table.to_pandas(types_mapper=pd.ArrowDtype)
assert pdf["user_id"].dtype.name.startswith("int")O que isso demonstra:
IpcWriterdo Polars produzindo um arquivo que o Python entende- pandas lendo dtypes baseados em Arrow sem inferência de string
- Fidelidade de ida e volta em colunas numéricas
Mergulho Profundo
Como Funciona
- Arrow define um layout de memória canônico que ambos os ecossistemas decodificam.
- O formato de arquivo IPC incorpora o esquema + buffers de coluna para leituras amigáveis a mmap.
- PyO3 permite que funções Rust aceitem/retornem objetos
PyArrowno mesmo processo (sem arquivo IPC). - pandas 2.x prefere dtypes baseados em Arrow via
pd.ArrowDtypepara inteiros anuláveis.
Caminhos de Interoperabilidade
| Caminho | Cópias | Melhor para |
|---|---|---|
| Arquivo Arrow IPC | Mínimo com mmap | Troca de lotes entre trabalhos |
| PyO3 + pyarrow | No mesmo processo | Loops rápidos em Python chamando Rust |
| Parquet em disco | Custo de decodificação | Lago compartilhado durável entre equipes |
| CSV | Análise completa | Apenas para depuração |
Notas Rust
// Ao expor PyO3, use maturin para construir wheels:
// #[pyfunction] fn transform(py: Python, table: Bound<PyAny>) -> PyResult<PyObject> { ... }Armadilhas
- Intermediário JSON - 10x mais lento e perde semântica de inteiros anuláveis. Correção: padronizar em Arrow IPC ou Parquet.
- Discrepância de datetime sem fuso horário - pandas vs Polars interpretam offsets de forma diferente. Correção: armazene nanossegundos UTC em metadados do esquema.
- Derivação de dicionário categórico/string - junções falham entre linguagens. Correção: concorde com Utf8 vs categórico no registro de esquema.
- PyO3 limitado por GIL para trabalho de CPU longo - bloqueia outras threads Python. Correção: libere o GIL com
py.allow_threadsem torno da computação Rust. - Versões diferentes de Polars/pyarrow - erros de decodificação em novos tipos de extensão. Correção: fixe as versões em
Cargo.lockerequirements.txt.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Apenas lago Parquet | Lotes assíncronos entre equipes | Loops interativos de subsegundo em notebooks |
| gRPC + Arrow Flight | Streaming de serviço para serviço | Troca simples de CLI local |
| DuckDB em ambos | Contrato SQL sobre arquivos | Kernels Rust customizados pesados |
| Polars puro Python | Equipe permanece na API Python | Propriedade Rust do caminho crítico de desempenho |
FAQs
A troca sem cópia é garantida de Rust para Python?
Com mmap IPC e buffers compatíveis, muitas vezes sim. PyO3 no mesmo processo ainda pode copiar dependendo da propriedade do array - compare o desempenho do seu caminho.
O pandas pode escrever de volta para Rust?
Sim - escreva Arrow IPC ou Parquet do pandas via PyArrow, leia com scan_ipc / read_parquet do Polars.
Preciso de PyO3 para interoperação?
Não para pipelines de arquivos/lotes. PyO3 ajuda quando Python orquestra e Rust acelera loops apertados em um processo.
E os arrays NumPy?
Arrow faz a ponte com NumPy para colunas numéricas sem caixas de dtype de objeto - prefira a tabela Arrow como contrato.
Como distribuo extensões Rust?
Use maturin develop localmente e maturin build para wheels em CI - combine com um pyproject.toml apontando para seu crate.
Isso funciona em notebooks?
Sim - escreva IPC para /tmp, leia na próxima célula. Para dados grandes, mmap mantém a RAM estável.
Como depuro discrepâncias de esquema?
Imprima table.schema em ambos os lados antes das transformações. Falhe rapidamente em Rust com Schema explícito na escrita.
Posso usar polars Python em vez de pandas?
Polars Python compartilha o mesmo núcleo Rust - IPC entre Rust Polars e Python Polars é especialmente suave.
E os inteiros anuláveis?
Use Arrow int64 com bitmap nulo; evite o sentinela NaN float do pandas para IDs.
Onde o Apache Arrow se encaixa?
Veja Apache Arrow para os fundamentos do RecordBatch que sustentam essa troca.
Relacionados
- Apache Arrow - contrato colunar
- Polars - exportação de DataFrame Rust
- I/O CSV/Parquet - Parquet como troca alternativa
- Construindo CLIs e Serviços de Dados - binários produtores Rust
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.