-
Notifications
You must be signed in to change notification settings - Fork 16
lixo, gerando abrev 3 letras
CREATE SCHEMA IF NOT EXISTS abbrev;
CREATE FUNCTION abbrev.consoants(
p_x text, -- any input word
p_preserveFirst boolean DEFAULT true -- flag
) RETURNS text AS $f$
SELECT string_agg(x,'')
FROM regexp_split_to_table($1,'') WITH ORDINALITY t (x,a)
WHERE (p_preserveFirst AND a=1) OR x not IN ('A','E','I','O','U')
$f$ LANGUAGE SQL IMMUTABLE;
CREATE or replace FUNCTION abbrev.drop_prep_pt(
p_words text[] -- any input word
-- ,p_lang text DEFAULT 'pt' -- flag
) RETURNS text[] AS $f$
SELECT array_agg(replace(x,E'D\'',''))
FROM unnest($1) WITH ORDINALITY t(x,a)
WHERE a=1 OR x not IN ('E', 'DA', 'DE', 'DO', 'DAS', 'DOS')
$f$ LANGUAGE SQL IMMUTABLE;
----
CREATE or replace FUNCTION abbrev.letters3_by_rule_from_array(
p_list text[], -- the name spplited into array
p_rule text -- the rule to be used to obtain the 3-letter abbreviation
) RETURNS text AS $f$
SELECT substr(x,1,3)
FROM ( SELECT CASE -- 1=first word, 9=last word
WHEN $2='cut1' THEN array_to_string($1,'')
WHEN $2='init1_cutcons1' THEN abbrev.consoants( array_to_string($1,''), true )
WHEN $2='init1_cut2' and array_length($1,1)>1
THEN substr($1[1],1,1) || array_to_string($1[2:],'')
WHEN $2='inits12_init9' and array_length($1,1)>2
THEN substr($1[1],1,1) || substr($1[2],1,1) || substr($1[array_upper($1,1)],1,1)
WHEN $2='cut1last1' AND length($1[1])>2
THEN substr($1[1],1,2) || substr($1[1], length($1[1]), 1)
WHEN $2='cut9' AND length($1[1])>1 THEN $1[array_upper($1,1)]
WHEN $2='init1_cut9' AND length($1[1])>1
THEN substr($1[1],1,1) || $1[array_upper($1,1)]
WHEN $2='init9_cutcons' AND length($1[1])>1
THEN abbrev.consoants( $1[array_upper($1,1)], true )
WHEN $2='init1_cutcons9' AND length($1[1])>1
THEN substr($1[1],1,1) || abbrev.consoants( $1[array_upper($1,1)], true )
ELSE NULL
END
) t(x)
WHERE length(x)>2
$f$ LANGUAGE SQL IMMUTABLE;
CREATE or replace FUNCTION abbrev.apply_rules(
p_x text -- any city name. E.g. 'São José dos Campos' or 'Manaus'
) RETURNS jsonb AS $f$
SELECT jsonb_object_agg(val,rule)
FROM (
SELECT *, lag(val) OVER (order by val,rule) dupval
FROM regexp_split_to_array( upper(unaccent(trim(p_x))) , '[\s\.,;\-]+') t(x),
LATERAL ( VALUES
('r01', abbrev.letters3_by_rule_from_array(x,'cut1') )
,('r02', abbrev.letters3_by_rule_from_array(abbrev.drop_prep_pt(x),'inits12_init9') )
,('r03', abbrev.letters3_by_rule_from_array(abbrev.drop_prep_pt(x),'init1_cut2') )
,('r04', abbrev.letters3_by_rule_from_array(x,'init1_cutcons1') )
,('r15', abbrev.letters3_by_rule_from_array(x,'cut9') )
,('r16', abbrev.letters3_by_rule_from_array(x,'init9_cutcons') )
,('r17', abbrev.letters3_by_rule_from_array(x,'cut1last1') )
) t2(rule,val)
WHERE x IS NOT NULL AND val IS NOT NULL
) t3
WHERE dupval is null OR dupval!=val
$f$ LANGUAGE SQL IMMUTABLE;
-- falta score de qualidade das regras: os mais usados nas listagens tidas como de "boas siglas"
-- terão maior score.
Usando nas estatísticas das abreviações conhecidas:
-- full
SELECT count(*) n,
count(*) FILTER (WHERE candidatas?abbrev3) as n_bate,
count(*) FILTER (WHERE uf='SP') as n_sp,
count(*) FILTER (WHERE uf='SP' AND candidatas?abbrev3) as n_sp_bate
FROM (
SELECT name, uf, abbrev3, abbrev.apply_rules(name) as candidatas
FROM brcodes_city where abbrev3 is not null
) t;
-- not SP:
SELECT count(*) n,
count(*) FILTER (WHERE candidatas?abbrev3) as n_bate
FROM (
SELECT name, uf, abbrev3, abbrev.apply_rules(name) as candidatas
FROM brcodes_city where abbrev3 is not null AND uf!='SP'
) t ;
------ principal:
-- SP: (depois trocar por =! 'SP')
SELECT t2.rv, count(*) n, count(*) FILTER (WHERE t2.rk=t.abbrev3) n_bate
FROM (
SELECT name, uf, abbrev3, abbrev.apply_rules(name) as candidatas
FROM brcodes_city where abbrev3 is not null AND uf='SP'
) t, jsonb_each_text(candidatas) t2(rk,rv)
WHERE candidatas is not null AND candidatas!='{}'::jsonb
GROUP BY 1
ORDER BY 1
;
Resultado geral:
n | n_bate | n_sp | |
---|---|---|---|
Contagem | 4503 | 887 | 645 |
Percentual | 20% | 14% |
Percentuais relativos ao total de municípios em São Paulo (645).
regra | tem | tem_perc | bate | bate_perc | bate_percTot |
---|---|---|---|---|---|
r01 | 645 | 100% | 88 | 30% | 14% |
r02 | 53 | 8% | 32 | 11% | 5% |
r03 | 219 | 34% | 22 | 7% | 3% |
r04 | 566 | 88% | 153 | 52% | 24% |
(total) | 371 | 57% | 295 | 100% | 46% |
Como na análise subjetiva o conjunto foi considerado de "de qualidade", o valor de 46% do total fazendo uso das quatro regras, passa a ser um valor de referência para boa qualidade.
Conclui-se que as regras mais usadas são r4, r1, r2, r3 nesta ordem. O créscimo de mais uma ou duas regras seria suficiente para amostrar mais de 50% dos municípios.
PS: as médias são apenas indicativos do número de casos em que uma regra pode ser obtida (e sem colisão com regra anterior).
Além das regras de formação deve-se acrescentar regras de penalização, tais como "letra ausente no nome" ou "sequência fora de ordem".
total | bate | bate_percTot |
---|---|---|
3858 | 592 | 15,3% |
regra | tem | tem_perc | bate | bate_perc | bate_percTot |
---|---|---|---|---|---|
r01 | 3858 | 100% | 139 | 23% | 4% |
r02 | 432 | 11% | 82 | 14% | 2% |
r03 | 1707 | 44% | 100 | 17% | 3% |
r04 | 3447 | 89% | 271 | 46% | 7% |
total | 2361 | 61% | 592 | 100% | 15% |
O percentual do total de casos que batem é o principal indicador: mostra a baixa qualidade das siglas da Anatel.
O espectro de uso (bate_perc) é o mesmo que SP, sugerindo que esse perfil é independente da perda de qualidade por colisão.