← Blog
September 1, 2025

GPU geoespacial com RAPIDS CUSpatial: uniões espaciais e ponto no polígono

Grandes conjuntos de pontos contra grandes polígonos costumavam significar “volte amanhã”. Com o CuSpatial, você pode executar essas junções em minutos, se sua pilha estiver configurada corretamente. Este guia mostra um caminho limpo, além do código que você pode colar.

O que abordaremos

  • Escolhendo um Modelo pronto para CUDA (ou uma imagem do RAPIDS)
  • Obtendo CUDF/CU Spatial pronto sem barbear
  • Dois padrões principais: ponto no polígono e ponto no polígono em escala (com filtragem espacial)
  • Um pequeno autoavaliação arreios
  • Armadilhas de VRAM, E/S e projeção

Start in seconds with the fastest, most affordable cloud GPU clusters.

Launch an instance in under a minute. Enjoy flexible pricing, powerful hardware, and 24/7 support. Scale as you grow—no long-term commitment needed.

Try Compute now

1) Escolha sua imagem

Em locatários de GPU, seu trabalho funciona dentro de uma imagem. Duas boas opções:

A) Use uma imagem RAPIDS (mais rápida)

  • Registro (imagem): <24.xx>docker.io/rapidsai/rapidsai: -cuda12-runtime-ubuntu22.04-py3.10
  • Vars de ambiente:
    • NVIDIA_VISIBLE_DEVICES=Todos
    • nvidia_driver_capabilities=Computação, utilitário
  • CMD: mantenha seu script de inicialização ou um shell interativo.

B) Use um modelo CUDA e instale o RAPIDS com micromamba

# uma vez em uma nova instância
curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba
mkdir -p ~/micromamba &&. /bin/micromamba shell init -s bash -p ~/micromamba
fonte ~/.bashrc
micromamba create -y -n rapids -c rapidsai -c conda-forge rapids=24,* python=3,10
micromamba ativa corredeiras
python -c “importar cudf, cuspatial; imprimir (cudf. __version__, cuspatial. __versão__)”

Qualquer caminho te dá manguito + cuspatial com o espaço de usuário CUDA pronto. O driver do host geralmente é fornecido pelo seu provedor de serviços de computação.

2) Formatos de dados que funcionam bem

  • GeoParquet para pontos e polígonos. É colunar e amigável ao CuDF.
  • Shapefile funciona, mas prefiro converter para o GeoParquet uma vez.
  • CARROS: reprojete para uma métrica CRS (por exemplo, UTM) antes da matemática de distância/área. Mantenha tudo no mesmo CRS.

3) Point‑in‑Polygon (PIP): o padrão básico

Isso mostra a API na memória com um polígono de brinquedo. Troque dados reais posteriormente.

importar cudf
importar cupy como copo
importação causal

# Pontos (N x 2)
N = 1_000_000
pontos = cudf.DataFrame ({
“x”: cp.random.random (N),
“y”: cp.random.random (N),
})

# Um polígono quadrado (anel fechado)
poly_offsets = CUDF.series ([0], dtype="int32")
ring_offsets = CUDF.series ([0], dtype="int32")
poly_x = CUDF.series ([0, 1, 1, 0, 0], dtype="float64")
poly_y = CUDF.series ([0, 0, 1, 1, 0], dtype="float64")

máscara = cuspatial.point_in_polygon (
pontos ["x"], pontos ["y"],
poli_offsets, ring_offsets,
poli_x, poli_y,
)
# mask é um Bool DataFrame (linhas = pontos, colunas = polígonos)
dentro = pontos [mask.iloc [:, 0]]
imprimir (len (dentro))

Notas

  • Para vários polígonos, mascaram tem uma coluna por polígono. Uso .qualquer (eixo = 1) se você só se importa se um ponto caiu qualquer polígono.
  • Uso float64 para coordenadas poligonais, se seu domínio precisar; os pontos podem ser float32/64.

4) PIP em escala: filtre e teste

Cargas de trabalho reais usam milhares de polígonos e centenas de milhões de pontos. Teste menos candidatos filtrando primeiro com caixas delimitadoras e depois ligue ponto_em_polígono só nesses.

importar cudf, copiar como copo, cuspatial

# Suponha que pontos e polígonos já estejam carregados como cudf
# Exemplo de estrutura poligonal (vários pólipos, anéis):
# poly_offsets, ring_offsets, poly_points_x, poly_points_y

# 1) Construa caixas delimitadoras de polígonos (minx, maxx, miny, maxy)
caixas = cuspatial.polygon_bounding_boxes (
poli_offsets, ring_offsets, poli_x, poli_y
)
# caixas: DataFrame [min_x, min_y, max_x, max_y]

# 2) Filtro rápido de candidatos: pontos em qualquer caixa
segundo = (
(pontos.x >= caixas.min_x.min ()) & (pontos.x <= caixas.max_x.max ()) &
(pontos.y >= caixas.min_y.min ()) e (pontos.y <= boxes.max_y.max ())
)
pts_cand = pontos [cond]

# 3) Teste exato somente em candidatos
máscara = cuspatial.point_in_polygon (
pts_cand.x, pts_cand.y,
poli_offsets, ring_offsets, poli_x, poli_y
)
any_hit = mask.any (eixo = 1)
ingressou = pts_cand [any_hit]

Por que isso ajuda
A filtragem por caixa limite reduz o número de testes PIP caros. Para escalas extremas, veja os utilitários quadtree da CuSpatial para reduzir ainda mais os candidatos.

5) Lendo dados reais (GeoParquet)

importar cudf

pontos = cudf.read_parquet (“sensors_utm.parquet”) # cols: x, y, id
poly = cudf.read_parquet (“zones_utm.parquet”) # armazenado como anéis explodidos

# Crie matrizes poligonais esperadas pelo CuSpatial
poly_offsets = poli ["poly_offset"] .astype (“int32")
ring_offsets = poli ["ring_offset"] .astype (“int32")
poli_x = poli ["x"] .astype (“float64")
poli_y = poli ["y"] .astype (“float64")

Se seus polígonos estiverem em shapefiles, converta uma vez em GeoParquet (fora da GPU é bom) para acelerar carregamentos futuros.

6) Solicite tarefas maiores do que a GPU (opcional)

Para conjuntos de dados que não cabem em uma GPU, use o Dask para particionar o trabalho. Padrão:

  • Pontos de partição entre trabalhadores/GPUs.
  • Transmita polígonos (geralmente menores) para os trabalhadores.
  • Filtre candidatos por partição e, em seguida, PIP.

O código espelha a versão de GPU única, mas agrupa DataFrames cuDF no Dask CuDF.

7) Arnês de autoavaliação

Mantenha-o chato e comparável.

entradas: N_pontos, N_polígonos, vértices poligonais, CRS, precisão
hardware: modelo de GPU/VRAM, CUDA, driver
código: versão CuSpatial, caminho de código exato (com/sem filtro)
métricas: segundos para carregamento → filtro → PIP, pico de VRAM

Computar custo por milhão de pontos:

custo por milhão = (preço_por_hora × segundos_parede/3600)/(N_pontos/1e6)

8) Dicas de VRAM e desempenho

  • VRAM: fique de olho nvidia-smi. Se estiver quase cheia, fragmente a tabela de pontos.
  • CARROS: reprojete uma vez para uma métrica CRS antes das operações de distância/área; armazene isso no GeoParquet.
  • I/O: leia Parquet no NVMe local. Para buckets de nuvem, use grupos de linhas maiores e snappy/zstd.
  • Precisão: float32 é mais rápido e menor. Use float64 somente se a validação exigir isso.
  • Registro: cronometre cada estágio (carregamento, filtro, PIP) separadamente; isso ajuda você a ver os gargalos.

9) Solução de problemas

Erro CUDA/sem GPU
Verifique nvidia-smi dentro do contêiner. Certifique-se de que sua imagem esteja pronta para CUDA e defina as variáveis de ambiente da NVIDIA.

Erro de memória ou OOM
Separe a tabela de pontos; filtre cedo com bboxes; reduza o conjunto de colunas.

Resultados errados
CRS incompatível. Reprojete e teste novamente. Confirme a orientação do anel e os polígonos fechados.

Cargas lentas
Mova dados para o NVMe local; mude para o GeoParquet; aumente o tamanho do grupo de linhas do Parquet.

Trecho de métodos (copiar e colar)

hardware:
gpu: "<model>(<VRAM>GB)”
motorista: "<NVIDIA driver>”
<CUDA version>cuda: "”
software:
<24.xx>imagem: “rapidsai/rapidsai: -cuda12-runtime-ubuntu22.04-py3.10"
python: “3.10"
libs:
<version>- manguito: “”
<version>- cospacial: "”
entradas:
pontos: "s3://…/sensors_utm.parquet (N=<... >)”
polígonos: "s3://…/zones_utm.parquet (polys=<... >)”
executar:
script: "pip_join.py”
notas: “filtro bbox → PIP; CRS=EPSG:32633"
saídas:
wall_seconds: “<... >”
custo por milhão: “<... >”

Leitura relacionada

Experimente o Compute hoje

Inicie uma instância de GPU com um modelo pronto para CUDA (por exemplo, Ubuntu 24.04 LTS/CUDA 12.6) ou sua própria imagem GROMACS. Aproveite o faturamento flexível por segundo com modelos personalizados e a capacidade de iniciar, interromper e retomar suas sessões a qualquer momento. Não tem certeza sobre os requisitos do FP64? Entre em contato com o suporte para ajudá-lo a selecionar o perfil de hardware ideal para suas necessidades computacionais.