# ────────────────────────────────────────
library(igraph)
##
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
##
## decompose, spectrum
## The following object is masked from 'package:base':
##
## union
library(ggplot2)
set.seed(123) # para reprodutibilidade
# ────────────────────────────────────────
# Criamos uma rede com nós e arestas representando conexões diversas
rotas <- matrix(c(
"A", "B", # A: 1
"A", "C", # A: 2
"A", "D", # A: 3
"A", "E", # A: 4
"B", "D", # B: 2
"B", "F", # B: 3
"B", "H", # B: 4
"C", "D", # C: 2
"C", "Y", # C: 3
"C", "Z", # C: 4
"D", "E", # D: 4
"D", "F", # D: 5
"E", "F", # E: 3
"E", "I", # E: 4
"F", "G", # F: 4
"F", "Z", # F: 5
"G", "H", # G: 2
"H", "I", # H: 2
"Y", "Z" # Y: 1, Z: 3
), byrow = TRUE, ncol = 2)
g <- graph_from_edgelist(rotas, directed = FALSE)
E(g)$id <- paste0("e", seq_along(E(g)))
##definir manualmente os atributos X e Y nos nós
V(g)$X <- runif(vcount(g), min = -51.20364, max = -51.18838) # Longitude
V(g)$Y <- runif(vcount(g), min = -30.03472, max = -30.02750) # Latitude
E(g)$faixas <- sample(1:5, ecount(g), replace = TRUE) # número de faixas (1 a 5)
E(g)$tem_semaforo <- sample(c(0, 1), ecount(g), replace = TRUE) # binário: tem ou não
E(g)$comprimento_km <- runif(ecount(g), min = 0.1, max = 3.5) # em km
E(g)$densidade_edif <- rnorm(ecount(g), mean = 0.5, sd = 0.1) # densidade simulada
plot(g, vertex.size = 30, vertex.color = "lightblue", main = "Rede Original")
data.frame(
id = V(g)$name,
X = V(g)$X,
Y = V(g)$Y
)
## id X Y
## 1 A -51.19925 -30.03145
## 2 B -51.19161 -30.02983
## 3 C -51.19740 -30.03059
## 4 D -51.19017 -30.03398
## 5 E -51.18929 -30.02822
## 6 F -51.20294 -30.03294
## 7 H -51.19558 -30.03442
## 8 Y -51.19002 -30.03235
## 9 Z -51.19523 -30.02783
## 10 I -51.19667 -30.02830
## 11 G -51.18904 -30.02972
df_arestas <- data.frame(
id = E(g)$id,
from = ends(g, E(g))[, 1],
to = ends(g, E(g))[, 2],
faixas = E(g)$faixas,
tem_semaforo = E(g)$tem_semaforo,
comprimento_km = E(g)$comprimento_km,
densidade_edif = E(g)$densidade_edif
)
df_arestas
## id from to faixas tem_semaforo comprimento_km densidade_edif
## 1 e1 A B 1 1 1.5954277 0.6207962
## 2 e2 A C 1 0 2.6652155 0.3876891
## 3 e3 A D 5 0 2.2393518 0.4597115
## 4 e4 A E 3 0 2.5146202 0.4533345
## 5 e5 B D 2 0 0.1021242 0.5779965
## 6 e6 B F 2 1 1.7160764 0.4916631
## 7 e7 B H 1 1 0.8484042 0.5253319
## 8 e8 C D 3 0 1.3913762 0.4971453
## 9 e9 C Y 4 1 2.1834214 0.4957130
## 10 e10 C Z 1 0 1.2961129 0.6368602
## 11 e11 D E 3 0 0.4778604 0.4774229
## 12 e12 D F 5 1 0.9283062 0.6516471
## 13 e13 E F 4 1 2.3713890 0.3451247
## 14 e14 E I 2 0 1.5199991 0.5584614
## 15 e15 F G 5 0 2.7798658 0.5123854
## 16 e16 F Z 1 1 0.4497398 0.5215942
## 17 e17 H G 1 0 1.5786353 0.5379639
## 18 e18 H I 2 0 3.4488537 0.4497677
## 19 e19 Y Z 3 0 3.1363738 0.4666793
grau <- degree(g)
grau
## A B C D E F H Y Z I G
## 4 4 4 5 4 5 3 2 3 2 2
betweenness <- betweenness(g)
betweenness
## A B C D E F H Y
## 3.583333 5.583333 6.000000 5.166667 6.583333 12.583333 2.750000 0.000000
## Z I G
## 4.500000 1.000000 1.250000
eigen <- eigen_centrality(g)$vector
eigen
## A B C D E F H Y
## 0.8252319 0.7805574 0.6639840 1.0000000 0.7632768 0.8541215 0.3548072 0.2905100
## Z I G
## 0.4652780 0.2876343 0.3110047
closeness <- closeness(g)
closeness
## A B C D E F H
## 0.05882353 0.05882353 0.05263158 0.06666667 0.05882353 0.06666667 0.04761905
## Y Z I G
## 0.04000000 0.05263158 0.04545455 0.04761905
###🔸 Transitividade (ou Fator de Agrupamento) Global:
- Mede a proporção de triângulos na rede inteira, comparado ao número de
tríades (trios possíveis que poderiam formar triângulo).
- Avalia na rede como um todo, os amigos de amigos também são
amigos?
- Mede a proporção de triângulos fechados em relação ao total de
“triângulos possíveis” na rede como um todo.
agrupamento <- transitivity(g, type = "global", isolates = "zero")
agrupamento
## [1] 0.3396226
###🔹 Transitividade (ou Fator de Agrupamento) Local
cada nó, o quanto seus vizinhos estão interconectados entre si.
- Dos pares de vizinhos que um nó tem, quantos estão conectados entre
si?
- Valor entre 0 e 1:
- 1 → todos os vizinhos do nó se conhecem (clique completo)
- 0 → nenhum vizinho se conhece
agrupamento <- transitivity(g, type = "local", isolates = "zero")
agrupamento
## A B C D E F H Y
## 0.5000000 0.3333333 0.3333333 0.5000000 0.3333333 0.2000000 0.0000000 1.0000000
## Z I G
## 0.3333333 0.0000000 0.0000000
dist_média <- mean_distance(g)
dist_média
## [1] 1.890909
diâmetro <- diameter(g)
diâmetro
## [1] 4
cat("Distância média:", dist_média, "\n")
## Distância média: 1.890909
cat("Diâmetro:", diâmetro, "\n")
## Diâmetro: 4
No contexto da rede viária
- Alta transitividade local em uma interseção pode significar
redundância e conectividade alternativa — o que pode ser bom para
redistribuir fluxo em caso de congestionamento.
- Alta transitividade global sugere que a cidade, como um todo, tem alta
interconectividade — característica de cidades planejadas ou com padrões
mais regulares.
##🔹 Métricas de Agrupamento
### Transitividade global
Também conhecida como o coeficiente de agrupamento global (global
clustering coefficient), ela mede a tendência da rede como um todo de
formar triângulos — ou seja, de três nós quaisquer conectados dois a
dois também estarem conectados entre si.
T_{global} =
- Valor próximo de 1 → A rede tem muitos triângulos → Forte coesão
triádica → Muito agrupamento (ex: áreas urbanas densas).
- Valor próximo de 0 → Poucas conexões de terceiro nível → Rede mais
linear ou hierárquica (ex: rodovias).
# ────────────────────────────────────────
transitivity(g, type = "global")
## [1] 0.3396226
A transitividade local de um nó em uma rede representa o quanto os
vizinhos desse nó estão conectados entre si. Essa métrica é útil para
identificar agrupamentos locais ou malhas viárias densas, onde as
conexões ao redor de uma interseção também se conectam entre si.
📘 Fórmula
A transitividade local C_i de um nó i é dada por:
\(C_i = \frac{2 \times e_i}{k_i (k_i -
1)}\)
Onde:
- e_i: número de arestas entre os vizinhos de i;
- k_i: grau (número de vizinhos) do nó i.
O resultado varia entre:
- 0 → Nenhuma conexão entre os vizinhos;
- 1 → Todos os vizinhos estão interconectados (formando um clique).
transitivity(g, type = "local")
## A B C D E F H Y
## 0.5000000 0.3333333 0.3333333 0.5000000 0.3333333 0.2000000 0.0000000 1.0000000
## Z I G
## 0.3333333 0.0000000 0.0000000
trans_local <- transitivity(g, type = "local", isolates = "zero")
head(trans_local)
## A B C D E F
## 0.5000000 0.3333333 0.3333333 0.5000000 0.3333333 0.2000000
🔍 Walktrap
- Ele realiza passeios aleatórios curtos (por padrão, 4 passos) dentro
da rede.
- Mede a similaridade entre nós com base nesses passeios.
- A partir disso, utiliza uma abordagem hierárquica para agrupar nós que
frequentemente aparecem juntos nos passeios.
- O resultado é uma estrutura de comunidades que maximiza a modularidade
da rede.
Detectar comunidades usando Walktrap
comunidades <- cluster_walktrap(g)
comunidades
## IGRAPH clustering walktrap, groups: 3, mod: 0.26
## + groups:
## $`1`
## [1] "A" "B" "D" "E" "F"
##
## $`2`
## [1] "C" "Y" "Z"
##
## $`3`
## [1] "H" "I" "G"
##
length(comunidades)
## [1] 3
membership(comunidades)
## A B C D E F H Y Z I G
## 1 1 2 1 1 1 3 2 2 3 3
plot(comunidades, g, vertex.label = NA, vertex.size = 5)
📊 Por que usar o Walktrap?
- Robusto para grafos grandes e com estrutura modular bem
definida.
- Não exige definir o número de comunidades previamente.
- Funciona bem para redes urbanas com zonas de conectividade local densa
(ex: bairros bem conectados internamente mas com menos ligações
externas).
plot(comunidades, g, main = "Comunidades Detectadas")
Primeiro, vamos garantir que cada aresta (rua) saiba a qual
comunidade pertencem seus nós de origem e destino:
Associe os grupos aos nós
comunidades <- cluster_walktrap(g)
membership_df <- data.frame(
id = names(membership(comunidades)),
comunidade = as.numeric(membership(comunidades))
)
membership_df
## id comunidade
## 1 A 1
## 2 B 1
## 3 C 2
## 4 D 1
## 5 E 1
## 6 F 1
## 7 H 3
## 8 Y 2
## 9 Z 2
## 10 I 3
## 11 G 3
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:igraph':
##
## as_data_frame, groups, union
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
nodes <- data.frame(
id = V(g)$name,
X = V(g)$X, # se houver coordenadas
Y = V(g)$Y
)
nodes_enriquecidos <- left_join(nodes, membership_df, by = "id")
rm(edges)
## Warning in rm(edges): objeto 'edges' não encontrado
class(g)
## [1] "igraph"
edges <- igraph::as_data_frame(g, what = "edges")
edges_vis <- edges %>%
left_join(nodes_enriquecidos %>% dplyr::select(id, comunidade), by = c("from" = "id")) %>%
rename(comunidade_from = comunidade) %>%
left_join(nodes_enriquecidos %>% dplyr::select(id, comunidade), by = c("to" = "id")) %>%
rename(comunidade_to = comunidade)
Criar uma coluna de comunidade dominante por rua (por simplicidade)
edges_vis$comunidade_rua <- ifelse(edges_vis$comunidade_from == edges_vis$comunidade_to,
edges_vis$comunidade_from,
NA)
Agora, podemos fazer análises por comunidade, por exemplo:
library(dplyr)
# Agrupar por comunidade da rua e calcular média dos atributos urbanos
analise_comunidades <- edges_vis %>%
filter(!is.na(comunidade_rua)) %>%
group_by(comunidade_rua) %>%
summarise(
media_faixas = mean(faixas, na.rm = TRUE),
prop_semaforo = mean(tem_semaforo, na.rm = TRUE),
densidade_media = mean(densidade_edif, na.rm = TRUE),
comprimento_medio = mean(comprimento_km, na.rm = TRUE)
)
Se quiser colorir o grafo pelas comunidades:
nodes_vis <- left_join(nodes, membership_df, by = "id")
nodes_vis$group <- as.factor(nodes_vis$comunidade)
library(visNetwork)
visNetwork(nodes_vis, edges) %>%
visGroups(groupname = levels(nodes_vis$group)) %>%
visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE) %>%
visLegend()
#Ou, se preferir um mapa interativo com cores por comunidade:
library(mapview)
library(sf)
## Linking to GEOS 3.11.2, GDAL 3.8.2, PROJ 9.3.1; sf_use_s2() is TRUE
library(dplyr)
library(purrr)
##
## Attaching package: 'purrr'
## The following objects are masked from 'package:igraph':
##
## compose, simplify
# Junta as coordenadas dos nós de origem e destino
edges_sf <- edges_vis %>%
left_join(nodes, by = c("from" = "id")) %>%
rename(X_from = X, Y_from = Y) %>%
left_join(nodes, by = c("to" = "id")) %>%
rename(X_to = X, Y_to = Y) %>%
rowwise() %>%
mutate(geometry = st_sfc(
st_linestring(matrix(c(X_from, X_to, Y_from, Y_to), ncol = 2)), crs = 4326
)) %>%
ungroup() %>%
st_as_sf()
# Supondo que edges_vis tenha geometria em `sf`
mapview(edges_sf, zcol = "comunidade_rua", legend = TRUE)
📐 Modularidade (Modularity)
É uma métrica que varia de -1 a 1 (na prática, geralmente entre 0 e 1),
e avalia a qualidade da partição da rede em comunidades. A fórmula
simplificada da modularidade Q é:
Q = {i,j} (c_i, c_j)
Onde:
- A{ij}: valor da aresta entre os nós i e j;
- k_i, k_j: grau dos nós i e j;
- m: número total de arestas;
- (c_i, c_j): vale 1 se i e j estão na mesma comunidade, 0 se não.
Esse valor indica o quanto as conexões estão concentradas
dentro
das comunidades, em comparação ao que se esperaria ao acaso (em uma rede
com as mesmas distribuições de grau, mas conexões aleatórias).
📏 Escala de interpretação da modularidade
- Q ≤ 0:
🔴 Sem estrutura comunitária
A divisão da rede é pior ou igual à aleatoriedade. Comunidades não fazem
sentido.
- 0 < Q < 0.3:
🟠 Comunidades fracas
Há uma leve preferência por conexões internas, mas ainda é um
agrupamento difuso.
- 0.3 ≤ Q < 0.6:
🟡 Comunidades razoáveis a boas
Estrutura comunitária perceptível. Nós tendem a estar mais conectados
dentro de seus grupos do que fora.
- 0.6 ≤ Q < 0.8:
🟢 Comunidades bem definidas
Forte modularidade, agrupamentos bem separados. Estrutura comunitária
sólida.
- Q ≥ 0.8:
🔵 Comunidades muito bem formadas (raro)
Quase toda a conectividade está contida dentro das comunidades. Pode
indicar estrutura fortemente compartimentalizada.
modularity(comunidades)
## [1] 0.2590028
is_connected(g)
## [1] TRUE
components(g)
## $membership
## A B C D E F H Y Z I G
## 1 1 1 1 1 1 1 1 1 1 1
##
## $csize
## [1] 11
##
## $no
## [1] 1
Pontos de articulação (ou articulation points) são nós críticos de uma rede — ou seja, vértices cuja remoção desconecta uma parte do grafo. Em outras palavras, eles são “gargalos” ou “portas” que mantêm diferentes regiões da rede conectadas.
articulation_points(g)
## + 0/11 vertices, named, from 46674d3:
🔎 Interpretação:
Nenhum dos nós em g é crítico a ponto de, se removido, desconectar a
rede. Em outras palavras, sua rede é resiliente: a remoção de qualquer
nó não interrompe a conectividade geral entre os outros. Esse resultado
é comum em redes:
- redundantes, com caminhos alternativos entre regiões;
- ou densamente conectadas, onde os nós têm múltiplas conexões
paralelas.
articulation_points(g)
## + 0/11 vertices, named, from 46674d3:
ranking <- sort(betweenness, decreasing = TRUE)
ranking
## F E C B D Z A H
## 12.583333 6.583333 6.000000 5.583333 5.166667 4.500000 3.583333 2.750000
## G I Y
## 1.250000 1.000000 0.000000
nos_críticos <- names(ranking)[1:3]
cat("Nós mais críticos:", paste(nos_críticos, collapse = ", "), "\n")
## Nós mais críticos: F, E, C
g_colapsado <- delete_vertices(g, nos_críticos)
plot(g_colapsado, vertex.color = "gray", main = "Rede Após Falhas Críticas")
cat("Distância média pós-falha:", mean_distance(g_colapsado), "\n")
## Distância média pós-falha: 1.8125
cat("Rede conectada? ", is_connected(g_colapsado), "\n")
## Rede conectada? FALSE
cat("Componentes presentes:", components(g_colapsado)$no, "\n")
## Componentes presentes: 2
v_validos <- V(g_colapsado)$name
arestas_novas <- matrix(c("C", "I", "D", "G", "A", "I"), byrow = TRUE, ncol = 2)
arestas_filtradas <- arestas_novas[
apply(arestas_novas, 1, function(par) all(par %in% v_validos)),
]
if (nrow(arestas_filtradas) > 0) {
g_reforçado <- add_edges(g_colapsado, t(arestas_filtradas))
} else {
g_reforçado <- g_colapsado
message("Nenhuma aresta válida foi encontrada — rede mantida como está.")
}
plot(g_reforçado, vertex.color = "lightgreen", main = "Rede Reforçada")
cat("Distância média pós-reforço:", mean_distance(g_reforçado), "\n")
## Distância média pós-reforço: 1.4375
cat("Rede reconectada? ", is_connected(g_reforçado), "\n")
## Rede reconectada? FALSE
n <- vcount(g)
m <- ecount(g)
k <- round(mean(grau))
plot(g)
g_er <- erdos.renyi.game(n, m, type = "gnm")
plot(g_er)# Aleatória
g_ws <- watts.strogatz.game(1, size = n, nei = k %/% 2, p = 0.05) # Small-world
## Warning: `watts.strogatz.game()` was deprecated in igraph 2.0.0.
## ℹ Please use `sample_smallworld()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
plot(g_ws)
g_ba <- barabasi.game(n, m = k %/% 2) # Com hubs
## Warning: `barabasi.game()` was deprecated in igraph 2.0.0.
## ℹ Please use `sample_pa()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
plot(g_ba)
get_metrics <- function(gr) {
c(
dist_média = mean_distance(gr),
agrupamento = transitivity(gr, type = "global"),
diâmetro = diameter(gr),
grau_médio = mean(degree(gr))
)
}
tabela_comp <- rbind(
Real = get_metrics(g),
Erdős_Rényi = get_metrics(g_er),
Watts_Strogatz = get_metrics(g_ws),
Barabási = get_metrics(g_ba)
)
cat("\n🔎 Comparação entre estruturas:\n")
##
## 🔎 Comparação entre estruturas:
print(round(tabela_comp, 3))
## dist_média agrupamento diâmetro grau_médio
## Real 1.891 0.340 4 3.455
## Erdős_Rényi 1.909 0.508 3 3.455
## Watts_Strogatz 3.000 0.000 5 2.000
## Barabási 1.438 0.000 3 1.818
perfil_nos <- data.frame(
nome = V(g)$name,
grau = grau,
betweenness = betweenness,
eigenvector = eigen,
closeness = closeness,
clustering = agrupamento
)
rownames(perfil_nos) <- perfil_nos$nome
perfil_nos$nome <- NULL
colunas_variaveis <- apply(perfil_nos, 2, sd) != 0
perfil_limp <- perfil_nos[, colunas_variaveis]
pca <- prcomp(perfil_limp, scale. = TRUE)
pca
## Standard deviations (1, .., p=5):
## [1] 1.9027813 1.0341225 0.5041325 0.2097583 0.1089300
##
## Rotation (n x k) = (5 x 5):
## PC1 PC2 PC3 PC4 PC5
## grau -0.51786419 -0.05074758 0.07441624 -0.71163639 0.46613005
## betweenness -0.46262112 0.21376016 -0.83055458 0.10419512 -0.19902453
## eigenvector -0.50435724 -0.16810957 0.40707440 -0.06315581 -0.74004373
## closeness -0.51268034 0.06881850 0.28511117 0.68125672 0.43246247
## clustering -0.02410441 -0.95850637 -0.24009032 0.12090347 0.09177963
sdev <- pca$sdev
variancia <- sdev^2
variancia_perc <- variancia / sum(variancia) * 100
explicacao <- data.frame(
Componente = paste0("PC", seq_along(sdev)),
Desvio_Padrao = round(sdev, 3),
Variancia = round(variancia, 3),
Percentual = round(variancia_perc, 1)
)
print(explicacao)
## Componente Desvio_Padrao Variancia Percentual
## 1 PC1 1.903 3.621 72.4
## 2 PC2 1.034 1.069 21.4
## 3 PC3 0.504 0.254 5.1
## 4 PC4 0.210 0.044 0.9
## 5 PC5 0.109 0.012 0.2
A tabela Rotation mostra os loadings (coeficientes) que ligam os
componentes às variáveis originais. Veja como ler:
🔵 PC1
grau 0.51378
betweenness 0.49191
eigenvector 0.49423
closeness 0.49979
Todos os valores são positivos e próximos → PC1 representa uma média
ponderada de TODAS as métricas de centralidade. Ou seja:
🧠 PC1 mede a centralidade “geral” de um nó: quanto mais central em
qualquer sentido, maior a pontuação.
🟡 PC2 betweenness 0.65118 (muito alta)
grau 0.30902
closeness -0.39606
eigenvector -0.56886
Aqui temos um contraste: betweenness é positiva, enquanto closeness e
eigenvector são negativas.
🧭 PC2 diferencia nós “articuladores” (alta betweenness) daqueles
integrados localmente (alta eigen/closeness).
Nó com PC2 alto → atua como ponte Nó com PC2 baixo → atua mais como hub
interno ou periférico
Componente | Interpretação prática
PC1 | Centralidade geral (todos os scores altos)
PC2 | Contraste entre ponte (betweenness) e hub local
PC3/4 | Detalhes marginais (pouco impacto global)
set.seed(123)
agrupamento <- kmeans(scale(perfil_limp), centers = 3)
perfil_nos$cluster <- as.factor(agrupamento$cluster)
df_pca <- as.data.frame(pca$x[, 1:2])
df_pca$cluster <- perfil_nos$cluster
df_pca$nome <- rownames(perfil_nos)
ggplot(df_pca, aes(x = PC1, y = PC2, color = cluster)) +
geom_point(size = 4) +
geom_text(aes(label = nome), vjust = -1.2, size = 3.5) +
labs(title = "Clusters de Perfis Estruturais (PCA + k-means)", color = "Grupo") +
theme_minimal()
nó <- "E"
arestas_incidentes <- incident(g, nó, mode = "all")
ids_das_arestas <- E(g)[arestas_incidentes]$id
cat("\nArestas conectadas ao nó", nó, ":", paste(ids_das_arestas, collapse = ", "), "\n")
##
## Arestas conectadas ao nó E : e4, e11, e13, e14
df_arestas
## id from to faixas tem_semaforo comprimento_km densidade_edif
## 1 e1 A B 1 1 1.5954277 0.6207962
## 2 e2 A C 1 0 2.6652155 0.3876891
## 3 e3 A D 5 0 2.2393518 0.4597115
## 4 e4 A E 3 0 2.5146202 0.4533345
## 5 e5 B D 2 0 0.1021242 0.5779965
## 6 e6 B F 2 1 1.7160764 0.4916631
## 7 e7 B H 1 1 0.8484042 0.5253319
## 8 e8 C D 3 0 1.3913762 0.4971453
## 9 e9 C Y 4 1 2.1834214 0.4957130
## 10 e10 C Z 1 0 1.2961129 0.6368602
## 11 e11 D E 3 0 0.4778604 0.4774229
## 12 e12 D F 5 1 0.9283062 0.6516471
## 13 e13 E F 4 1 2.3713890 0.3451247
## 14 e14 E I 2 0 1.5199991 0.5584614
## 15 e15 F G 5 0 2.7798658 0.5123854
## 16 e16 F Z 1 1 0.4497398 0.5215942
## 17 e17 H G 1 0 1.5786353 0.5379639
## 18 e18 H I 2 0 3.4488537 0.4497677
## 19 e19 Y Z 3 0 3.1363738 0.4666793
df_arestas <- igraph::as_data_frame(g, what = "edges")
df_arestas_conectadas <- df_arestas[as.numeric(arestas_incidentes), ]
df_arestas_conectadas$id <- ids_das_arestas
print(df_arestas_conectadas)
## from to id faixas tem_semaforo comprimento_km densidade_edif
## 4 A E e4 3 0 2.5146202 0.4533345
## 11 D E e11 3 0 0.4778604 0.4774229
## 13 E F e13 4 1 2.3713890 0.3451247
## 14 E I e14 2 0 1.5199991 0.5584614