아래 답변은 중학생도 이해할 수 있도록 쉽고 친절하게 “라플라시안(Laplacian) 행렬”이라는 개념을 차근차근 설명한 것입니다. 네트워크(그래프)에서 흔히 쓰이는 라플라시안의 기본 아이디어와 정의, 그리고 왜 중요한지를 알아보겠습니다.
우선, 그래프 또는 네트워크라는 것은 “점과 선으로 이루어진 구조”라고 생각하면 됩니다:
이렇게 점과 선으로 이루어진 구조를 그래프(네트워크)라고 부릅니다.
라플라시안 행렬은 그래프(네트워크)에서 “내 노드가 가진 연결 정보”와 “이웃 노드와 연결된 관계”를 한꺼번에 행렬로 나타낸 것입니다.
간단한 무방향(서로 연결이 양방향), 가중치가 없는(모든 선이 같음) 그래프를 예로 들어볼게요.
인접 행렬(Adjacency Matrix) (A)
차수(degree)
대각 행렬 (D)
라플라시안 (L = D - A)
쉽게 말해:
- 대각 원소( (L_{ii}) ) = “i번 노드가 가진 연결 개수”,
- 오프대각 원소( (L_{ij}) ) = “i,j가 연결되어 있으면 -1, 연결 없으면 0” (단, i≠j).
그래프에서 라플라시안은 “나와 이웃이 어떻게 연결됐는지”를 수학적으로 명확히 표현해줍니다.
이걸 통해 어떤 노드가 얼마나 연결됐는지, 이웃은 누구인지, 그리고 전체 구조가 어떤 모양으로 연결됐는지를 한 행렬로 표현할 수 있습니다.
가령 노드가 3개(1,2,3)이고, 다음처럼 연결되어 있다고 합시다:
그러면:
인접행렬 (A)는:
[
A = \begin{pmatrix}
0 & 1 & 0 \
1 & 0 & 1 \
0 & 1 & 0
\end{pmatrix}
]
대각행렬 (D)는:
[
D = \begin{pmatrix}
1 & 0 & 0 \
0 & 2 & 0 \
0 & 0 & 1
\end{pmatrix}
]
따라서 라플라시안 (L = D - A)는:
[
L = \begin{pmatrix}
1 & 0 & 0 \
0 & 2 & 0 \
0 & 0 & 1
\begin{pmatrix}
0 & 1 & 0 \
1 & 0 & 1 \
0 & 1 & 0
\begin{pmatrix}
1 & -1 & 0 \
-1 & 2 & -1 \
0 & -1 & 1
\end{pmatrix}
]
“라플라시안은 (내 노드 차수) - (연결 관계)를 요약한 행렬로서, 그래프 구조를 스펙트럴(고윳값·벡터)로 분석하게 해준다. 그래서 ‘그래프가 몇 개 덩어리인지’(연결성), ‘어떻게 잘 나눌 수 있는지’(군집), ‘희박 그래프에서 복잡한 패턴을 찾을 수 있는지’ 등을 수학적으로 알게 해주는 것”이라고 이해하면 됩니다.
중학생 수준의 설명으로 보면, “라플라시안” 은 ‘각 점이 가진 연결 개수와 이웃관계를 행렬로 간단히 표현한 것이다’ 라고 요약할 수 있어요. 그리고 이 행렬을 이용하면, 그래프가 어떤 구조를 가지고 있는지 수리적으로 분석하고, 네트워크를 분할(커뮤니티 찾기)하거나, 연결성이 떨어지는 부분(이어지지 않은 컴포넌트) 등을 찾을 수 있습니다.
아래 내용은 Saade, Krzakala, Zdeborová가 2014년에 발표한 “Spectral Clustering of Graphs with the Bethe Hessian” 논문(arXiv: 1406.1880)를 발췌한 것입니다. 이 논문은 그래프의 군집(community) 구조를 찾는 데 있어, 전통적인 인접행렬(adjacency)나 라플라시안(laplacian) 행렬 대신 Bethe Hessian(비등방적(?) 연산자인 non-backtracking operator와 관련이 있음)을 사용하는 방법을 제안합니다. 저자들은 이 Bethe Hessian이,
1) Sparse(희박) 네트워크(특히 Stochastic Block Model, SBM)에서 군집 검출 한계를 이론적으로 만족하는 성능(임계점 이하에서 군집 검출 가능),
2) 대칭 실수(symmetric, real) 행렬이 가지는 계산 효율성(메모리 이점, 고속의 선형대수 연산),
3) non-backtracking 행렬과 동일한 수준(혹은 더 나은 성능)의 군집 검출 역량,
을 모두 달성한다고 주장합니다.
아래에서는 Bethe Hessian(이른바 “deformed Laplacian”)의 정의, 원리, 수식, 그리고 왜 군집 검출에 좋으며 어떤 방식으로 non-backtracking operator와 연관되는지, 그리고 본 논문에서의 핵심 아이디어와 식(수식)을 최대한 자세하게 설명하겠습니다.
논문 저자들은 Bethe Hessian(또는 “deformed Laplacian”)이라고 불리는 대칭(실수) 행렬을 사용하면,
그래프 (G=(V,E)), 인접행렬 (A), 대각행렬 (D) (노드 차수(di)를 대각 원소로).
정규화 상수(regularizer) (r) (절댓값 (\lvert r \rvert > 1))를 잡고,
[
H(r) \;:=\; (r^2 - 1)\mathbf{I} \;-\; r\,A \;+\; D.
]
이 (\displaystyle H(r))을 "Bethe Hessian" 혹은 "deformed Laplacian"이라 부름.
결론적으로, Bethe Hessian은 스펙트럴 클러스터링 관점에서, “(non-)backtracking operator 수준의 이론 성능을, 대칭 행렬 형태로 좀 더 깔끔하게 구현”해 준다고 볼 수 있습니다. 이 접근은 다양한 실제 네트워크(정치 블로그, 돌고래 사회망, 어휘 연결망 등)에서도 좋은 성능을 보인다는 것이 논문의 핵심 주장입니다.
이상으로 논문의 주요 개념(수식, 원리, 분석)을 정리했습니다. “Bethe Hessian”이 제안된 배경(왜 non-backtracking과 연관?), 수학적 정의(식 (2), (3)), Ising-Bethe Free Energy와의 관계(9)~(10), SBM 임계점 해석, 그리고 실제 실험 결과까지 개괄적으로 살펴보았습니다.
아래 튜토리얼은 graph-tool 라이브러리에서 제공하는 laplacian 함수를 활용해, 그래프의 라플라시안(Laplacian)이나 Bethe Hessian(특정 파라미터 (r\neq 1)에서) 행렬을 생성하는 과정을 단계별로 살펴보고, 이를 실제로 파이썬에서 어떻게 구현하고 분석(예: 고윳값 스펙트럼 확인)하는지 소개합니다. 초보자도 쉽게 따라 할 수 있도록 상세한 한글 주석과 친절한 설명을 곁들였으니 참고하시기 바랍니다.
그래프의 라플라시안은 전통적으로 다음과 같이 정의됩니다:
무가중치·무방향 그래프에서,
[
L = D - A
]
정규화 라플라시안(Normalized Laplacian):
[
L_{\text{norm}} \;=\; I - D^{-\tfrac{1}{2}} \, A \, D^{-\tfrac{1}{2}}.
]
군집(clustering)·스펙트럴 방법에서 자주 쓰이는 형태.
그래프가 가중치 혹은 방향성(directed)을 가진다면, 차수나 대각 항 정의가 더 복잡하게 바뀌지만, 요지는 “노드의 연결 강도(또는 개수)만큼 자신을 보강하고, 인접노드와는 음의 값으로 연결”한다는 해석입니다.
laplacian 함수 개요graph_tool.spectral.laplacian(
g,
deg='out',
norm=False,
weight=None,
r=1.0,
vindex=None,
operator=False,
csr=True
) -> csr_matrix or LaplacianOperator
주요 파라미터
"out"): "in" : 노드 in-degree "out" : 노드 out-degree "total" : 양방향 합(= in + out) False → 일반 라플라시안 True → 정규화 라플라시안((L_{\text{norm}}))norm=False이면, 라플라시안 대신 Bethe Hessian을 반환:False → 희소 행렬(scipy.sparse) 형태 반환 True → LaplacianOperator(LinearOperator 서브클래스) 반환operator=False일 때, True이면 csr_matrix, 아니면 coo_matrix 형태반환:
csr_matrix (희소) operator=True라면 LaplacianOperator (메모리 절약·병렬화 등 장점)[
\text{Bethe Hessian: } \quad
H(r) \;=\; (r^2 - 1)\mathbf{I} \;-\; r\,A \;+\; D.
]
laplacian(g, norm=False, r!=1)로 호출하면 이 Bethe Hessian 행렬을 반환함(= “정규화 파라미터 (r)” 활용).아래 예시는:
scipy.sparse.linalg를 이용해 고윳값(eigenvalues)를 구하고 시각화# laplacian_tutorial_basic.py
import graph_tool.all as gt
import numpy as np
import scipy.sparse.linalg as spla
import matplotlib.pyplot as plt
def main():
# 1) 그래프 로드: polblogs (정치 블로그 네트워크)
g = gt.collection.data["polblogs"]
# 라플라시안(기본=비정규화, operator=True => LinearOperator 반환)
L_op = gt.laplacian(g, operator=True, norm=False)
# 노드 수
N = g.num_vertices()
# 2) 고윳값 계산: LR (largest real), SR (smallest real)
# N//2개는 큰 부분, 나머지는 작은 부분
ew1 = spla.eigs(L_op, k=N//2, which="LR", return_eigenvectors=False)
ew2 = spla.eigs(L_op, k=N - N//2, which="SR", return_eigenvectors=False)
# 고윳값 합치기
ew = np.concatenate([ew1, ew2])
# 3) 시각화
plt.figure(figsize=(8, 2))
plt.scatter(np.real(ew), np.imag(ew),
c=np.sqrt(np.abs(ew)), alpha=0.6, edgecolors='none')
plt.xlabel(r"Re($\lambda$)")
plt.ylabel(r"Im($\lambda$)")
plt.title("Laplacian Spectrum (un-normalized)")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()
g = gt.collection.data["polblogs"] gt.laplacian(g, operator=True, norm=False) operator=True -> 반환값은 LaplacianOperator(LinearOperator). 메모리 절감 + 병렬 곱셈 지원. spla.eigs(L_op, k=..., which="LR"/"SR") # laplacian_tutorial_norm_bethe.py
import graph_tool.all as gt
import numpy as np
import scipy.sparse.linalg as spla
import matplotlib.pyplot as plt
def main():
g = gt.collection.data["polblogs"]
N = g.num_vertices()
# (A) 정규화 라플라시안
L_norm_op = gt.laplacian(g, norm=True, operator=True)
ew1_norm = spla.eigs(L_norm_op, k=N//2, which="LR", return_eigenvectors=False)
ew2_norm = spla.eigs(L_norm_op, k=N - N//2, which="SR", return_eigenvectors=False)
ew_norm = np.concatenate([ew1_norm, ew2_norm])
plt.figure(figsize=(8,2))
plt.scatter(np.real(ew_norm), np.imag(ew_norm),
c=np.sqrt(np.abs(ew_norm)), alpha=0.6)
plt.xlabel(r"Re($\lambda$)")
plt.ylabel(r"Im($\lambda$)")
plt.title("Normalized Laplacian Spectrum")
plt.tight_layout()
plt.show()
# (B) Bethe Hessian (r != 1, norm=False)
# 예: r=2.0 (임의로)
L_bethe_op = gt.laplacian(g, norm=False, operator=True, r=2.0)
ew1_b = spla.eigs(L_bethe_op, k=N//2, which="LR", return_eigenvectors=False)
ew2_b = spla.eigs(L_bethe_op, k=N - N//2, which="SR", return_eigenvectors=False)
ew_b = np.concatenate([ew1_b, ew2_b])
plt.figure(figsize=(8,2))
plt.scatter(np.real(ew_b), np.imag(ew_b),
c=np.sqrt(np.abs(ew_b)), alpha=0.6)
plt.xlabel(r"Re($\lambda$)")
plt.ylabel(r"Im($\lambda$)")
plt.title("Bethe Hessian Spectrum (r=2.0)")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()
laplacian(g, norm=True, ...)laplacian(g, norm=False, r=2.0, operator=True)in, out, or total "out" default. EdgePropertyMap norm=False일 때, r != 1이면 Bethe Hessian으로 간주. operator=True → 반환이 LaplacianOperator(LinearOperator). scipy.sparse.linalg 연산과 호환. operator=False → csr_matrix 또는 coo_matrix (희소행렬). True → csr_matrix, False → coo_matrix.laplacian(g, ...) 함수는 그래프의 (정규화) 라플라시안이나, 특정 파라미터 (r\neq 1)일 때 Bethe Hessian(“deformed Laplacian”) 행렬을 만들어주는 중심 도구입니다.norm=True → 정규화 라플라시안r != 1 & norm=False → Bethe Hessianoperator=True → 메모리 효율적 LinearOperator (병렬 지원)이처럼 graph-tool의 laplacian 함수는 간단한 호출을 통해서도 다양한 라플라시안 계열 행렬을 빠르게 만들고, scipy.sparse.linalg를 이용한 스펙트럴 연산을 쉽게 접목할 수 있게 해줍니다. 도시·교통 빅데이터나 대규모 네트워크를 다룰 때, “부분 고윳값”을 효율적으로 구하기 위해 operator=True 모드를 자주 활용할 수 있다는 점도 기억해 두면 좋겠습니다.
즐거운 네트워크 분석 되세요!
아래 튜토리얼은 graph-tool 라이브러리의 spectral.incidence 함수를 사용해, 그래프의 인시던스(incidence) 행렬을 만들어보고 분석(예: 특이값 분해)하는 방법을 단계별로 살펴봅니다. 초보자를 위해 최대한 친절하게 파이썬 코드, 한글 주석을 상세히 포함했으며, 인시던스 행렬이 무엇이고 어떻게 해석되는지도 함께 설명합니다.
그래프에는 노드(정점)와 간선이 있습니다.
인시던스 행렬은 그래프의 노드와 간선 간의 “연결(incidence)” 정보를 행렬 형태로 나타낸 것입니다.
이를 이용하면, 그래프의 구조를 노드(\leftrightarrow)간선 “누가 누구와 연결되었는가” 관점에서 파악할 수 있게 됩니다.
graph_tool.spectral.incidence 문서에서:
무방향 그래프:
[
B_{v,e} =
\begin{cases}
1 & \text{if edge } e \text{는 노드 } v \text{와 incident(연결)},\
0 & \text{otherwise}.
\end{cases}
]
방향 그래프:
[
B_{v,e} =
\begin{cases}
1 & \text{if } e \text{는 } v \text{로 incoming}, \
-1 & \text{if } e \text{는 } v \text{에서 outgoing}, \
0 & \text{otherwise}.
\end{cases}
]
즉, 열 하나(간선 (e))가 특정 노드 (v)와 어떤 관계인지 “+1, -1, 0”으로 표현.
graph_tool.spectral.incidence(
g,
vindex=None,
eindex=None,
operator=False,
csr=True
) -> csr_matrix or IncidenceOperator
False → 희소행렬(scipy.sparse) 반환 True → IncidenceOperator(LinearOperator) 형태 반환(메모리 절약, 병렬 연산 가능)True & operator=False일 때, csr_matrix 형태 coo_matrix.아래 예시는 graph-tool에 내장된 “political blogs” (정치 블로그) 그래프를 불러온 뒤, 인시던스 행렬을 생성하고, scipy.sparse.linalg.svds(부분 특이값 분해)로 특이값을 계산한 뒤 시각화하는 예입니다.
# incidence_tutorial.py
import graph_tool.all as gt
import numpy as np
from scipy.sparse.linalg import svds
import matplotlib.pyplot as plt
def main():
# 1) 샘플 그래프 로딩: "polblogs"
g = gt.collection.data["polblogs"]
# 2) 인시던스 행렬 생성
# - operator=True => IncidenceOperator (LinearOperator) 반환
# - operator=False => 실제 희소행렬(scipy.sparse) 반환
B_op = gt.incidence(g, operator=True)
# 노드 수, 간선 수
N = g.num_vertices()
M = g.num_edges()
print("Num vertices =", N, "Num edges =", M)
# 3) 특이값(singular values) 계산
# - svds: 부분 특이값 분해
# - which="LM" => 큰 값부터?
# - which="SM" => 작은 값부터?
# => tutorial 문서 예시
s1 = svds(B_op, k=N//2, which="LM", return_singular_vectors=False)
s2 = svds(B_op, k=N - N//2, which="SM", return_singular_vectors=False)
s = np.concatenate((s1, s2))
s.sort()
# 4) 시각화
plt.figure(figsize=(8, 2))
plt.plot(s, "s-", alpha=0.7, markeredgecolor='none')
plt.xlabel(r"Index")
plt.ylabel(r"Singular value $\sigma_i$")
plt.title("Incidence matrix singular values for polblogs")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()
g = gt.collection.data["polblogs"] B_op = gt.incidence(g, operator=True) operator=True → IncidenceOperator(LinearOperator) → 대형 그래프에서 메모리 효율, 병렬 곱셈 지원. svds(...)로 특이값 분해(SVD) s를 정렬 후 플롯 vindex, eindex vindex[node] = ..., eindex[edge] = ...로 커스텀 인덱스.operator (bool) True → IncidenceOperator(LinearOperator), 메모리 절감 + 병렬 곱셈 False → 실제 희소 행렬(scipy.sparse.csr_matrix or coo_matrix)csr (bool) True & operator=False이면 csr_matrix 리턴, coo_matrix.incidence 함수는 그래프의 노드-간선 관계를 행렬(혹은 연산자)로 반환. operator=True 옵션을 주면 큰 그래프 처리 시 효율적(병렬·메모리). 인시던스 행렬은 “노드 ↔ 간선” 연결 정보를 2차원 매트릭스로 표현한 것. 특이값 분해를 통해 그래프 구조적 특성을 파악하거나, 네트워크 해석(connectedness, cycle space 등)에 활용할 수 있습니다.
operator=True + svds” 방식으로 부분 특이값만 빠르게 구해, 그래프 특성을 요약 가능. 위 아이디어들을 확장해보면, 인시던스 행렬을 다양한 그래프 알고리즘(회로망, 흐름, 커트셋, 주기(cycle) 탐색 등)에 적용할 수 있습니다. 즐거운 그래프 분석 되세요!
아래는 Stochastic Matrix(확률 행렬)에 대한 위키백과 영문 글 일부를 발췌한 내용을 한글로 꼼꼼히 설명하고, 필요한 수식/개념/원리에 집중하여 최대한 자세하고 친절하게 정리한 것입니다. (소제목, 내용, 식, 개념적 해설 포함)
스토캐스틱 행렬(확률 행렬)은 마코프 체인(Markov chain)의 전이(transition)를 나타내는 정방행렬입니다. 즉, 행렬의 각 원소가 모두 음이 아닌 확률(0 이상 1 이하)을 나타내고, 보통 각 행(혹은 열)의 합이 1이 되도록 정의합니다.
이 글(원본)에서는 주로 “right stochastic matrix(행 합=1)” 기준으로 설명합니다.
마코프 체인을 생각하면, 상태공간 (S)가 (n)개(유한)라고 하자. “상태 i에서 j로 가는 확률”을 (P_{i,j})라고 할 때, 전이행렬 (P)는:
[
P =
\begin{pmatrix}
P{1,1} & P{1,2} & \cdots & P{1,j} & \cdots & P{1,n} \
P{2,1} & P{2,2} & \cdots & P{2,j} & \cdots & P{2,n} \
\vdots & \vdots & \ddots & \vdots & \ddots & \vdots \
P{i,1} & P{i,2} & \cdots & P{i,j} & \cdots & P{i,n} \
\vdots & \vdots & \ddots & \vdots & \ddots & \vdots \
P{n,1} & P{n,2} & \cdots & P{n,j} & \cdots & P{n,n}
\end{pmatrix}
]
그리고
[
\sum{j=1}^{n} P{i,j} = 1 \quad (\text{각 i마다})
]
이는 “한 상태 i에서 가능한 모든 j로 전이 확률을 다 합하면 1”이 됨을 의미한다.
원문에서 나온 예시:
“직관적으로, 스토캐스틱 행렬은 ‘확률 분포를 또 다른 확률 분포로 바꿀 때’ 사용하는 선형 변환. 따라서 한 번, 두 번, k번 연속 곱해가며, ‘장기 상태’를 찾으면 그게 바로 ‘stationary distribution’이 된다.”
이상으로, 위키백과 내용을 바탕으로 스토캐스틱 행렬(확률 행렬)에 관한 개념, 역사, 성질, 응용을 상세히 정리했습니다.
아래 튜토리얼은 graph-tool 라이브러리에서 제공하는 transition 함수를 사용해, 그래프(네트워크)의 전이 행렬(transition matrix) 을 생성하고, 이를 활용해 간단한 스펙트럴(고윳값) 분석을 시도하는 예시 코드와 함께 자세한 한글 설명을 제공하는 가이드입니다.
전이 행렬(transition matrix) 은 일종의 “확률 행렬(stochastic matrix)” 개념을 그래프에 적용한 것으로서, 각 노드(정점)에서 이웃 노드로 이동하는 확률을 나타냅니다.
정의상, 전이 행렬 (T)는 확률(스토캐스틱) 행렬이 되므로, 마코프 체인(Markov chain) 해석에서 “노드 간 전이 확률”로 해석할 수 있습니다.
아래와 같이 표현할 수 있습니다.
[
T{ij} =
\begin{cases}
\frac{A{ij}}{di}, & \text{(노드 i의 차수가 }d_i \text{, } A{ij}=1 \text{면 이웃)}\
0, & \text{(연결 없음)}
\end{cases}
]
graph-tool에서 transition(...) 함수는 위 개념을 자동으로 계산해, 전이 확률행렬(혹은 해당 연산자)을 만들어 줍니다.
transition(g, weight=None, vindex=None, operator=False, csr=True)graph_tool.spectral.transition(
g,
weight=None,
vindex=None,
operator=False,
csr=True
) -> csr_matrix or TransitionOperator
g (Graph)
weight (EdgePropertyMap, optional)
vindex (VertexPropertyMap, optional)
operator (bool)
False면 희소행렬(scipy.sparse) 반환 True면 TransitionOperator(LinearOperator). 메모리 절약 + 병렬 연산 가능.csr (bool)
operator=False일 때, True면 csr_matrix, 아니면 coo_matrix 반환.csr_matrix or TransitionOperator).다음은 graph-tool에 내장된 정치 블로그("polblogs") 그래프를 불러와 전이 행렬을 생성하고, 이를 이용해 부분 고윳값(또는 eigs)을 구해 시각화하는 예시입니다.
# transition_tutorial.py
import graph_tool.all as gt
import numpy as np
import scipy.sparse.linalg as spla
import matplotlib.pyplot as plt
def main():
# 1) 샘플 그래프 로딩: "polblogs" (정치 블로그 네트워크)
g = gt.collection.data["polblogs"]
# 2) 전이 행렬 생성
# - operator=True => TransitionOperator 반환(LinearOperator)
# - operator=False => 실제 희소행렬(sc.sparse)의 csr 또는 coo
T_op = gt.transition(g, operator=True)
# 노드 수
N = g.num_vertices()
print("Number of vertices:", N)
# 3) 고윳값(eigenvalues) 계산
# - which="LR": real part가 큰 것부터 k개
# - which="SR": real part가 작은 것부터 k개
# => 스펙트럼 대략 살피기 위해 각 절반씩 구해 합침
ew1 = spla.eigs(T_op, k=N//2, which="LR", return_eigenvectors=False)
ew2 = spla.eigs(T_op, k=N - N//2, which="SR", return_eigenvectors=False)
ew = np.concatenate((ew1, ew2))
# 4) 시각화
plt.figure(figsize=(8, 2))
plt.scatter(np.real(ew), np.imag(ew),
c=np.sqrt(np.abs(ew)), alpha=0.6, edgecolors='none')
plt.xlabel("Real part of eigenvalue")
plt.ylabel("Imag part of eigenvalue")
plt.title("Transition matrix spectrum (polblogs)")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()
"polblogs" 그래프 로드gt.transition(g, operator=True): 전이 연산자(TransitionOperator)를 생성scipy.sparse.linalg.eigs(...)로 부분 고윳값 계산(‘LR’ + ‘SR’)확률 행렬(스토캐스틱)
최대 고윳값 = 1
PageRank나 임의 랜덤워크
스펙트럼에서
transition 함수는 그래프(무방향·유향·가중치 포함)의 랜덤워크 전이행렬을 쉽게 생성.“전이행렬은 그래프에서 이웃으로 이동할 확률을 나타내는 스토캐스틱 행렬로, 마코프 체인 관점에서 노드 분포가 어떻게 변하는지 분석하는 핵심 도구.”**
T에서 (\pi) s.t. (\pi T = \pi) 이상으로 transition 함수를 이용해 그래프의 전이행렬을 생성·분석하는 방법과 예시 코드를 살펴보았습니다. 현업에서 무작위 랜덤워킹(교통흐름, 사용자 이동, 통신 패킷 경로 등) 모델링 시, 네트워크 전이행렬을 자주 사용하게 됩니다. 그런 경우 graph_tool의 transition 함수를 손쉽게 활용하면 됩니다.
즐거운 네트워크 분석 되세요!
아래 튜토리얼은 graph-tool 라이브러리에서 제공하는 modularity_matrix 함수를 사용해, 네트워크의 모듈러리티(modularity) 행렬을 생성하고, 이를 토대로 스펙트럴(고윳값) 분석 등을 시도하는 방법을 단계별로 소개합니다. 초보자도 쉽게 따라 할 수 있도록 한글 주석과 자세한 설명을 충분히 포함했습니다.
Newman의 논문([newman-modularity])에서 제시된 바에 따르면, 모듈러리티 행렬은
[
B = A - \frac{k \cdot k^T}{2m}
]
형태로 정의하는 경우가 많습니다.
graph-tool의 modularity_matrix 함수는 내부적으로 위와 유사한 식(수식에서 (\frac{k_i k_j}{\sum k}) 형태)을 적용해 모듈러리티 행렬을 생성하며, 결과물을 LinearOperator 형태로 반환합니다(희소행렬 대신).
graph_tool.spectral.modularity_matrix(
g,
weight=None,
vindex=None
) -> LinearOperator
Graph).EdgePropertyMap (간선 가중치). 없다면 무가중치(=1).VertexPropertyMap으로 행/열에서 노드 순서를 지정할 수 있음. 기본은 내부 인덱스 사용.B, 즉 모듈러리티 행렬을 표현하는 LinearOperator(sparse 형태).(\textbf{Note}):
modularity_matrix함수는 희소행렬(scipy.sparse)이 아니라LinearOperator객체로 반환합니다. 내부적으로 곱셈 연산을 정의해서, 큰 그래프도 효율적으로 처리할 수 있도록 되어 있습니다.
아래 예제에서는 graph-tool에 내장된 "polblogs" (정치 블로그) 그래프를 사용, 모듈러리티 행렬을 구한 후, 부분 고윳값을 계산해 스펙트럼(실수·허수부) 시각화까지 보여줍니다.
# modularity_matrix_tutorial.py
import graph_tool.all as gt
import numpy as np
import scipy.sparse.linalg as spla
import matplotlib.pyplot as plt
def main():
# 1) 예시 그래프 불러오기: "polblogs"
g = gt.collection.data["polblogs"]
N = g.num_vertices()
# 2) 모듈러리티 행렬 생성
# - 함수가 LinearOperator 객체로 반환
B_op = gt.modularity_matrix(g, weight=None, vindex=None)
# 3) 고윳값(eigenvalues) 계산
# - which="LR": 실수부가 큰 고윳값부터 k개
# - which="SR": 실수부가 작은 고윳값부터 k개
# => 두 가지를 합쳐 전체 스펙트럼을 대략 얻어봄
ew1 = spla.eigs(B_op, k=N//2, which="LR", return_eigenvectors=False)
ew2 = spla.eigs(B_op, k=N - N//2, which="SR", return_eigenvectors=False)
ew = np.concatenate((ew1, ew2))
# 4) 시각화
plt.figure(figsize=(8, 2))
plt.scatter(np.real(ew), np.imag(ew),
c=np.sqrt(np.abs(ew)), alpha=0.6, edgecolors='none')
plt.xlabel(r"Re($\lambda$)")
plt.ylabel(r"Im($\lambda$)")
plt.title("Modularity matrix spectrum (polblogs)")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()
g = gt.collection.data["polblogs"]: gt.modularity_matrix(...): weight=None → 무가중치(=1). B_op (LinearOperator).scipy.sparse.linalg.eigs(B_op, ...)로 고윳값 계산. 모듈러리티 행렬 (B)는 네트워크가 커뮤니티 구조를 얼마나 갖고 있는지 스펙트럴 방식으로 분석하는 도구:
LinearOperator 형태로 제공 -> 대규모 그래프도 메모리 부담 덜고, 필요한 연산(곱셈, 부분 고윳값)을 효율적으로 수행.[
B{ij} = A{ij} - \frac{k_i k_j}{2m}
]
minimize_blockmodel_dl등 다른 내부 알고리즘도 있으니 상황에 따라 적절히 사용 가능.operator=True: B를 전부 만들지 않고, 행렬-벡터 곱등만 정의하여, 큰 그래프에서도 효율적. weight: modularity_matrix 함수: 모듈러리티 기반 스펙트럴 분석 용도의 행렬(LinearOperator)을 생성. operator=True로 반환된 B를 직접 곱 연산 통해 효율적으로 고윳값/벡터 추정 가능.“모듈러리티 행렬”은 네트워크 군집 탐색에서 역사적으로 중요한 방법론이며, graph-tool이 이를 Lazy(LinearOperator) 방식으로 다룬다는 점이 실무나 대규모 그래프 분석에 큰 장점이 될 수 있습니다.
즐거운 네트워크 분석 되세요!