R의 SNA 생태계 — 네 패키지의 역할 분담

R의 SNA 생태계 — 네 패키지의 역할 분담

R 실습 — 손으로 돌려 보기STAGED+ 스터디

1.1 누가 무엇을 맡는가 (Division of Labor)

R에서 네트워크를 다루는 패키지는 두 계보로 갈린다. 이 사실을 모르고 시작하면 반드시 헤맨다.

statnet 계보 독립 sna 사회학 지표 273개 ergm 통계 모형 network 자료구조 — 네트워크를 담는 그릇 위 둘이 이 그릇 위에서 돈다 igraph 그릇과 알고리즘을 자기 안에 다 가진다 커뮤니티 탐지 · k-코어 무작위 그래프 모형 대신 igraph 전용 객체만 받는다 intergraph asIgraph() / asNetwork() — 속성까지 같이 옮긴다
두 계보는 객체가 다르다. 그래서 오갈 때마다 번역기가 필요하다. "그럼 igraph만 쓰면 되지 않나?"는 1.2에서 답한다.
패키지계보맡는 일
networkstatnet자료구조. 분석 함수는 거의 없다. 네트워크를 담는 그릇(network 객체)을 정의하고, 정점·간선에 속성을 붙이는 일을 한다. snaergm이 이 그릇 위에서 돌아간다.
snastatnet사회학 전통의 분석 도구. 함수 273개. 중심성, 블록모델링, QAP 검정 등 사회학 문헌에 나오는 지표가 강하다. 인접행렬(matrix)을 그대로 받아 준다는 게 큰 장점.
igraph독립그래프 이론·전산 전통의 분석 도구. C로 짜여 빠르고, 커뮤니티 탐지·k-코어·무작위 그래프 모형이 압도적으로 풍부하다. 대신 igraph 전용 객체만 받는다.
intergraph다리번역기. asIgraph() / asNetwork() 두 함수가 사실상 전부다. 속성까지 같이 옮겨 준다.

1.2 그럼 igraph만 쓰면 되지 않나?

위 그림만 보면 igraph 혼자 그릇과 알고리즘을 다 가졌으니, 나머지 셋은 군더더기처럼 보인다. 실제로 기술 통계까지는 igraph만으로 된다 — 중심성, 밀도, 커뮤니티 탐지, 그림까지 전부. 그런데 사회과학 분석은 네 지점에서 igraph만으로는 막히고, 거기가 statnet 계보를 같이 켜는 이유다.

막히는 지점왜 statnet 쪽이 필요한가
① 사회학 전통 기법블록모델링·구조적 등위(equiv.clust, blockmodel), QAP 검정(qaptest, netlogit), 중개 역할 분석(brokerage)은 igraph에 구현 자체가 없다. "지위가 비슷한 학생 묶음은 어디인가"(블록모델링), "친교 관계와 도움 관계는 겹치는가"(QAP) 같은 질문의 답이 여기에 있다.
② 통계 모형(ERGM)"동성이면 친구일 확률이 유의하게 높은가"를 검정하는 ergm()은 statnet 계보라 network 그릇만 받는다. 기술 통계에서 추론 통계로 넘어가는 순간 igraph 객체로는 못 간다.
③ 문헌 재현같은 지표라도 정규화 방식·비연결 그래프 처리 같은 기본값이 계보마다 달라 수치가 다르게 나올 수 있다. 사회학 교재·논문(Wasserman–Faust 계열)의 옵션 체계(gmode=, cmode=)와 1:1로 맞는 쪽은 sna다. 논문 수치를 재현·대조하려면 그 논문이 쓴 구현이 필요하다.
④ 행렬 입출력교실 소시오메트리 명부는 인접행렬로 오간다. sna는 matrix를 그대로 받지만 igraph는 매번 전용 객체로 변환해야 한다. 행렬 연산과 병행하는 빠른 확인에는 sna가 덜 번거롭다.

반대 방향도 성립한다. 커뮤니티 탐지·k-코어·대규모 처리 속도는 igraph가 압도적이라 statnet만으로도 안 된다. 어느 쪽도 상대의 부분집합이 아니다.

그래서 실무는 "하나를 고른다"가 아니라 "둘 다 켜 두고 필요한 쪽 함수를 쓴다"이다. 이 스터디도 그렇다 — 기술 통계와 커뮤니티 탐지는 igraph로 가고, 구조적 등위(이론 3단계)와 QAP·ERGM(이론 5단계)은 sna·ergm으로 간다. 그리고 두 계보의 객체가 다르므로 번역기 intergraph가 반드시 따라온다. 넷을 같이 켜는 대가가 바로 다음 절의 이름 충돌이다.
install.packages(c("network", "sna", "igraph", "intergraph"))

library(network)     # 자료구조
library(sna)         # 사회학 지표
library(igraph)      # 그래프 알고리즘
library(intergraph)  # 변환

이 프로젝트에 깔린 판본: network 1.20, sna 2.8, igraph 2.3.3, intergraph 2.0.4, ergm 4.12 (R 4.5.1).

1.3 가장 먼저 부딪히는 벽: 이름 충돌 (Function Masking)

위 순서로 패키지를 켜면 콘솔에 이런 경고가 쏟아진다.

The following objects are masked from 'package:sna':
    betweenness, bonpow, closeness, components, degree,
    dyad.census, evcent, hierarchy, is.connected, neighborhood,
    triad.census

같은 이름의 함수가 양쪽에 다 있다. 나중에 켠 igraph가 sna를 가려서(mask), 그냥 degree()라고 쓰면 igraph 것이 불린다. 문제는 두 함수의 인자 이름이 서로 다르다는 점이다.

closeness(adj, cmode = "suminvdir")
Error in closeness(adj, cmode = "suminvdir") :
  unused argument (cmode = "suminvdir")

교재대로 썼는데 에러가 난다. 코드가 틀린 게 아니라 다른 패키지의 함수가 불린 것이다. sna는 cmode=, igraph는 mode=를 쓴다.

해결책은 하나뿐이다 — 항상 네임스페이스를 붙여 쓴다.
sna::closeness(adj, gmode = "digraph", cmode = "suminvdir")   # ✔ 확실
igraph::closeness(g, mode = "out")                            # ✔ 확실
closeness(adj, cmode = "suminvdir")                           # ✘ 어느 쪽인지 모름

conflicts.policy 옵션은 경고만 없애 줄 뿐, 어느 함수가 불릴지는 바꾸지 않는다. 경고를 껐다고 문제가 사라진 게 아니다.

충돌하는 이름 중 초보자가 실제로 자주 쓰는 것: degree, closeness, betweenness, evcent, components, dyad.census, triad.census, neighborhood. 이 여덟 개는 예외 없이 ::를 붙이는 습관을 들이는 게 제일 싸게 먹힌다.