Cokrigagem
O CoKriging estima uma variável primária com a ajuda de uma ou mais
variáveis secundárias relacionadas. Por exemplo, você pode combinar amostras
esparsas de produtividade com NDVI, altitude ou condutividade elétrica (CE) do
solo. O fluxo tem três etapas: selecionar as variáveis candidatas, ajustar e
interpolar com as que passarem e fazer a validação cruzada para conferir se a
cokrigagem de fato melhora o resultado.
A cokrigagem é um fluxo avançado. Hoje ela não faz parte da seleção padrão do
apbase.Map. Use-a quando tiver variáveis secundárias relevantes e quiser
testar se elas reduzem o erro.
from apbase.cross_variogram import screen_secondary_variables
from apbase.cokriging import CoKriging
from apbase.cross_validate import cross_validate_cokriging, select_best_model
# 1. Seleção das candidatas: ficam só as que passam nos dois testes
screened = screen_secondary_variables(
x0, y0, z0,
{"ndvi": (xn, yn, zn), "ec": (xe, ye, ze)},
max_colocation_dist=30.0, # pareia amostras a até 30 unidades de distância
)
screened.report # rho, p_value, n_pairs, decision, status, ... de cada candidata
secondaries = screened.selected # ex.: {"ndvi": (xn, yn, zn)}
# 2. Ajuste e interpolação
ck = CoKriging(method="icm", max_neighbors=40, min_neighbors=3, max_colocation_dist=30.0)
ck.fit(x0, y0, z0, secondaries)
z_targets = ck.interpolate(targets) # targets: array (n, 2)
# 3. Confirma pela LOO-CV que ela supera a krigagem sem variáveis secundárias
cv = cross_validate_cokriging(x0, y0, z0, secondaries, max_colocation_dist=30.0)
best = select_best_model(cv.by_method)
best.method, best.significant
use apbase::cokriging::{CoKriging, CoKrigingMethod, CoKrigingOptions, SecondaryInput};
use apbase::cross_validate::{
CrossValidateCokrigingOptions, SelectBestModelOptions, cross_validate_cokriging, select_best_model,
};
use apbase::cross_variogram::{ScreeningOptions, screen_secondary_variables};
use indexmap::IndexMap;
// 1. Seleção das candidatas: ficam só as que passam nos dois testes
let candidates = IndexMap::from([
("ndvi".to_string(), (xn.clone(), yn.clone(), zn.clone())),
("ec".to_string(), (xe.clone(), ye.clone(), ze.clone())),
]);
let screened = screen_secondary_variables(
&x0, &y0, &z0,
&candidates,
ScreeningOptions { max_colocation_dist: Some(30.0), ..Default::default() }, // pareia amostras a até 30 unidades de distância
)?;
screened.report; // rho, p_value, n_pairs, decision, status, ... de cada candidata
let secondaries = SecondaryInput::from(screened.selected); // ex.: {"ndvi": (xn, yn, zn)}
// 2. Ajuste e interpolação
let mut ck = CoKriging::new(CoKrigingOptions {
method: CoKrigingMethod::Icm,
max_neighbors: 40,
min_neighbors: 3,
max_colocation_dist: Some(30.0),
..Default::default()
})?;
ck.fit(&x0, &y0, &z0, &secondaries)?;
let z_targets = ck.interpolate(&targets)?; // targets: array (n, 2)
// 3. Confirma pela LOO-CV que ela supera a krigagem sem variáveis secundárias
let cv = cross_validate_cokriging(
&x0, &y0, &z0,
&secondaries,
CrossValidateCokrigingOptions { max_colocation_dist: Some(30.0), ..Default::default() },
)?;
let best = select_best_model(&cv.by_method, SelectBestModelOptions::default())?;
(best.method, best.significant);
Não pule a primeira etapa. Passar uma variável secundária sem relação direto
para o CoKriging pode não gerar erro, mas pode piorar a estimativa.
Defina max_colocation_dist quando as variáveis secundárias forem amostradas
nos seus próprios locais, como costumam ser as superfícies de NDVI ou de CE. A
seleção compara valores primários e secundários em pares e, com o padrão
None, um par só se forma onde as coordenadas são idênticas. Sem esse
parâmetro, nenhum par se forma e toda candidata é rejeitada com o status
"insufficient sample". Use uma distância da ordem do espaçamento de
amostragem da variável secundária. O CoKriging e o cross_validate_cokriging
pareiam as amostras do mesmo jeito para estimar as covariâncias cruzadas, então
passe a mesma distância para eles; sem pares, eles geram um ValueError.
Entradas principais
x0, y0 : array_like
: Coordenadas dos pontos amostrais da variável primária.
z0 : array_like
: Valores da variável primária. Precisa ter o mesmo tamanho de x0 e y0.
candidates : dict[str, tuple[array_like, array_like, array_like]]
: Variáveis secundárias candidatas passadas a screen_secondary_variables,
por exemplo {"ndvi": (xn, yn, zn)}.
secondaries : dict ou list
: Variáveis secundárias selecionadas, passadas a CoKriging.fit e
cross_validate_cokriging. screened.selected já vem no formato certo.
targets : array_like ou Grid
: Coordenadas dos pontos a estimar passadas a CoKriging.interpolate.
Etapa 1: seleção
screen_secondary_variables verifica se cada candidata tem correlação
relevante com a variável primária (teste de Fisher) e um semivariograma
cruzado admissível (verificação de Cauchy–Schwarz). Só as candidatas que
passam nas duas verificações são mantidas. Veja
Seleção de variáveis secundárias para a estatística.
Parâmetros da seleção
alpha : float, padrão 0.05
: Nível de significância do teste de Fisher.
correction : {"bonferroni", "none"}, padrão "bonferroni"
: Correção para testes múltiplos usada quando há várias candidatas.
min_abs_rho : float, padrão 0.3
: Correlação prática mínima. Uma candidata estatisticamente significativa,
mas fraca, continua sendo rejeitada.
max_violation_fraction : float, padrão 0.1
: Fração máxima dos lags avaliados que pode violar o limite de
admissibilidade do semivariograma cruzado.
max_colocation_dist : float, opcional
: Distância máxima usada para parear amostras primárias e secundárias. None
pareia só coordenadas idênticas (veja acima).
screened = screen_secondary_variables(
x0, y0, z0,
{"ndvi": (xn, yn, zn), "ec": (xe, ye, ze), "random_noise": (xr, yr, zr)},
alpha=0.05,
min_abs_rho=0.3,
max_colocation_dist=30.0,
)
let candidates = IndexMap::from([
("ndvi".to_string(), (xn, yn, zn)),
("ec".to_string(), (xe, ye, ze)),
("random_noise".to_string(), (xr, yr, zr)),
]);
let screened = screen_secondary_variables(
&x0, &y0, &z0,
&candidates,
ScreeningOptions {
alpha: 0.05,
min_abs_rho: 0.3,
max_colocation_dist: Some(30.0),
..Default::default()
},
)?;
screened.selected já tem o formato esperado por CoKriging.fit, então passe
direto como secondaries (em Rust, SecondaryInput::from(screened.selected)).
screened.report inclui todas as candidatas, inclusive as rejeitadas: cada
CovariateReport traz rho, p_value, n_pairs, admissible_fraction,
decision, status e os model_params ajustados. É útil quando você precisa
registrar por que uma variável foi descartada.
Etapa 2: ajuste e interpolação
ck = CoKriging(
method="icm", radius=None, max_neighbors=40, min_neighbors=3, max_colocation_dist=30.0
)
ck.fit(x0, y0, z0, secondaries)
estimates = ck.interpolate(targets)
let mut ck = CoKriging::new(CoKrigingOptions {
method: CoKrigingMethod::Icm,
radius: None,
max_neighbors: 40,
min_neighbors: 3,
max_colocation_dist: Some(30.0),
..Default::default()
})?;
ck.fit(&x0, &y0, &z0, &secondaries)?;
let estimates = ck.interpolate(&targets)?;
Parâmetros do ajuste
method : {"collocated", "icm", "lmc"}, padrão "collocated"
: Modelo de cokrigagem. O padrão "collocated" é o mais barato, mas tem os
dois requisitos descritos abaixo. Quando eles não são atendidos, use
"icm": ele não tem nenhum dos dois nem formas por estrutura para ajustar.
radius : float, opcional
: Raio de busca local. Se for omitido, o APbase o deriva do semivariograma da
variável primária.
max_neighbors, min_neighbors : int
: Limites de vizinhos da primária. Para "icm" e "lmc", cada variável
secundária busca os próprios vizinhos dentro de radius, até
max_secondary_neighbors.
n_structures : int, padrão 2
: Número de estruturas aninhadas do LMC. Usado só por "lmc".
model_values : array_like, opcional
: Valores de modelo pré-calculados. Só "collocated" aceita.
max_colocation_dist : float, opcional
: Distância dentro da qual uma amostra da primária é pareada com o ponto mais
próximo da variável secundária para estimar as covariâncias cruzadas. None
pareia só coordenadas idênticas; variáveis secundárias heterotópicas, como
rasters, precisam de uma distância (por exemplo, metade da diagonal da
célula).
max_secondary_neighbors : int, opcional
: Número máximo de vizinhos de cada variável secundária por ponto a estimar,
só para "icm" e "lmc". None usa max_neighbors. Variáveis secundárias
densas precisam de bem menos vizinhos que a primária, já que as mais próximas
encobrem as demais.
ck.model_params mostra os parâmetros ajustados de forma legível (a estrutura
muda conforme o método; veja a docstring da classe); ck.model_values dá o
vetor nativo achatado, que pode ser passado de volta como model_values para
reaproveitar um ajuste colocalizado. Em Rust, os dois são getters:
ck.model_params()? devolve um enum CoKrigingModelParams com uma variante
por método, e ck.model_values()?, o vetor.
A cokrigagem colocalizada precisa do valor secundário em todos os pontos a estimar da interpolação, não só nos seus pontos amostrais (veja a docstring da classe). Se for preciso, interpole antes uma variável secundária esparsa numa grade densa o suficiente. Ela também depende da hipótese do Modelo de Markov 1 (MM1): assume-se que o valor secundário no ponto a estimar torna redundantes os dados secundários mais distantes (veja Cokrigagem). ICM e LMC não têm nenhum desses dois requisitos.
Todos os métodos estimam as covariâncias cruzadas a partir de amostras da
primária pareadas com pontos da variável secundária: nas mesmas coordenadas
ou, com max_colocation_dist, o ponto secundário mais próximo dentro dessa
distância. Se uma secundária tiver poucos pares, o fit gera um ValueError
com o nome dela; para dados heterotópicos, como um raster, defina
max_colocation_dist.
Etapa 3: validação cruzada
Ajustar a cokrigagem é só parte do trabalho. A validação cruzada mostra se ela de fato supera a krigagem sem variáveis secundárias neste conjunto de dados.
Parâmetros da validação cruzada
max_points : int, padrão 500
: Número máximo de amostras primárias avaliadas na validação leave-one-out.
seed : int, opcional
: Semente usada quando a validação sorteia um subconjunto dos pontos
primários.
radius, max_neighbors, min_neighbors, n_structures, max_colocation_dist, max_secondary_neighbors
: Mesmo significado que no CoKriging.
from apbase.cross_validate import cross_validate_cokriging, select_best_model
cv = cross_validate_cokriging(
x0, y0, z0, secondaries, max_neighbors=40, min_neighbors=3, max_colocation_dist=30.0
)
{name: result.rmse for name, result in cv.by_method.items()}
best = select_best_model(cv.by_method)
best.method # ex.: "icm"
best.significant # True se a vantagem sobre o segundo colocado dificilmente é acaso
use apbase::cross_validate::{
CrossValidateCokrigingOptions, SelectBestModelOptions, cross_validate_cokriging, select_best_model,
};
let cv = cross_validate_cokriging(
&x0, &y0, &z0,
&secondaries,
CrossValidateCokrigingOptions {
max_neighbors: 40,
min_neighbors: 3,
max_colocation_dist: Some(30.0),
..Default::default()
},
)?;
for (name, result) in &cv.by_method {
println!("{name}: {}", result.rmse);
}
let best = select_best_model(&cv.by_method, SelectBestModelOptions::default())?;
best.method; // ex.: "icm"
best.significant; // true se a vantagem sobre o segundo colocado dificilmente é acaso
cross_validate_cokriging roda o leave-one-out sobre a variável primária para
os três métodos numa única passada. Um método cujo modelo não pode ser
ajustado fica de fora de cv.by_method em vez de interromper a execução;
Validação cruzada explica o que é retirado e quando um
método é descartado.
Isso mostra qual método de cokrigagem é o melhor, não se acrescentar variáveis
secundárias ajudou. Para conferir isso, compare cv.by_method[...] com as
métricas de result.kriging de uma execução simples de
apbase.cross_validate.cross_validate(x0, y0, z0).