sequencial · reposição mínima de probabilidade · Chromy (1979)
O método de Chromy seleciona as unidades uma a uma ao longo de uma lista
ordenada, cada qual com probabilidade proporcional ao seu tamanho, de modo
que uma unidade esperada 0,3 vezes é selecionada 0 ou 1 vez, uma esperada
2,4 vezes é selecionada 2 ou 3 — nunca mais longe — e o tamanho da amostra
é sempre exato. É assim que muitos grandes levantamentos sorteiam as suas
amostras, e é assim que funciona o PROC
SURVEYSELECT METHOD=PPS_SEQ. Até agora o método vivia dentro de
software proprietário e de um módulo de Stata.
chromy é o método em
código aberto: um motor em Rust, vinculado a R e a Python.
s <- chromy_sample(frame, n = 40, size = "pupils",
order_by = c("region", "chromy_size"), seed = 123)
sum(s$sample$hits) 40 # sempre: exato, não esperado
sum(s$expected_hits) 40
estimate_total(s, "outcome") total 37623, EP 5010 (CV 13,3%)
A mesma semente dá a mesma amostra, até o último sorteio — a aleatoriedade vem do gerador do próprio R, nunca de dentro do motor.
o método
Os hits esperados se acumulam ao longo da lista ordenada. Cada vez que a soma corrente cruza um inteiro, uma seleção é liberada; um único uniforme por unidade decide, condicionalmente à caminhada até ali, se a seleção pendente cai aqui ou segue adiante. Os condicionais são construídos para que os hits de cada unidade saiam exatamente com a probabilidade que a sua expectativa exige — uma implementação sequencial do desenho, não uma aproximação dele.
tamanho exato
Os hits somam n em toda realização. Não em média: sempre.
reposição mínima
Os hits são o piso ou o teto da expectativa — uma unidade pode ser selecionada mais de uma vez, mas nunca se afasta do que o desenho lhe prometeu.
estratificação implícita
Unidades vizinhas na lista são selecionadas afastadas, e a amostra se espalha sobre o que quer que as chaves de ordenação codifiquem.
as ferramentas
Um procedimento de seleção sozinho é metade de um desenho. Em volta dele, as peças que os levantamentos que dependem do método de Chromy de fato usam — cada uma é uma função do motor, cada uma testada contra a mesma referência.
ordenação serpentina
A ordenação hierárquica que inverte a direção em cada fronteira de grupo, de modo que a lista serpenteia pelo cadastro e as unidades vizinhas são sempre parecidas. Chaves categóricas ordenam por bytes, nunca pelo locale: o mesmo cadastro ordena igual em qualquer máquina.
medida de tamanho maximal
Para levantamentos que precisam estimar vários totais com uma só amostra: o tamanho de cada unidade é a maior das suas participações escalonadas entre as variáveis auxiliares (Folsom, Potter e Williams, 1987), e toda variável recebe ao menos a cobertura que pretendia.
alocação de CVs iguais
Os fatores que decidem quanta amostra cada variável comanda, buscados até que o total de toda variável seja antecipado com o mesmo coeficiente de variação — nenhuma estimativa sacrificada em silêncio a outra.
estimação por multiplicidade
O estimador que corresponde ao desenho — valores divididos pelos hits esperados efetivos, ponderados pelos hits recebidos — com a variância de diferenças sucessivas lida na ordem da lista, onde a serpentina deixou vizinhos genuinamente parecidos.
um motor, três linguagens
chromy-core não tem dependências
nem gerador: os uniformes chegam como argumentos, e uma seleção é uma função
pura das suas entradas. O R os sorteia com o gerador do próprio R — e é por
isso que set.seed() reproduz o
protótipo original sorteio a sorteio — e o Python os sorteia de uma semente
documentada. Três linguagens, uma aritmética, uma referência.
R · chromy
Data frames entram, tibbles saem; o desenho inteiro numa chamada; quatro vinhetas, da caminhada à validação.
Python · pychromy
Listas de colunas entram, dicts de listas paralelas saem — nada para instalar além da wheel; pandas opcional por construção.
Rust · chromy-core
O próprio motor, para um sistema de produção que sorteia as próprias amostras; slices entram, structs saem.
fidelidade
Hits esperados que deveriam somar um inteiro raramente somam em doubles, e um resto que cai em 1 − 10−16 é ou não é um cruzamento — a resposta muda quem pode ser selecionado. O motor mede o desvio com soma compensada, recusa-o além de 10−8 em vez de reescalar as probabilidades do chamador, atribui o que resta a uma única unidade e relata cada ajuste que fez. Os hits esperados efetivos que devolve são os denominadores pelos quais o estimador divide.
O ecossistema inteiro está fixado a uma única implementação de referência por fixtures-ouro: saídas inteiras exatas, ponto flutuante na precisão da máquina — e o pacote R vai além, reproduzindo a referência semente a semente.
s$accounting
$eps_sum -8.43e-15 # o desvio medido
$corrected_unit 512 # quem o absorveu
$adjusted_crossings 0
$max_adjustment 8.43e-15
# e uma recusa é uma recusa:
Error: the expected hits sum 3.2e-2 away from an
integer, beyond the 1e-8 tolerance; they do not
define a sample size
instalar
pak::pak(
"castlaboratory/chromy")
pip install pychromy
[dependencies]
chromy-core = "0.1"
O pacote R compila do código-fonte com uma toolchain Rust (≥ 1.77) até os binários do CRAN estarem no ar; o crate em si não tem dependência alguma.