聰明不如鈍筆
총명불여둔필
assignment KindeR

R로 피처링 관계도를 그려보자(feat. tidygraph, ggraph)


'최대한 친절하게 쓴 R로 사회연결망 분석하기(feat. tidygraph, ggraph)' 포스트에는 2016년 7월부터 1년간 M 사이트 TOP 100에 등장한 음악을 가지고 그린 '피처링 관계도'를 보여드린 적이 있습니다.


우연한 기회에 사회연결망을 그려야 하는 일이 생겨서 지난해(2018년) 12월부터 올해 11월까지 같은 데이터를 긁어서 피처링 관계도를 그려보았습니다. 그리고 아래 결과를 얻었습니다.



이번 포스트에서는 이런 그래프를 어떻게 그리는지 간단하게 알아보도록 하겠습니다. '간단히'라고 쓴 건 이미 자세한 내용은 '최대한 친절하게 쓴 R로 사회연결망 분석하기(feat. tidygraph, ggraph)' 포스트에 남겼기 때문입니다. 더 궁금하신 분은 이 포스트를 참고하시면 도움을 받으실 수 있을 겁니다.


먼저 전체 코드는 이렇습니다.

#install.packages('tidyverse')
#install.packages('tidygraph')
#install.packages('ggraph')
library('tidyverse')
library('tidygraph')
library('ggraph')

feat %>%
  as_tbl_graph(directed=FALSE) %>%
  activate(nodes) %>%
  mutate(eigen = centrality_eigen(),
         group = group_infomap()) %>%
  ggraph(layout='nicely') +
    geom_edge_link(color='gray50', alpha=.2) +
    geom_node_point(aes(color=factor(group), size=eigen)) +
    geom_node_text(aes(label=name), size=3, repel=TRUE) +
    theme_graph() +
    theme(legend.position='none')


이 코드를 Ctrl+C/V하셔도 같은 그림이 나오지 않습니다. 데이터가 없기 때문. 아래 데이터를 불러들이셔야 같은 그림을 얻으실 수 있습니다. 패키지도 (설치하고) 불러오셨죠?


featuring_2019.csv


데이터를 보시면 아실 것처럼 'from', 'to' 열에 각각 뮤지션 이름이 들어 있습니다. 이런 식으로 정리한 자료만 있으면 언제든지 이런 사회관계망 그래프를 그릴 수 있습니다.

feat <- read.csv('featuring_2019.csv')
feat
## # A tibble: 314 x 2
##    from        to           
##                   
##  1 1ho         Chan         
##  2 1ho         공기남       
##  3 ASH ISLAND  Hash Swan    
##  4 ASH ISLAND  The Quiett   
##  5 ASH ISLAND  김효은       
##  6 ASH ISLAND  릴러말즈     
##  7 ASH ISLAND  창모         
##  8 B.I.        이하이       
##  9 BewhY       수퍼비       
## 10 BIG Naughty Chillin Homie
## # ... with 304 more rows


그러려면 제일 먼저 데이터 프레임을 그래프 형태로 바꿔줘야 합니다. 이때 쓰는 함수가 as_tbl_graph()입니다. 그래프에는 방향이 있을 때와 없을 때가 있는데 이번에는 방향이 없는 걸로 처리(directed=FALSE)하겠습니다.

feat2 %>%
  as_tbl_graph(directed=FALSE)
## # A tbl_graph: 102 nodes and 314 edges
## #
## # An undirected multigraph with 21 components
## #
## # Node Data: 102 x 1 (active)
##   name       
##   <chr>      
## 1 1ho        
## 2 ASH ISLAND 
## 3 B.I.       
## 4 BewhY      
## 5 BIG Naughty
## 6 C JAMM     
## # ... with 96 more rows
## #
## # Edge Data: 314 x 2
##    from    to
##    <int>  <int>
## 1     1     7
## 2     1    30
## 3     2    13
## # ... with 311 more rows


이제 진짜 그래프를 그릴 차례. 보통 그래프를 ggplot()으로 그리는 것처럼 네트워크 그래프는 ggraph()를 씁니다. 아래 코드는 선을 긋고, 점을 찍고, 이름을 표시하라는 뜻입니다. ggplot() 문법을 이미 알고 계시다면 어려울 게 없는 내용입니다.

feat %>%
  as_tbl_graph(directed=FALSE) %>%
  ggraph() +
    geom_edge_link() +
    geom_node_point() +
    geom_node_text(aes(label=name))
## Using `nicely` as default layout


문자 그대로 기본 중 기본 형태가 나왔습니다. 이제 살을 붙여 보겠습니다.


이런 그래프에는 '중심성(centrality)'이라는 개념을 적용할 수 있습니다. 일단 가장 기본적인 연결(degree) 중심성을 알아보겠습니다. 그리고 각 노드(점)가 어떤 그룹에 속해 있는지도 파악해 보도록 하시죠.


이를 알아 볼 때는 tidygraph()에 들어 있는 centrality_degree(), group_infomap() 함수를 써서 계산하고 mutate() 함수를 통해 계산 결과를 추가하면 됩니다. 그러면 아래처럼 Node에 열을 추가하는 걸 알 수 있습니다.

feat2 %>%
  as_tbl_graph(directed=FALSE) %>%
  mutate(degree = centrality_degree(),
         group = group_infomap())
## # A tbl_graph: 102 nodes and 314 edges
## #
## # An undirected multigraph with 21 components
## #
## # Node Data: 102 x 3 (active)
##   name        degree group
##   <chr>        <dbl> <int>
## 1 1ho              4     9
## 2 ASH ISLAND      10    33
## 3 B.I.             2    32
## 4 BewhY            2    42
## 5 BIG Naughty     10    34
## 6 C JAMM          10     4
## # ... with 96 more rows
## #
## # Edge Data: 314 x 2
##    from    to
##   <int> <int>
## 1     1     7
## 2     1    30
## 3     2    13
## # ... with 311 more rows


이 값을 가지고 점 색깔과 크기를 조절하는 코드는 이렇게 쓸 수 있습니다.

feat %>%
  as_tbl_graph(directed=FALSE) %>%
  mutate(degree = centrality_degree(),
         group = group_infomap()) %>%
  ggraph() +
    geom_edge_link() +
    geom_node_point(aes(color=factor(group), size=degree)) +
    geom_node_text(aes(label=name))
## Using `nicely` as default layout


확실히 나아졌습니다. 그래서 점과 점을 연결하는 선이 너무 진하다고 생각하지 않으십니까? 그래서 선 색깔을 'gray50'으로 바꾸겠습니다. 레이블도 잘 보이게 크기를 3으로 맞췄습니다. (물론 원하신다면 중심성에 따라 레이블 크기를 조절하는 것도 가능합니다.)

feat %>%
  as_tbl_graph(directed=FALSE) %>%
  activate(nodes) %>%
  mutate(degree = centrality_degree(),
         group = group_infomap()) %>%
  ggraph() +
    geom_edge_link(color='gray50') +
    geom_node_point(aes(color=factor(group), size=degree)) +
    geom_node_text(aes(label=name), size=3)
## Using `nicely` as default layout


연결 중심성은 이웃이 많을수록 그 점이 중요하다는 개념입니다. 그래서 이 그림 '메인 그룹'이 아닌데도 도드라져 보이는 노드가 존재합니다.


실제로는 이웃에 중요한 점이 많을수록 해당 점도 중요할 때가 많습니다. 이를 보여주는 지표는 고유벡터(eigenvector) 중심성입니다. 이 중심성은 centrality_eigen()을 통해 계산할 수 있습니다.


점 크기를 고유벡터 중심성 기준으로 바꾸면서 선도 투명도를 20%로 내리겠습니다. 또 레이블이 서로 겹치지 않도록 repel 속성에도 TRUE 값을 주겠습니다. (ggplot 그래프에서 레이블이 겹치는 걸 막아주는 패키지 이름도 'ggrepel'입니다.)


feat %>%
  as_tbl_graph(directed=FALSE) %>%
  activate(nodes) %>%
  mutate(eigen = centrality_eigen(),
         group = group_infomap()) %>%
  ggraph() +
    geom_edge_link(color='gray50', alpha=.2) +
    geom_node_point(aes(color=factor(group), size=eigen)) +
    geom_node_text(aes(label=name), size=3, repel=TRUE)
## Using `nicely` as default layout


이러면 거의 완성입니다. 마지막 남은 단계는 범례와 배경을 없애는 것. 범례는 위치는 theme() 안에 legend.position을 조절하면 됩니다. 또 ggraph()에는 배경을 없애는 theme_graph()라는 함수가 들어 있습니다. 이를 더하면 우리가 맨 처음에 본 코드가 됩니다.

feat %>%
  as_tbl_graph(directed=FALSE) %>%
  activate(nodes) %>%
  mutate(eigen = centrality_eigen(),
         group = group_infomap()) %>%
  ggraph(layout='nicely') +
    geom_edge_link(color='gray50', alpha=.2) +
    geom_node_point(aes(color=factor(group), size=eigen)) +
    geom_node_text(aes(label=name), size=3, repel=TRUE) +
    theme_graph() +
    theme(legend.position='none')
## Using `nicely` as default layout


그나저나 이런 그래프를 그리는 법은 이 포스트를 통해 배우시면 될 텐데 그래프 안에 들어 있는지 가수가 누군지 모를 때는 어디서 알아봐야 하는 걸까요?


그러면 여러분 모두 Happy Charting!

댓글, 6

  • 댓글 수정/삭제 녕과솜
    2020.05.12 12:05 신고

    키니님 감사합니다! 성공했어요 ㅎㅎ
    또 다른 글 참고하러 오겠습니다!

  • 댓글 수정/삭제 premier
    2020.05.29 07:11

    키니님 친절한 글 너무 감사합니다^^

    혹시 이렇게 정형화된 데이터들은 손수 만드시는 건지 궁금합니다!
    좋은 하루 되세요^^

  • 댓글 수정/삭제 커뮤니티 탐지
    2020.11.26 13:47

    안녕하세요. 항상 많은 도움 받고 있습니다. 친절한 포스트 너무 감사드려요.
    위 그래프에서 '커뮤니티 탐지' 기능을 활용하여 연결 밀도가 높은 그룹(커뮤니티)끼리 묶어서 보려면 스크립트를 어떻게 짜는게 좋을지요? igraph에도 해당 기능이 있다고 하는데 제가 R 초보라서 검색해봐도 잘 모르겠네요..ㅜㅜ

    •  수정/삭제 kini
      2020.12.17 21:42 신고

      이 그래프에서는 group에 관련 정보가 들어 있습니다.
      filter() 함수를 쓰시면 원하시는 데이터만 골라내실 수 있습니다.

account_circle
vpn_key
web

security

mode_edit
KindeR | 카테고리 다른 글 더 보기