library(tidyverse)
library(ggbeeswarm)
library(hrbrthemes)
theme_set(theme_ipsum())
# theme_set(theme_bw())
Para comparar valores, nós normalmente pensamos em termos de alguma diferença entre eles. Uma distância.
Por exemplo, podemos entender que 10 está a 5 unidades de distância de 5. Ou que 10 é 2x maior que 5. No primeiro caso, estamos usando a subtração (ou adição necessária) como distância. No segundo, uma razão (ou multiplicação necessária).
A maior parte das comparações que encontramos rotineiramente usa escalas baseadas em adição.
Segundo uma escala desse tipo, a distância entre 10 e 20 é a mesma distância que entre 100 e 110 e entre 100.000.000 e 100.000.010.
Diferentes formatos de dados geram os seguintes formatos em uma escala linear. Para alguns formatos, ela facilitará as comparações que queremos fazer. Para outros, dificultará.
Para ilustrar, usaremos dados sobre nomes e população dos municípios em cada UF do Brasil.
municipios = read_csv("../dados/populacao-municipios-2010.csv", col_types = "ccd")
municipios = municipios %>%
mutate(comprimento_nome = str_length(municipio))
pb = municipios %>% filter(uf == "PB")
por_estado = municipios %>%
filter(!is.na(populacao2010), uf != "DF") %>%
group_by(uf) %>%
summarise(santos_100_municipios = 100 * sum(grepl("São|Santo|Santa", municipio))/n(),
maior_populacao = max(populacao2010))
por_estado
Quantos municípios têm nome de santo ou santa em cada UF?
por_estado %>%
ggplot(aes(x = reorder(uf, santos_100_municipios), y = santos_100_municipios)) +
geom_point(color = "#EF8A17") +
geom_rug(alpha = .7, color = "#EF2917", sides = "l") +
labs(
title = "Nomes de santo",
subtitle = "Número de municípios com nome de santo para cada 100 municípios",
x = "UF",
y = "Nomes de santo / 100 municípios"
)
A distribuição é simétrica e sem valores extremos. Nenhum estado tem uma preferência muito distoante dos demais:
por_estado %>%
ggplot(aes(x = santos_100_municipios)) +
geom_histogram(bins = 8, color = "#EF8A17", fill = "white") +
labs(
y = "Quantidade",
x = "Proporção"
)
Com essa distribuição, é fácil comparar todos. As distâncias são normalmente parecidas entre quaisquer dois vizinhos nos dados.
por_estado %>%
ggplot(aes(x = reorder(uf, maior_populacao), y = maior_populacao / 1e6)) +
geom_point(color = "#33658A") +
geom_rug(alpha = .7,
color = "#2F4858",
sides = "l") +
labs(
title = "Maior município por UF",
subtitle = "Tamanho em população em 2010",
x = "UF",
y = "População do maior município (Milhões)"
)
A distribuição aqui não apenas é assimétrica, mas ela tem uma cauda bem longa à direita.
Veja que as distâncias entre vizinhos inclusive vão aumentando na medida que os valores são maiores.
por_estado %>%
ggplot(aes(x = maior_populacao/ 1e6)) +
geom_histogram(binwidth = .5, boundary = 0, color = "#034732", fill = "white") +
labs(
y = "Quantidade",
x = "População (milhões)"
)
A mesma distribuição acontece para todos os municípios brasileiros, inclusive:
municipios %>%
filter(!is.na(populacao2010)) %>%
ggplot(aes(x = populacao2010/ 1e6)) +
geom_histogram(binwidth = .1, boundary = 0, fill = "white", color = "dark orange") +
geom_rug(size = .3, alpha = .6, color = "red") +
labs(
y = "Quantidade",
x = "População (milhões)"
)
Nesse tipo de situação, usar uma escala linear dificulta que façamos comparações tanto nos valores menores quanto nos valores maiores do domínio da variável.
E há uma forma intuitiva de pensar que diferenças são diferentes em regiões distintas. Por exemplo: a diferença entre uma cidade de 10 mil habitatantes e outra de 100 mil é bastante grande proporcionalmente, enquanto a diferença de uma cidade de 10 milhões de habitantes para outra de 10 milhões e 90 mil habitantes é pequena.
Só que isso que se isso é verdade, não estamos usando uma escala linear para comparar. Na escala linear a distância entre 100.000 e 90.000 é a mesma que entre 10.090.000 e 10.000.000.
A escala logarítmica, ou de log, é uma que considera que toda multiplicação por um mesmo número causa uma diferença de mesmo tamanho. Não é uma subtração. O número pelo qual multiplicamos nós escolhemos, e ele se chama a base.
Por exemplo, numa escala logarítmica de base 10, a distância de 1 para 10 é igual à de 10 para 100, e à de 100 para 1000. Aumentar uma ordem de magnitude causa uma diferença de mesmo tamanho, independente da magnitude.
Da mesma maneira, numa escala logarítmica, a distância de de 100 para 110 é menor que a distância de 10 para 20. Na segunda 20 é 2x o valor de 10, enquanto na primeira 110 é 1,1x o valor de 100.
Usando um exemplo sintético, dá para deixar mais claro. Aqui, um exemplo com duas distribuições. Numa as diferenças são sempre 100 entre os elementos ordenados Na outra, um elemento é o dobro do imediatamente menor - as distâncias entre vizinhos crescem com o valor da variável.
exemplo = tibble(
x = c(1:10, 1:10),
y = c(1:10 * 100, 2 ** (1:10)),
diferencas = c(rep("aditivas", 10), rep("multiplicativas", 10))
)
exemplo
Ambas as distribuições numa escala linear:
exemplo %>%
ggplot(aes(diferencas, y, group = diferencas, color = diferencas)) +
geom_point(size = 2) +
scale_y_continuous(breaks = c(0, 1:10 * 100), minor_breaks = F)
Agora as duas em uma escala log2:
exemplo %>%
ggplot(aes(diferencas, y, group = diferencas, color = diferencas)) +
geom_point(size = 2) +
scale_y_continuous(trans='log2', breaks = 2 ** (1:10), minor_breaks = F)
A diferença na posição de acordo com a escala (ou seja, na imagem) é tal que: log2(8) - log2(4) = 3 - 2 = 1
. Da mesma maneira, log2(1024) - log2(512) = 10 - 9 = 1
. A posição do valor 1024 é dada por log2(1024)
. Para andar uma unidade nessa escala, é preciso multiplicar 1024 por 2, pois log2(1024*2) = log2(1024) + 1
.
É uma boa entender onde ficam os valores crescendo linearmente em uma escala de log, também:
exemplo %>%
ggplot(aes(diferencas, y, group = diferencas, color = diferencas)) +
geom_point(size = 2) +
scale_y_continuous(trans='log2', breaks = c(1:10 * 100), minor_breaks = F)
Esses formatos seriam o mesmo para outras bases.
Outra coisa: não há posição para o zero em uma escala de log. Isso porque não existe log(x)
em nenhuma base.
Agora com uma escala de log na base 10.
por_estado %>%
ggplot(aes(x = reorder(uf, maior_populacao), y = maior_populacao / 1e3)) +
geom_point(color = "#33658A") +
geom_rug(alpha = .7,
color = "#2F4858",
sides = "l") +
labs(
title = "Maior município por UF",
subtitle = "Tamanho em população em 2010",
x = "UF",
y = "População do maior município (Em milhares)"
) +
scale_y_log10()
Veja como agora os pontos estão menos concentrados nos valores baixos. Temos espaço para ver as diferenças entre os valores baixos, porque diferenças menores da escala linear nessa região da logarítmica são consideradas maiores. Ganhamos nuance nessa parte da escala.
O histograma muda mais ainda:
por_estado %>%
ggplot(aes(x = maior_populacao/ 1e3)) +
geom_histogram(bins = 6, boundary = 0, color = "#034732", fill = "white") +
labs(
y = "Quantidade",
x = "População (milhares)"
) + scale_x_log10()
E ainda mais quando vemos os dados de todos os municípios, onde a concentração, assimetria e cauda da distribuição são todos maiores que nos dados acima:
municipios %>%
filter(!is.na(populacao2010)) %>%
ggplot(aes(x = populacao2010/ 1e3)) +
geom_histogram(bins = 30, boundary = 0, fill = "white", color = "dark orange") +
geom_rug(size = .3, alpha = .3, color = "red") +
labs(
y = "Quantidade",
x = "População (milhares)"
) + scale_x_log10()
Outra situação útil é quando queremos comparar porcentagens ou razões. Nesse caso, o dobro e a metade deveriam ter a mesma distância de um valor. Assim como se queremos dizer que um evento é tantas vezes mais/menos frequente que outro.
Por exemplo, nos nomes de santo e santa nas cidades.
mais_sobre_nomes = municipios %>%
filter(!is.na(populacao2010), uf != "DF") %>%
group_by(uf) %>%
summarise(joao = 100 * sum(grepl("João", municipio))/n(),
maria = 100 * sum(grepl("Maria", municipio))/n(),
razao_jm = joao/maria)
mais_sobre_nomes %>%
filter(joao * maria > 0) %>%
ggplot(aes(x = reorder(uf, razao_jm), y = razao_jm)) +
geom_col() +
labs(
x = "UF",
y = "#joões/#marias"
)
mais_sobre_nomes %>%
filter(joao * maria > 0) %>%
ggplot(aes(x = reorder(uf, razao_jm), y = razao_jm)) +
geom_col(width = .4) +
scale_y_continuous(trans = "log2") +
labs(
x = "UF",
y = "#joões/#marias"
)