Ele é um número entre 0 e 1, sendo 1 a desigualdade completa (uma única pessoa tem toda a riqueza) e 0 a igualdade total (todos ganham a mesma coisa). O número também é interpretado como a metade da diferença média normalizada. Ou seja, se a média é R$1.000 e o coeficiente de Gini for 0,6, então a diferença média entre rendas vai ser R$1.000*0,6*2=R$1.200. Ou seja, neste caso, a diferença média é maior que a média; esta seria uma sociedade bastante desigual. Países considerados avançados, como os da Escandinávia têm coeficientes entre 0,2 e 0,3. Países como Brasil, Uruguai, Estados Unidos e China, têm coeficientes entre 0,4 e 0,5. Atualmente, o país mais desigual do mundo é a Namíbia, com 0,707.
Na falta de dados sobre renda, usei uma lista de produtos. Mesmo assim, vou supor estar usando uma tabela PESSOAS com as seguintes colunas:
- ID - um identificador único para casa pessoa;
- SALARIO - o salário.
Usando a definição supracitada, escrevi o seguinte no Oracle:
select (diff/media)/2 from (
select avg(abs(p1.salario-p2.salario)) diff
from pessoas p1, pessoas p2
where p1.id<>p2.id
),(
select avg(salario) media
from pessoas
)
Temos dois cross-joins. O primeiro é terrível, porque multiplica todos os registros da tabela por ela mesma para calular as diferenças. Como eu tinha 14.354 registros, o cross-join resultante disso tinha 206.022.962 linhas. Nada bom. Se eu quisesse calcular o coeficiente de Gini do Brasil, teria que usar uma tabela de uns 190 milhões de registros e isso não ia funcionar. O segundo é inócuo, porque o último select produz apenas uma linha.
Por sorte, um economista chamado Angus Deanton encontrou uma maneira melhor de calcular isto. Na fórmula abaixo, N é o número total de indivíduos, u é a média dos rendimentos, X é o rendimento de cada um e P é a classificação de cada um (sendo 1 o mais rico e N o mais pobre).
Isso é muito mais eficiente, porque agora não é mais preciso comparar cada um a todos os demais.
A consulta resultante usa a função analítica ROW_NUMBER() para classificar os salários:
select ((n+1)/(n-1))-(2/(n*(n-1)*media))*sum(pc*salario) from (
select salario, row_number() over (order by salario desc) pc
from pessoas
), (
select avg(salario) media, count(1) n
from pessoas
) group by n, media
A tabela abaixo compara os resultados:
SELECT | Tempo | Resultado |
---|---|---|
1 | 67,94s | 0,55617007994480478319584630635542608397 |
2 | 0,03s | 0,5561700799448047831958463063554260839701 |
O segundo, além de ser 2.264 vezes mais rápido, ainda produziu mais duas casas de precisão que, por outro lado, não têm nenhuma utilidade.
Awesome! Que tal liberar o dataset (sanitizado) para comparacao?
ResponderExcluirEstive brincando c/ o MySQL e um dataset de umas 22K linhas. A primeira abordagem me tomou 121s, a segunda 0.06, mas com um hack para compensar a ausencia de ROW_NUMBER() no MySQL ...
[]s
~heckler
Interessante como a proporção entre os tempos manteve-se. Tem tanta coisa que pode variar, mesmo usando o mesmo banco.
ResponderExcluirPor outro lado, não entendo o que alguém tão inteligente esteja fazendo com MySQL. Postgresql tem Window Functions, que são sua versão das Analytic Functions do Oracle.
Tsk, tsk. No cookie for you.