Introdução
A Teoria dos Grafos, ramo da Matemática que utiliza conceitos fundamentais para representar elementos definidos como nós (ou vértices) e arestas (ou conexões), lida com estruturas abstratas de relações. Em termos práticos, fornece um conjunto de conceitos, modelos e algoritmos que são utilizados para a análise de redes.
Para análise de redes com pacotes do R, utiliza-se a estrutura de dados em pares do tipo “from, to”, que representa a conexão entre os elementos. Entretanto, técnicas de análise de rede também são aplicadas a matrizes de correlação. Conceitos como centralidade, motivo e estrutura comunitária podem ser empregados para manifestar as propriedades ocultas em um conjunto de dados.
Nesse caso, estabelecemos um limite ou limiar a partir do qual os valores pareados são filtrados, como método para criar uma rede a partir de uma matriz de correlação.
Objetivo
Utilizamos ferramentas de análise de rede para visualizar e destacar diferentes grupos de Unidades de Planejamento, de acordo com o Plano de Desenvolvimento Territorial do município de Juiz de Fora.
Recursos
A relação de Unidades de Planejamento do município de Juiz de Fora pode ser extraída da página web https://www.pjf.mg.gov.br/desenvolvimentodoterritorio/dados/rp_centro_oeste.php.
Bibliotecas
Carregamos as seguintes bibliotecas do R no RStudio:
- tidyverse - para manipulação de dados;
- rvest - para extração de dados da web;
- ggplot2 - para visualização gráfica;
- igraph - fornece rotinas para análise de rede;
- tidygraph - ferramentas para manipular estruturas da rede;
- ggraph - extensão do ggplot2 para visualização de redes;
- rlang - ferramenta para manipulação de expressões e funções;
- rmdformats - temas adicionais para documentos Rmarkdown.
Coleta e limpeza de dados
Utilizamos a função read_html() do pacote rvest para ler a página e extrair os links relevantes:
url <- "https://www.pjf.mg.gov.br/desenvolvimentodoterritorio/dados/rp_centro_oeste.php"
page <- read_html(url)
rp <- page %>%
html_nodes(xpath = "//li[@class='sub-sub']//a[contains(@href, '/rp')]") %>%
html_attr("href")Após a extração dos links, utilizamos a função lapply() para percorrer cada link e extrair as tabelas:
tbls <- lapply(rp, function(i) {
z <- xml2::read_html(i) %>%
html_nodes("table") %>%
.[2] %>%
html_table(fill = TRUE)
})
df <- bind_rows(tbls)Feito isto, realizamos algumas transformações nos dados, como renomear colunas e calcular novas variáveis:
novos_nomes <- c("RP", "UP", "Localidades", "Hectares", "População", "Densidade")
names(df) <- novos_nomes
df <- df %>%
mutate(Quant_Loc = str_count(Localidades, ",") + 1)
replan <- df %>%
mutate(
Hect = gsub("\\.", "", Hectares),
Hectares = as.numeric(gsub(",", ".", Hect)),
População = as.numeric(gsub("\\.", "", População)),
Densidade = as.numeric(gsub(",", ".", gsub("\\.", "", Densidade, fixed = TRUE)))
)Convertemos o objeto replan em um data frame e atribuímos rótulos às linhas:
Por fim, removemos as colunas indesejadas:
Definição da matriz de correlação
Definimos a matriz de correlação com a função cor() do pacote igraph, e estabelecemos o ponto de corte:
Definição da rede
Convertemos a matriz de correlação em um objeto com estrutura de rede para ser tratado pelo pacote tidygraph:
O objeto tbl_graph gerado pela função as_tbl_graph() é composto por duas tabelas; uma contém os nós e outra as conexões.
## # A tbl_graph: 38 nodes and 145 edges
## #
## # An undirected multigraph with 8 components
## #
## # Node Data: 38 × 1 (active)
## name
## <chr>
## 1 CO1-Remonta
## 2 CO2-Francisco Bernardino
## 3 CO3-Morro do Sabão
## 4 CO4-Cerâmica
## 5 CO5-Limeira
## 6 C1-Mariano Procópio
## 7 C2-Centro
## 8 C3-São Mateus
## 9 L1-Vitorino Braga
## 10 L2-Progresso
## # ℹ 28 more rows
## #
## # Edge Data: 145 × 3
## from to weight
## <int> <int> <dbl>
## 1 1 1 1
## 2 1 21 0.998
## 3 2 2 1
## # ℹ 142 more rows
Visualização da rede
Utilizamos o pacote ggraph para visualizar a rede e destacar diferentes grupos de Unidades de Planejamento. O parâmetro layout aceita 13 tipos de estruturas gráficas para representação visual da rede, de modo que a aparência muda de acordo com o algoritmo escolhido.
ggraph(ntw, layout = 'kk') +
geom_edge_link() +
geom_node_point() +
geom_node_text(aes(label = name), size = 2, repel = TRUE, max.overlaps=Inf) +
theme_graph()Inspeção inicial
Exploramos algumas informações básicas da rede em análise. O tamanho da rede, correspondente à quantidade de conexões, é dado pela função gsize():
## [1] 145
A ordem da rede, correspondente à quantidade de nós, é dada pela função gorder():
## [1] 38
Características dos nós
Antes de mais nada, removemos os nós isolados, se houver:
Centralidade
A mais reconhecida características dos nós é a
centralidade.
Quanto maior o índice de centralidade, mais
central é o nó.
Há diversas medidas de centralidade.
A primeira medida,
denominada grau de centralidade e calculada pela função
centrality_degree(), captura o número de relacionamentos de um
nó.
## # A tbl_graph: 38 nodes and 145 edges
## #
## # An undirected multigraph with 8 components
## #
## # Node Data: 38 × 2 (active)
## name grau
## <chr> <dbl>
## 1 CO1-Remonta 3
## 2 CO2-Francisco Bernardino 12
## 3 CO3-Morro do Sabão 4
## 4 CO4-Cerâmica 12
## 5 CO5-Limeira 6
## 6 C1-Mariano Procópio 12
## 7 C2-Centro 12
## 8 C3-São Mateus 14
## 9 L1-Vitorino Braga 4
## 10 L2-Progresso 2
## # ℹ 28 more rows
## #
## # Edge Data: 145 × 3
## from to weight
## <int> <int> <dbl>
## 1 1 1 1
## 2 1 21 0.998
## 3 2 2 1
## # ℹ 142 more rows
Criamos um gráfico para visualizar o grau de centralidade dos nós:
ggraph(nocd, layout = 'kk') +
geom_edge_link() +
geom_node_point(aes(size = grau, colour = grau)) +
scale_color_continuous(guide = 'legend') +
theme_graph()A segunda medida de centralidade, traduzida como intermediação, é fornecida pela função centrality_betweenness(), que captura o número de caminhos mais curtos que passam por um nó.
Que também pode ser visualizada graficamente:
ggraph(nob, layout = 'fr') +
geom_edge_link() +
geom_node_point(aes(size = inter, colour = inter)) +
scale_color_continuous(guide = 'legend') +
theme_graph()A centralidade de proximidade de um nó é calculada como o inverso da soma do comprimento dos caminhos mais curtos entre o nó e todos os outros nós da rede. Quanto mais central for um nó, mais próximo ele estará de todos os outros.
Que também pode ser visualizada graficamente:
ggraph(nob, layout = 'kk') +
geom_edge_link() +
geom_node_point(aes(size = proximidade, colour = proximidade)) +
scale_color_continuous(guide = 'legend') +
theme_graph()## Warning: Removed 2 rows containing missing values or values outside the scale range
## (`geom_point()`).
Características da rede
Podem ser calculadas algumas métricas para avaliação da rede:
Densidade - proporção das possíveis conexões
existentes
Diâmetro - caminho mais curto e mais
longo na rede
Distância - distância média entre
dois nós
Transitividade - probabilidade dos nós
adjacentes serem interconectados
Densidade <- igraph::edge_density(ntw)
Diametro <- with_graph(ntw, graph_diameter())
Distancia <- with_graph(ntw, graph_mean_dist())
Transitividade <- igraph::transitivity(ntw)
tibble(Densidade, Diametro, Distancia, Transitividade)## # A tibble: 1 × 4
## Densidade Diametro Distancia Transitividade
## <dbl> <dbl> <dbl> <dbl>
## 1 0.206 3 1.37 0.894
Estatísticas da rede
Exibimos um resumo contendo algumas medidas estatísticas, calculadas através da função summarise():
resumo <- nocd %>%
activate(nodes) %>%
as_tibble() %>%
summarise(
média = mean(grau),
máximo = max(grau),
mediana = median(grau))
resumo## # A tibble: 1 × 3
## média máximo mediana
## <dbl> <dbl> <dbl>
## 1 7.63 14 8
Função auxiliar
Com ajuda do pacote rlang, definimos uma função auxiliar, que recebe como entrada o data frame e a coluna escolhida como fator.
fator <- function(fonte, coluna) {
coluna_nome <- sub(".*\\$", "", deparse(substitute(coluna)))
coluna_quo <- enquo(coluna)
fact <- tibble(
name = rownames({{fonte}}),
!!paste0("fct.", coluna_nome) := as.factor(!!coluna_quo)
)
return(list(fact, paste0("fct.", coluna_nome)))
}Na chamada da função, atribuímos os argumentos de entrada desejados:
A saída da função, que retorna tanto o data frame quanto o nome da coluna fatorizados, é armazenada em um objeto de nome “results”.
Preparamos o grafo ntw para visualização, adicionando informações dos nós através de uma junção à esquerda (left join) com o data frame rp.group e renomeando a coluna resultante como “label”, que será usada para rotular os nós na visualização do grafo.
Como os objetos tbl_graph possuem duas tabelas, especificamos qual delas será modificada com a função activate().
O nome da coluna fatorizada pode ser atribuído dinamicamente ao argumento color da função geom_node_point(), para especificar a cor dos nós, ao gerar o gráfico com o pacote ggraph.
Utilizamos o operador “!! sym” para converter a string do nome da coluna em um símbolo inteligível pela função ‘aes()’ do ggplot2.
ggraph(ntw, layout = 'kk') +
geom_edge_link(aes(width = weight), alpha = 0.2) +
scale_edge_width(range = c(0.2, 1)) +
geom_node_point(aes(color = !!sym(coluna_fatorizada)), size = 2) +
geom_node_text(aes(label = label), size = 2, repel = TRUE, max.overlaps = Inf) +
theme_graph() +
guides(color = guide_legend(ncol = 2)) Detecção de comunidades
Finalmente, utilizamos uma função de agrupamento predefinida para identificar comunidades representadas por grupos de nós densamente conectados.
ntw %>%
activate(nodes) %>%
mutate(community = as.factor(group_infomap())) %>%
ggraph(layout = "graphopt") +
geom_edge_link(width = 1, colour = "lightgray") +
geom_node_point(aes(colour = community), size = 4) +
geom_node_text(aes(label = label), size = 2, repel = TRUE, max.overlaps=Inf) +
theme_graph()Referências:
Brazil, Noli (2023). Lab 9: Social Network Analysis. CRD 230 - Spatial Methods in Community Research. Acessado em 17/04/2024: https://crd230.github.io/lab9.html#Network_characteristics.
Brunson, Cory (2019). embed with the Petersens. Acessado em 17/04/2024: https://corybrunson.github.io/2019/03/01/embeddability/
Christian (2020). Graphs are fun: A gentle introduction to graphs in R. Statistics, Science, Random Ramblings. A blog mostly about data and R. Acessado em 17/04/2024: https://hohenfeld.is/posts/graphs-are-fun-an-introduction-to-graphs-in-r/
Hevey, David (2018). Network analysis: a brief overview and tutorial. HEALTH PSYCHOLOGY AND BEHAVIORAL MEDICINE. 2018, VOL. 6, NO. 1, 301–328. https://doi.org/10.1080/21642850.2018.1521283
Newman, M. E. J. (2006). Modularity and community structure in networks. PNAS. June 6. 2006. Vol. 103, n° 23, pg. 8577-8582. https://www.pnas.org/doi/epdf/10.1073/pnas.0601602103
Nowak, Benjamin (2021). [R] Network analysis with {tidygraph}. Acessado em 17/04/2024: https://bjnnowak.netlify.app/2021/09/30/r-network-analysis-with-tidygraph/
Pedersen, Thomas L. (2017). Introduction to ggraph: Layouts. Data Imaginist. Acessado em 17/04/2024: https://www.data-imaginist.com/posts/2017-02-06-ggraph-introduction-layouts/
Radicchi, F., Castellano, C., Cecconi, F., Loreto, V., & Parisi, D. (2004). Defining and identifying communities in networks. Proceedings of the national academy of sciences, 101(9), 2658-2663. https://www.pnas.org/doi/full/10.1073/pnas.0400054101
Sadamori, K., Naoki, M. (2019). Constructing networks by filtering correlation matrices: a null model approach. Proc. R. Soc. A.47520190578. http://doi.org/10.1098/rspa.2019.0578
Sadler, Jesse (2017). Introduction to Network Analysis with R. Creating static and interactive network graphs. Acessado em 17/04/2024: https://www.jessesadler.com/post/network-analysis-with-r/
Schweinberger, Martin(2024). Network Analysis using R. Brisbane: The University of Queensland. url: https://ladal.edu.au/net.html (Version 2024.03.02). Acessado em 17/04/2024: https://ladal.edu.au/net.html#Network_Statistics
Wilson, Robin J. (1996). Introduction to Graph Theory. Fourth edition. Longman. First published by Oliver & Boyd, 1972. Disponível em: https://www.maths.ed.ac.uk/~v1ranick/papers/wilsongraph.pdf