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

Abstract

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.

Introdução

Redes Sociais

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)

Vantagens Competitivas da Rede

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).

Importancia da Análise de Redes Sociais

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:

  • Gestão de Talentos: Encontrar os líderes naturais na organização;
  • Inovação: Identificar fronteiras. Garantir que a organização tenha acesso a novas idéias;
  • Colaboração: Encontrar lacunas no conhecimento dentro de grupos, ou entre organizações ou geografias. Monitorar ou medir mudanças;
  • Gestão do conhecimento: Identificar e manter conhecimentos vitais. Monitorar ou medir mudanças no conhecimento ou na troca de conhecimento;
  • Mudança Organizacional e Desenvolvimento: Encontrar líderes de opinião para iniciativas de gerenciamento de mudanças ou durante a integração após fusões e aquisições;
  • Desempenho Organizacional: Diagnosticar a coesão entre os membros da equipe e identificar conexões críticas para a melhoria.

Conceitos Chaves para Análise de Redes

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:

Degree Centrality (Grau)

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:

  • Quantas pessoas essa pessoa pode alcançar diretamente?
  • Em uma rede de músicos: com quantas pessoas essa pessoa já colaborou/tocou junto?
# 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" )

Betweenness Centrality (Intermediação)

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:

  • Qual a probabilidade de esta pessoa ser a rota mais direta entre duas pessoas na rede?
  • Me uma rede de espiões: quem é o espião pela qual a maioria das informações confidenciais pode fluir?
# 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" )

Closeness Centrality (Proximidade)

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:

  • Quão rápido essa pessoa pode alcançar todos na rede?
  • Em rede de relações sexuais: quão rápido uma DST se espalhará dessa pessoa para o resto da rede?
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" )

Eigenvector Centrality (Autovetor)

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:

  • Quão bem esta pessoa está conectada a outras pessoas bem conectadas?
  • Na rede de citações de artigos: quem é o autor mais citado por outros autores bem citados?
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" )

Componentes

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" )

Identificando Atores e Padrões

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:

  • Cor do vértice: Degree Centrality
  • Tamanho do vértice: Closeness Centrality
  • Número abaixo do vértice: Eigenvetor Centrality
  • Cor e valor na aresta: Edge Betweenness Centrality
h %>% activate("nodes") %>%
  as.tibble() %>%
  select(-clst) %>%
  knitr::kable(caption="Métricas de Centralidade dos Nós")
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

  • Nós mais conectados: K com mais conexões seguidas de D e F;
  • A ligação entre a F e D é a de maior intermediação, além disso se removida desconecta o gráfico;
  • O nó D é o mais próximo aos demais e
  • O nó K é no mais referenciado por nós mais referenciados (maior eigenvector), seguido logo por D, mais uma vez mostrando a importância do no D na estrutura da rede.

Gatekeepers & Accessors

Combinando duas métricas de centralidade, autovetores e intermediação, é possível evidenciar dois tipos de atores específicos numa rede.

  • Um ator com alta intermediação (betweenness) e baixo autovetor (eigenvector) pode ser um porteiro (Gatekeeper) importante para um ator central ou atores importantes.
  • Um ator com baixa intermediação e alto autovetor pode ter acesso exclusivo a atores centrais.
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).

Comunidades (clusters)

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" )

Rede de Colaboração de Autores no CRAN

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

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.

Construindo a Rede

# 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()

Selecionando Components

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)")
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.

Comparando os três components

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:

  • densidade: número de arestas da rede dividido pelo número de arestas possíveis;
  • diâmetro: maior menor caminho (shortest path) existente na rede e
  • excentricidade: aqui definida como o diâmetro dividido pelo menor caminho (shortest path).

Nota-se nos valores que as redes de fato são distintas nessas dimensões.

analise de atores

# 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)

Component 30

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.

Componente 33

  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)")
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)")
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

Componente 717

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)")
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)")
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

Analisando colaboração recorrente

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")
Dados do Componente de Autores
nodes edges density diameter eccentricity
283 2357 0.0591 21 1.8

Autores Chaves

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)")
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.

Comunidades

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" )
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.

Conclusã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

Referências

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


  1. 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.

  2. 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.

  3. Matriz de vértices contra vértices cuja as células indica o peso ou a ligação entre os vértices.

  4. 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.

  5. Escolhido com base no formato dos componentes e escolhendo três casos distintos.

  6. 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.