CT050-Turma D: Geografia da Inovação, Política Tecnológica e Governança de Redes
Profa. Dra. Janaina Pamplona da Costa
Departamento de Política Científica e Tecnológica
Instituto de Geociências - Unicamp
Este artigo explora técnicas de Análise de Redes Sociais para analisar o comportamento e organização em redes colaboração de autores e desenvolvedores de pacotes de software para R1 publicados no repositório CRAN2.
O trabalho em rede tem se tornado cada vez mais uma maneira de organização humana presente em nossas vidas e nos mais diferentes níveis da estrutura das empresas modernas. “Os indivíduos, dotados de recursos e capacidades propositivas, organizam suas ações nos próprios espaços políticos em função de socializações e mobilizações suscitadas pelo próprio desenvolvimento das redes”. (MARTELETO 2001)
A dinâmica das redes funciona por meio de atividades relacionadas ao compartilhamento de valores e de idéias em comunidades, e em sua representação gráfica em que cada ator é representada por um nó, e as relações são representadas por linhas que conectam os nós. (STORCH 2008)
Analisar estas redes resume-se em estudar as ligações relacionais entre atores sociais. Estes atores, tanto podem ser pessoas e empresas individualmente ou coletivamente analisadas em unidades sociais, como por exemplo, departamento de uma organização, prestadoras de serviço público em um município ou estados-nação em um continente. (WASSERMAN 1994)
O acesso à informação é um elemento-chave para o desenvolvimento econômico e social de comunidades, grupos sociais e indivíduos. A capacidade de obter informações, além dos contornos restritos da própria localidade, é parte do capital relacional dos indivíduos e grupos. (MARTELETO 2004)
O capital social, definido como o conjunto de vantagens obtida da rede de relacionamento, pode ser considerado como capital humano ou financeiro, investimentos para sua ampliação devem permitir retornos ou benefícios, servindo de base para o desenvolvimento. (BURT 2001)
Com efeito, a rede não é conseqüência, apenas, das relações que de fato existem entre os atores; ela é também o resultado da ausência de relações, da falta de laços diretos entre dois atores, do que BURT (1992) chama de “buracos estruturais”. O “desenho” do tecido social apresenta-se, desse modo, como algo semelhante a um queijo suíço. Para os analistas que salientam o “fechamento da rede”, o capital social guarda relação direta e proporcional com a quantidade de cliques (ou núcleos de tríades sobrepostas) e com a intensidade dos laços fortes (ENGLE 1999).
Análise das métricas de rede possibilitaria então apontar intervenções necessárias para otimizar as interações entre os atores das redes.
Análise de Redes Sociais possibilitam, dentre outros, os seguintes benefícios para as organizações: promoção da integração da rede de pessoas participantes em atividades de negociações da empresa, identificação dos indivíduos que não compartilham seus conhecimentos; a avaliação do desempenho de um grupo de pessoas que trabalham de forma integrada, dentre outros.
Muitas práticas gerenciais habituais no cotidiano das empresas e corporações podem explorar os conceitos e mecanismos da organização em rede, melhorando a sua efetividade:
O uso primário da teoria de grafos na análise de rede é buscar identificar “importante” atores. O conceito de prestígio e centralidade busca quantificar ideias teóricas sobre a proeminência de um ator em uma rede, sumarizando as relações estruturais com os demais atores. Além disso, fornece indicadores no nível de grupo, que permite avaliar a dispersão ou desigualdade (de recursos e/ou informações) entre todos os atores da rede.
A teoria de grafos, campo da da matemática que estuda as relações entre os objetos de um determinado conjunto, fornece os mecanismos matemáticos que são base para a análise das estruturas da rede. Através do entendimento da estrutura de uma rede é possível ter insights sobre seus padrões, propriedades e indivíduos.
Um grafo é uma representação matemática de uma rede social, onde os elementos (empresas, pessoas, etc.) são representados por vértices e a relação entre os elementos são representados como arestas entre dois vértices. A ligação (aresta) pode ser direcional ou não direcional. Pode-se associar valores tanto aos nós como arestas.
# Lista de arestas, os números são identificadores dos nós
g_edgelist <- data.frame(
from = c( 1,1,2,2,3,3,5,5),
to = c( 2,3,3,5,4,5,6,7)
)
# construindo a rede a partir da lista de arestas
g <- g_edgelist %>%
as.matrix() %>%
graph.edgelist(directed = FALSE) %>% # usando igraph
as_tbl_graph() %>%
activate("nodes") %>%
mutate( name = LETTERS[1:7] ) # nomeando os nós
# calculando previamente as métricas
g <- g %>%
mutate( degree = centrality_degree(),
btwn = round( centrality_betweenness(),2 ),
clsn = round( centrality_closeness(normalized = T),2 ),
eign = round( centrality_eigen(scale = F), 2 ))
# fixando o layout previamente para todos os plots terem a mesma disposicao
g_layout <- create_layout(g, layout = "kk")
# plotando o graph
ggraph(g_layout) +
geom_edge_fan(alpha=0.3) +
geom_node_point(color="blue",alpha=0.8, size=8) +
geom_node_text(aes(label=name), color="white") +
theme_void() +
ggtitle( "Exemplo de Rede" ) +
theme( legend.position = "none" )
Há uma série de métricas e propriedades (Newmann, 2010) de um grafo que podem fornecer informações relevantes sobre a relação (arestas) entre os indivíduos (vértices) e os próprios indivíduos quando esse representa uma rede social. Iremos explorar algumas propriedades que podem estar ligadas a identificação de capital social, são elas:
O Grau (Degree) é o número de arestas (ou links) que levam para dentro ou para fora de um vértice. Freqüentemente usado como medida de conexão de um nó para outros nós imediatos. Podendo assim representar influencia e/ou popularidade de um nó juntos aos demais. Útil na avaliação de quais nós são fundamentais em relação à disseminação de informações e na capacidade influenciar outros nós na localidade imediata.
Exemplos:
# plot da rede evidenciando o degree
ggraph(g_layout) +
geom_edge_fan(alpha=0.4) +
geom_node_point(aes(color = degree), size=8) +
geom_node_text(aes(label=name),color="white") +
geom_node_text(aes(label=degree, color=degree), nudge_y = NUDGE_Y ) +
theme_graph() +
# ggtitle( "Degree" ) +
theme( legend.position = "none" )
A Betweenness Centrality é uma métrica que representa quantos caminhos curtos (shortest path) que ligam outros nó da rede, passam pelo nó em questão. Para calcular o valor para um determinado nó v, calcule o número de caminhos mais curtos entre os nós i e j que passam através de v e divida por todos os caminhos mais curtos entre i e j. Repita para todo os nós.
É uma medida importante, pois representa “o quanto” um nó, ou vértice, está dentro dos fluxos de informações possíveis entre os outros nós. Quanto mais alto o valor, maior a importância do nó, como um elo de comunicação entre os demais nós.
Esta métrica também pode ser calculada com respeito a uma aresta, assim estaríamos medindo o quanto um link entre dos nós participa dos caminhos mais curtos entre os nós da rede.
Exemplos:
# plot da rede evidenciando o betweenness
ggraph(g_layout) +
geom_edge_fan(alpha=0.4) +
geom_node_point(aes(color = btwn), size=8) +
geom_node_text(aes(label=name),color="white") +
geom_node_text(aes(label=btwn, color=btwn), nudge_y = NUDGE_Y ) +
theme_graph() +
# ggtitle( "Betweenness Centrality" ) +
theme( legend.position = "none" )
Representa o quão perto um nó está dos demais, pode ser uma medida direta da contagem de arestas ou da soma dos pesos dela. Para obtê-la calcule o comprimento médio de todos os caminhos mais curtos de um nó para todos os outros nós da rede.
É uma medida de alcance, mediria por exemplo a velocidade com informações pode alcançar outros nós a partir de um determinado nó inicial, quanto mais próximo um nó dos demais, mais rápido este nó influenciaria outros.
Exemplos:
ggraph(g_layout) +
geom_edge_fan(alpha=0.4) +
geom_node_point(aes(color = clsn), size=8) +
geom_node_text(aes(label=name),color="white") +
geom_node_text(aes(label=clsn, color=clsn), nudge_y = NUDGE_Y ) +
theme_graph() +
# ggtitle( "Closeness" ) +
theme( legend.position = "none" )
A centralidade do autovetores de um nó é proporcional à soma das centralidades de _autovetores de todos os nós diretamente conectados a ele. A métrica é obtida através da fatoração e calculo de autovetores da matriz de adjacência3 que representa a rede.
Está associado a reputação e um vértice com respeito às suas ligações.
Exemplos:
ggraph(g_layout) +
geom_edge_fan(alpha=0.4) +
geom_node_point(aes(color = eign), size=8) +
geom_node_text(aes(label=name),color="white") +
geom_node_text(aes(label=eign, color=eign), nudge_y = NUDGE_Y ) +
theme_graph() +
# ggtitle( "Eigenvector" ) +
theme( legend.position = "none" )
Um rede pode ter ser segmentada, ou seja, nós formam sub-redes não conectadas entre si, tais sub-redes são chamadas de componentes.
# montando uma lista de arestas (os números identificam o vértice)
edgelist <- data.frame(
from = c(1,1,2,4,2,3,4,5,6,6,7,7,8,8,9,10),
to = c(2,3,4,3,5,4,5,1,7,8,9,8,9,10,10,7)
)
# construindo o grafo a partid da lista de aresta
edgelist %>%
as.matrix() %>%
graph.edgelist(directed = T) %>%
as_tbl_graph() %>%
activate("nodes") %>%
mutate( name = LETTERS[1:10],
component = as.factor(group_components())) -> g
ggraph(g, layout="kk") +
geom_edge_fan(alpha=0.2, arrow = arrow(type="closed", angle=10, length = unit(5,units = "mm") ))+
geom_node_point(aes(color=component),alpha=0.8, size=8) +
geom_node_text(aes(label=name), color="white") +
theme_void() +
ggtitle( "Components" ) +
theme( legend.position = "none" )
Usando as métricas listadas acima é possível identificar e classificar a atuação e importância dos atores em uma rede.
Tome-se como exemplo esta rede:
# lista de ligacoes
h_edgelist <- data.frame(
from = c( 0, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 5, 8),
to = c(10, 10, 2, 10, 3, 4, 5, 10, 10, 6, 7, 8, 9)
) + 1
# construcao da rede
h <- h_edgelist %>%
as.matrix() %>%
graph.edgelist(directed = FALSE) %>%
as_tbl_graph() %>%
activate("nodes") %>%
mutate( name = LETTERS[1:11] ) # nomeando nos
# plot
ggraph(h, layout="kk") +
geom_edge_fan(alpha=0.2) +
geom_node_point(color="red",alpha=0.9, size=8) +
geom_node_text(aes(label=name), color="white") +
theme_void() +
ggtitle( "Exemplo" ) +
theme( legend.position = "none" )
Vamos combinar as medidas de centralidade para exibir importantes atores na estrutura.
# calculando métricas de centralidade
h <- h %>%
activate("nodes") %>%
mutate (
degree = as.factor(centrality_degree()),
btwn = round(centrality_betweenness(), 2),
clsn = round(centrality_closeness(normalized = T), 2),
eign = round(centrality_eigen(scale = T), 2),
clst = as.factor(group_edge_betweenness())) %>%
# centrality das arestas
activate("edges") %>%
mutate( ebtwn = centrality_edge_betweenness() )
ggraph(h, layout="kk") +
geom_edge_fan2(alpha=0.4, aes(edge_colour = ebtwn, label=ebtwn), label_size=3) +
geom_node_point(aes(color=degree, size=clsn),alpha=0.5) +
geom_node_text(aes(label=name), color="black") +
geom_node_text(aes(label=eign, color=degree), nudge_y = -NUDGE_Y/2, size=2) +
theme_void() +
ggtitle( "Combinando Métricas" ) +
scale_color_manual(breaks = c("1", "2","3", "5", "10"),
values=c("red","red","lightskyblue","lightskyblue","darkblue"))
As várias medidas de centralidade são mostradas acima e são representadas:
h %>% activate("nodes") %>%
as.tibble() %>%
select(-clst) %>%
knitr::kable(caption="Métricas de Centralidade dos Nós")
| name | degree | btwn | clsn | eign |
|---|---|---|---|---|
| A | 1 | 0.0 | 0.34 | 0.32 |
| B | 2 | 0.0 | 0.36 | 0.57 |
| C | 3 | 3.0 | 0.45 | 0.78 |
| D | 4 | 25.5 | 0.59 | 0.89 |
| E | 2 | 0.0 | 0.43 | 0.60 |
| F | 4 | 29.0 | 0.56 | 0.41 |
| G | 1 | 0.0 | 0.37 | 0.13 |
| H | 1 | 0.0 | 0.37 | 0.13 |
| I | 2 | 9.0 | 0.40 | 0.15 |
| J | 1 | 0.0 | 0.29 | 0.05 |
| K | 5 | 13.5 | 0.50 | 1.00 |
Através das relações entre as centralidades é possível identificar os seguintes aspectos
Combinando duas métricas de centralidade, autovetores e intermediação, é possível evidenciar dois tipos de atores específicos numa rede.
h %>% activate("nodes") %>% as_tibble() %>%
ggplot(aes(x=btwn, y=eign)) +
geom_point() + geom_label(aes(label=name)) +
theme( legend.position = "none" )
Observando a distribuição de como eigenvector fica em função betweenness, é possível observar então que o nó F atua como um Gatekeeper e o nó C como um nó de acesso a atores importantes (accessor).
# key actors type
h <- h %>%
activate("nodes") %>%
mutate( type = as.factor(case_when(
name == "F" ~ "gatekeeper",
name == "C" ~ "access to central actors",
TRUE ~ "others"
)))
# plot
ggraph(h, layout="kk") +
geom_edge_fan2(alpha=0.4, aes(edge_colour = ebtwn), label_size=3) +
geom_node_point(aes(color=type),alpha=0.9, size=8) +
geom_node_text(aes(label=name), color="white") +
geom_node_text(aes(label=eign), nudge_y = NUDGE_Y, size=3) +
theme_void() +
# ggtitle( "Gatekeeper and Accessor" ) +
scale_color_manual(breaks = c("others","gatekeeper","access to central actors"),
values=c("red","lightskyblue","darkblue"))
Podemos perceber que o nó C é o nó que “dá acesso” a nós de alta reputação (eigenvector) enquanto o nó F, é um nó de relativa baixa reputação que atua de porteiro para os nós de atua relevância (D, K, E e C).
Muitas redes consistem em módulos que estão densamente conectados, mas que estão escassamente conectados a outros módulos, a esses módulos é dado o nome de comunidade. A ideia da detecção de estrutura de comunidade é descobrir “bordas” e detectar arestas quem ligam módulos separados.
Uma estratégia é calcular a centralidade de betweenness das arestas e ir removendo gradualmente as arestas de maior pontuação, desconectando o gráfico, identificando assim as comunidades.
ggraph(h, layout="kk") +
geom_edge_fan2(alpha=0.5, aes(edge_colour = ebtwn)) +
geom_node_point(aes(color=clst),alpha=0.9, size=8) +
geom_node_text(aes(label=name), color="white") +
# ggtitle( "Community / Clusters" ) +
theme_void() +
theme( legend.position = "none" )
CRAN4 é o repositório oficial de pacotes de R, listando todos os pacotes produzido e disponibilizado gratuitamente pela comunidade de usuário e programadores. Os pacotes fornece funcionalidades adicionais ou específicas para o R e para serem utilizados devem ser copiados, instalados e carregados.
Qualquer pessoa pode desenvolver e disponibilizar pacotes, porém é mais comum que os pacotes sejam desenvolvidos por equipes de pesquisa e grupos de programadores dentro de empresas ou universidades ou que sejam um desenvolvimento que segue a dinâmica de software open source, quando o código do pacote está público e recebe contribuição de vários desenvolvedores espalhados pelo mundo.
Autores de um pacote R
O pacote publicado contém uma lista de autores, que contribuíram para construir e publicar o pacote. O objetivo desta análise entender como se organiza a rede de colaboração de autores, para isso usaremos os dados de publicação para construir uma rede, onde cada vértice da rede é um ator e uma aresta identifica um pacote em que dois (ou mais autores) colaboraram juntos.
# dados de publicacao de pacotes
pdb <- tools::CRAN_package_db()
# campo de autores dos pacotes
pbaut <- pdb$Author
# o campo de autores é uma string separada por virgula e contendo outras informações
# é necessario limpar a string e separar os nome dos atuores
aut <- pbaut %>%
str_replace_all("\\[.*?\\]", "") %>%
str_replace_all("[\\n\\t]", "") %>%
str_replace_all("\\<.*?\\>", "") %>%
str_replace_all("\\(.*?\\)", "") %>%
str_replace_all("\\(([^)]+)\\)", "") %>% # remocao
str_replace_all("\\[([^]]+)\\]", "") %>% # remocao
str_replace_all("<([^>]+)>", "") %>% # remocao
str_replace_all("\n", " ") %>% # remocao
str_replace_all("[Cc]ontribution.* from|[Cc]ontribution.* by|[Cc]ontributors", " ") %>%
str_replace_all("\\(|\\)|\\[|\\]", " ") %>% # remocao
iconv(to = "ASCII//TRANSLIT") %>% # limpeza dos caracters especiais
str_replace_all("'$|^'", "") %>% # limpeza
gsub("([A-Z])([A-Z]{1,})", "\\1\\L\\2", ., perl = TRUE) %>%
gsub("\\b([A-Z]{1}) \\b", "\\1\\. ", .) %>%
map(str_split, ",|;|&| \\. |--|(?<=[a-z])\\.| [Aa]nd | [Ww]ith | [Bb]y ", simplify = TRUE) %>%
map(str_replace_all, "[[:space:]]+", " ") %>%
map(str_replace_all, " $|^ | \\.", "") %>%
map(function(x) x[str_length(x) != 0]) %>%
set_names(pdb$Package) %>%
magrittr::extract(map_lgl(., function(x) length(x) > 1))
# conta autores por pacote
aut_list <- aut %>%
unlist() %>%
dplyr::as_data_frame() %>%
count(value) %>%
rename(name = value, packages = n)
# transforma a lista "pacote" -> [autores] em uma edge list
edge_list <- aut %>%
map(combn, m = 2) %>% # em cada pacote (map) gera uma combinacao do array de autores dois a dois
do.call("cbind", .) %>%
t() %>%
dplyr::as_data_frame() %>%
arrange(V1, V2) %>%
count(V1, V2)
# controi a rede a partir da lista de arestas
authors_network <- edge_list %>%
select(V1, V2) %>%
as.matrix() %>%
graph.edgelist(directed = FALSE) %>%
as_tbl_graph() %>% # wrapper tidygraph para o objeto igraph
activate("edges") %>%
mutate(weight = edge_list$n) %>% # resgata o peso das arestas (# de pacotes)
activate("nodes") %>%
left_join(aut_list, by="name") # nomeia os nós com os nomes dos autores
# dados de autores e arestas
total_authors <- authors_network %>% activate("nodes") %>% as.tibble() %>% nrow()
total_edges <- authors_network %>% activate("edges") %>% as.tibble() %>% nrow()
A rede construída é composta de 14533 autores que se relacionam através 72565 arestas. Dado a natureza do objeto estudado espera-se que essa rede não seja conecta integralmente, formando então componentes de colaboração entre grupos de autores distintos, vamos analisar esse aspecto.
# identifica os components
g <- authors_network %>%
activate("nodes") %>%
mutate(component = as.factor(group_components()))
# tabela components por número de autores
authors.by.components <- g %>%
activate("nodes") %>%
as.tibble() %>%
group_by(component) %>%
summarise( authors=n() ) %>%
arrange( desc(authors) )
# top 10 maiores components
knitr::kable(head(authors.by.components,10), caption = "Maiores componentes (top 10)")
| component | authors |
|---|---|
| 3 | 7279 |
| 30 | 68 |
| 33 | 50 |
| 6 | 44 |
| 22 | 35 |
| 717 | 25 |
| 69 | 24 |
| 43 | 23 |
| 46 | 23 |
| 109 | 23 |
Vamos selecionar três destes componentes para caracterizá-los: componentes 30, 33 e 7175.
sel_components <- c(30,33,717)
# plotando os components
g %>%
filter( component %in% sel_components ) %>%
ggraph(layout="auto") +
geom_edge_fan(alpha=0.2)+
geom_node_point(aes(color=component),alpha=0.8, size=2) +
theme_void()
Nota-se que os componentes possuem estruturas distintas umas das outras, vamos caracterizá-las com métricas de rede.
# para cada um do componentes escolhidos
net_metrics <- rbindlist(lapply( sel_components, function(comp){
# filtra pelo component
h <- g %>% filter( component == comp )
# calcula metricas de rede
res <- data.frame(
component = comp,
nodes = h %>% activate("nodes") %>% as.tibble() %>% nrow(),
density = round(graph.density(h, loops = F),4),
diameter = diameter(h, directed = F, unconnected = F, weights = NULL),
eccentricity = max(eccentricity(h, mode="all"))/min(eccentricity(h, mode="all"))
)
return(res)
}))
# tabela
knitr::kable(net_metrics)
| component | nodes | density | diameter | eccentricity |
|---|---|---|---|---|
| 30 | 68 | 1.0000 | 1 | 1.000000 |
| 33 | 50 | 0.0906 | 11 | 1.833333 |
| 717 | 25 | 0.2300 | 4 | 1.500000 |
Para cada um dos componentes calculamos:
Nota-se nos valores que as redes de fato são distintas nessas dimensões.
# calcula centralidades para uma rede
calcNodeMetrics <- function(net, comp){
net %>%
activate("nodes") %>%
filter( component==comp ) %>%
mutate(
degree = centrality_degree(),
btwn = round(centrality_betweenness(), 2),
clsn = round(centrality_closeness(normalized = T), 2),
eign = round(centrality_eigen(scale = T), 2),
clst = as.factor(group_edge_betweenness())
) %>%
activate("edges") %>%
mutate( ebtwn = centrality_edge_betweenness() ) %>%
return()
}
# para cada um dos componentes, faz o calculo de centralidades
netMetrics <- lapply(sel_components, function(comp) calcNodeMetrics(g,comp) )
netMetrics <- setNames(netMetrics, sel_components)
ggraph(netMetrics$`30`, layout="kk") +
geom_edge_fan2(alpha=0.2, aes(edge_colour = ebtwn)) +
geom_node_point(aes(color=btwn, size=degree),alpha=0.9) +
theme_void() %>% +
theme( legend.position = "none" ) +
ggtitle( "Componente 30" )
Numa rede totalmente conectada (densidade = 1), todos os nós e arestas tem as mesmas métricas, não é possível selecionar um (ou mais autores) como mais influente ou relação mais importante, a rede é homogênea. Este componente é composto de autores de um só pacote (rcorpora), cujo os autores não trabalharam com nenhum outro conjunto de autores.
ggraph(netMetrics$`33`, layout="kk") +
geom_edge_fan2(alpha=0.4, aes(edge_colour = ebtwn)) +
geom_node_point(aes(color=btwn, size=btwn),alpha=0.9) +
theme_void() +
theme( legend.position = "none" ) +
ggtitle( "Componente 33 - Betweenness" )
netMetrics$`33` %>%
activate("nodes") %>%
as.tibble() %>%
arrange( desc(btwn), desc(degree), desc(eign), desc(clsn) ) %>%
select(-component, -clst) %>%
head(10) %>%
knitr::kable(caption = "Autores por Betweeness (10 mais)")
| name | packages | degree | btwn | clsn | eign |
|---|---|---|---|---|---|
| Min Zhang | 3 | 10 | 744.11 | 0.33 | 0.41 |
| Xuesong Yu | 2 | 5 | 473.78 | 0.28 | 0.36 |
| Seunggeun Lee | 4 | 6 | 399.00 | 0.28 | 0.07 |
| Ying Huang | 2 | 5 | 294.50 | 0.21 | 0.04 |
| Peter B. Gilbert | 3 | 11 | 294.17 | 0.31 | 1.00 |
| Michal Juraska | 3 | 11 | 294.17 | 0.31 | 1.00 |
| Michael Wu | 2 | 6 | 294.00 | 0.24 | 0.01 |
| Dabao Zhang | 2 | 3 | 294.00 | 0.27 | 0.06 |
| Chen Chen | 2 | 5 | 259.50 | 0.22 | 0.01 |
| Youyi Fong | 6 | 6 | 237.50 | 0.24 | 0.14 |
A rede do componente 33 já é bem menos acoplada, portanto de menor densidade, é possível visualizar os autores mais bem “relacionados” e os autores que atuam com “pontes” entre os diversos nós na estrutura. Isso é reflexo de quando o autor trabalha em momentos diferentes com outros grupos de autores em pacotes diferentes.
ggraph(netMetrics$`33`, layout="kk") +
geom_edge_fan2(alpha=0.4, aes(edge_colour = ebtwn)) +
geom_node_point(aes(color=eign, size=eign),alpha=0.9) +
theme_void() +
theme( legend.position = "none" ) +
ggtitle( "Componente 33 - Eigenvector Centrality" )
netMetrics$`33` %>%
activate("nodes") %>%
as.tibble() %>%
arrange( desc(eign), desc(degree), desc(btwn), desc(clsn) ) %>%
select(-packages, -component, -clst) %>%
head(10) %>%
knitr::kable( caption="Autores por Eigenvector (10 mais)")
| name | degree | btwn | clsn | eign |
|---|---|---|---|---|
| Peter B. Gilbert | 11 | 294.17 | 0.31 | 1.00 |
| Michal Juraska | 11 | 294.17 | 0.31 | 1.00 |
| Doug Grove | 7 | 18.67 | 0.23 | 0.76 |
| Alexander R. Luedtke | 6 | 5.28 | 0.25 | 0.51 |
| An Vandebosch | 6 | 5.28 | 0.25 | 0.51 |
| Sanne Roels | 6 | 5.28 | 0.25 | 0.51 |
| Yingying Zhuang | 6 | 5.28 | 0.25 | 0.51 |
| Min Zhang | 10 | 744.11 | 0.33 | 0.41 |
| Marie Davidian | 5 | 0.11 | 0.28 | 0.37 |
| Anastasios A. Tsiatis | 5 | 0.11 | 0.28 | 0.37 |
O componente 717 tem uma estrutura mais acoplada, com uma densidade de 0,23, intermediária entre a 30 e 33, é possível observar grupos que trabalham juntos e grande autor central conectando os subgrupos.
ggraph(netMetrics$`717`, layout="kk") +
geom_edge_fan2(alpha=0.4, aes(edge_colour = ebtwn)) +
geom_node_point(aes(color=btwn, size=btwn),alpha=0.9) +
theme_void() +
theme( legend.position = "none" ) +
ggtitle( "Componente 717 - Betweenness" )
netMetrics$`717` %>%
activate("nodes") %>%
as.tibble() %>%
arrange( desc(btwn), desc(degree), desc(eign), desc(clsn) ) %>%
select(-component, -clst) %>%
head(10) %>%
knitr::kable(caption = "Autores por Betweeness (10 mais)")
| name | packages | degree | btwn | clsn | eign |
|---|---|---|---|---|---|
| Quanli Wang | 7 | 21 | 210.0 | 0.75 | 1.00 |
| Yingbo Li | 2 | 7 | 63.0 | 0.52 | 0.16 |
| Ellese Cotterill | 1 | 7 | 11.4 | 0.52 | 0.49 |
| Matt Halvorsen | 1 | 7 | 11.4 | 0.52 | 0.49 |
| Stephen J. Eglen | 1 | 7 | 11.4 | 0.52 | 0.49 |
| Tom Edinburgh | 1 | 7 | 11.4 | 0.52 | 0.49 |
| Daniel Manrique-Vallier | 1 | 3 | 6.4 | 0.47 | 0.17 |
| Jerome P. Reiter | 2 | 6 | 4.5 | 0.38 | 0.32 |
| Jingchen Hu | 2 | 6 | 4.5 | 0.38 | 0.32 |
| Hang J. Kim | 1 | 4 | 3.2 | 0.48 | 0.18 |
Podemos observar, de fato, que o autor central Quanli Wang trabalhou em 7 pacotes diferente, servindo de pontes para os vários subgrupos presente neste componente. Como ele é o único autor ligando esses subgrupos ele também é o mais bem “referenciado”.
ggraph(netMetrics$`717`, layout="kk") +
geom_edge_fan2(alpha=0.4, aes(edge_colour = ebtwn)) +
geom_node_point(aes(color=eign, size=eign),alpha=0.9) +
theme_void() +
theme( legend.position = "none" ) +
ggtitle( "Componente 717 - Eigenvector Centrality" )
netMetrics$`717` %>%
activate("nodes") %>%
as.tibble() %>%
arrange( desc(eign), desc(degree), desc(btwn), desc(clsn) ) %>%
select(-packages, -component, -clst) %>%
head(10) %>%
knitr::kable( caption="Autores por Eigenvector (10 mais)")
| name | degree | btwn | clsn | eign |
|---|---|---|---|---|
| Quanli Wang | 21 | 210.0 | 0.75 | 1.00 |
| Diana Hall | 7 | 0.0 | 0.36 | 0.72 |
| Ryan Dhindsa | 7 | 0.0 | 0.36 | 0.72 |
| Sahar Gelfman | 7 | 0.0 | 0.36 | 0.72 |
| Ellese Cotterill | 7 | 11.4 | 0.52 | 0.49 |
| Matt Halvorsen | 7 | 11.4 | 0.52 | 0.49 |
| Stephen J. Eglen | 7 | 11.4 | 0.52 | 0.49 |
| Tom Edinburgh | 7 | 11.4 | 0.52 | 0.49 |
| Jerome P. Reiter | 6 | 4.5 | 0.38 | 0.32 |
| Jingchen Hu | 6 | 4.5 | 0.38 | 0.32 |
Vamos analisar frequência de publicação por autores, excluindo autores que contribuíram apenas uma vez.
aut_list %>%
select(packages) %>%
unlist() %>%
summary()
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 1.000 1.000 1.583 1.000 102.000
Observa-se que mais de 75% (3rd Quarter) dos autores contribuíram apenas 1 vez com outros autores, para estabelecer uma rede de colaboração mais efetiva (e não apenas momentânea), vamos filtrar na rede autores que pelo menos 5 pacotes.
# obtendo a rede de colaboradores com mais de 5 publicações
h <- authors_network %>%
activate("nodes") %>%
filter( packages > 5 ) %>%
mutate( component = group_components() ) %>%
# escolhendo o maior component
filter( component == names(table(component))[which.max(table(component))] )
# dados de autores e arestas
total_authors <- h %>% activate("nodes") %>% as.tibble() %>% nrow()
total_edges <- h %>% activate("edges") %>% as.tibble() %>% nrow()
ggraph(h, layout="lgl") +
geom_edge_fan(alpha=0.1)+
geom_node_point(alpha=0.2, size=0.2) +
theme_void()
Temos então o maior componente da rede de colaboração de autores que publicaram mais de 5 pacotes com as características:
knitr::kable( data.frame(
nodes = h %>% activate("nodes") %>% as.tibble() %>% nrow(),
edges = h %>% activate("edges") %>% as.tibble() %>% nrow(),
density = round(graph.density(h, loops = F),4),
diameter = diameter(h, directed = F, unconnected = F, weights = NULL),
eccentricity = max(eccentricity(h, mode="all"))/min(eccentricity(h, mode="all"))
), caption = "Dados do Componente de Autores")
| nodes | edges | density | diameter | eccentricity |
|---|---|---|---|---|
| 283 | 2357 | 0.0591 | 21 | 1.8 |
Nesta rede, vamos então localizar e analisar os principais autores chave, usando as métricas de centralidade.
h <- h %>%
activate("nodes") %>%
mutate(
degree = centrality_degree(),
btwn = round(centrality_betweenness(), 2),
clsn = round(centrality_closeness(normalized = T), 2),
eign = round(centrality_eigen(scale = T), 2)
) %>%
activate("edges") %>%
mutate( ebtwn = centrality_edge_betweenness() )
authors <- h %>%
activate("nodes") %>%
as.tibble() %>%
arrange(desc(btwn))
knitr::kable( head(authors, 10), caption = "Principais Autores, pelo critério de betweeness. (top 10)")
| name | packages | component | degree | btwn | clsn | eign |
|---|---|---|---|---|---|---|
| Hadley Wickham | 101 | 1 | 126 | 4828.99 | 0.45 | 0.90 |
| Martin Maechler | 46 | 1 | 90 | 4758.60 | 0.43 | 0.06 |
| Jeffrey Horner | 11 | 1 | 24 | 2476.31 | 0.34 | 0.08 |
| Dirk Eddelbuettel | 46 | 1 | 81 | 2369.20 | 0.43 | 0.14 |
| Ben Bolker | 23 | 1 | 76 | 2185.32 | 0.42 | 0.08 |
| Michael Friendly | 21 | 1 | 91 | 2140.02 | 0.43 | 0.10 |
| Kurt Hornik | 59 | 1 | 68 | 2106.34 | 0.39 | 0.04 |
| Achim Zeileis | 45 | 1 | 83 | 1981.74 | 0.42 | 0.06 |
| Torsten Hothorn | 24 | 1 | 60 | 1858.60 | 0.41 | 0.05 |
| Inc | 41 | 1 | 52 | 1718.11 | 0.37 | 0.37 |
Podemos notar que a lista trás de fato, autores influentes na comunidade de desenvolvimento R, como Hadley Wickham (cientista Chefe na empresa RStudio), Martin Maechler (estatístico suíço na ETH) e Jeffrey Horner (Developer no departamento de bio estatística da universidade Vanderbuilt). Importante notar que este último, possui alto **betweeness* mas relativamente pouco grau (degree) comparado aos autores da lista.
Vamos visualizar os autores na rede.
authors_top10 <- authors[1:10,]$name
authors_top20 <- authors[11:20,]$name
h <- h %>%
activate("nodes") %>%
mutate (
rank = as.factor(
case_when(
name %in% authors_top10 ~ "top 10",
name %in% authors_top20 ~ "top 20",
TRUE ~ "others"
)
)
)
ggraph(h, layout="lgl") +
geom_edge_fan(alpha=0.1)+
geom_node_point(aes(color=rank),alpha=0.8, size=1) +
theme_void() +
scale_color_manual(breaks = c("others","top 10","top 20"),
values=c("grey","red","orange"))
Embora a visualização com todos os nós seja complicada é possível visualizar que alguns dos autores no grupo selecionado realmente atuam como “pontes” (bridges) concentrado arestas entre grupos distintos.
Uma outra análise que podemos fazer, diz respeito a identificar e avaliar os diversos clusters (comunidades) dentro da rede, ou seja, grupos de autores fortemente conectados entre si, e fracamente conectados com outros grupo de autores, podemos identificar agrupando de acordo com a centralidade de betweenness das arestas.
h <- h %>%
activate("nodes") %>%
mutate(
clst = as.factor(group_edge_betweenness())
)
clusters <- h %>%
activate("nodes") %>%
as.tibble() %>%
group_by( clst ) %>%
summarise( authors = n() ) %>%
arrange( desc(authors) )
total_clusters <- nrow(clusters)
knitr::kable( head(clusters, 10), caption = "Comunidades de Autores dentro da Rede" )
| clst | authors |
|---|---|
| 4 | 56 |
| 3 | 45 |
| 63 | 9 |
| 9 | 8 |
| 67 | 7 |
| 12 | 5 |
| 19 | 5 |
| 50 | 5 |
| 8 | 4 |
| 14 | 4 |
Encontramos 96 comunidades dentro da rede, dos quais duas se destacam pelo número de colaboradores bem acima dos demais. Vamos visualizar algumas comunidades sobre a estrutura da rede.
h <- h %>%
activate("nodes") %>%
mutate (
community = as.factor(
case_when(
clst == 4 ~ "Comunidade 4",
clst == 3 ~ "Comunidade 3",
clst == 63 ~ "Comunidade 63",
clst == 9 ~ "Comunidade 9",
TRUE ~ "Others"
)
)
)
ggraph(h, layout="lgl") +
geom_edge_fan(alpha=0.1)+
geom_node_point(aes(color=community, size=packages),alpha=0.8) +
theme_void() +
scale_color_manual(breaks = c("Comunidade 4","Comunidade 3","Comunidade 63","Comunidade 9" ,"Others"),
values=c("red","skyblue","green","orange","grey"))
Claramente podemos observar a organização dos clusters dentro da estrutura. Cada um dos clusters poderiam ser separados da estrutura e analisados à parte, aplicando novamente as métricas de centralidade para evidenciar os seus atores principais e sua dinâmica de integração.
Vimos que as técnicas de análise de rede usando métricas de centralidade são relevante para identificar os principais autores de uma rede, analisar a estrutura e identificar padrões. Particularmente em estruturas muito complexas e com muitos atores, as métricas conseguem expor à luz, padrões e comportamento embutidos na estrutura.
Além disso o carácter reproduzível da análise6 feita em R permite refinar continuamente a análise, eliminando resíduos e apurando os resultados
BURT, R. Structural Holes. University of Chicago Press, Chicago, 1992.
BURT, R. S. (. Structural holes versus network closure as social capital. (Cap. 2, pp. 31-56). New York: Aldine de Gruyter. 2001
ENGLE, S. Structural Holes and Simmelian Ties: Exploring Social Capital, Task Interdependence and Individual Effectiveness. Phd Thesis, University of North Texas, 1999.
MARTELETO, R. M. Análise de redes sociais - aplicação nos estudos de transferência da informação. Ciência da Informação, Brasília, v.30, n. 1, p. 71-81, jan./abr. 2001.
MARTELETO, Regina Maria and SILVA, Antonio Braz de Oliveira e. Redes e capital social: o enfoque da informação para o desenvolvimento local. Ci. Inf. 2004, vol.33, n.3, pp.41-49.
NEWMANN, M. Networks. Oxford University Press. April 2010.
STORCH, S.. As redes sociais já fazem parte de nosso jeito de pensar. Disponível em: http://www.intranetportal.com.br/e-gov/redessociais - Acesso em: 15 set. 2008.
WASSERMAN, S.; FAUST, K. Social network analysis: methods and applications. Cambridge: Cambridge University Press, 1994
R é uma linguagem de programação e ambiente para computação e análise estatística, de uso gratuito e que que fornece uma ampla variedade de técnicas para: modelagem linear e não-linear, testes estatísticos, análise de séries temporais, classificação, agrupamento.↩
CRAN ou Comprehensive R Archive Network é uma rede de FTP e servidores web ao redor do mundo que armazenam versões de código e documentação atualizadas para pacotes e bibliotecas para R.↩
Matriz de vértices contra vértices cuja as células indica o peso ou a ligação entre os vértices.↩
CRAN ou Comprehensive R Archive Network é uma rede de FTP e servidores web ao redor do mundo que armazenam versões de código e documentação atualizadas para pacotes e bibliotecas para R.↩
Escolhido com base no formato dos componentes e escolhendo três casos distintos.↩
Reproducible Research ou pesquisa reproduzível é a ideia de que a análise de dados e, em geral, as alegações científicas, são publicados com seus dados e código de software para que outros possam verificar as descobertas e construir sobre elas.↩