아래 튜토리얼은 (\texttt{graph_tool.generation.generate_knn}) 함수가 어떤 역할을 하고, 내부적으로 어떤 수학적 개념·원리를 사용해 네트워크를 생성하는지를 친절하고 자세하게 설명합니다. 또한, 실제 파이썬 예제 코드와 함께, 중요한 매개변수와 인자에 대한 상세한 주석을 포함합니다.
(\textbf{k-Nearest Neighbors(최근접 k개 이웃)}) 그래프는, 주어진 (N)개의 데이터(또는 점들) 각각에 대해, “가장 가까운 k개의 점들과 연결”하는 방식으로 만들어진 그래프입니다. 이를 통해,
(\texttt{generate_knn}) 함수는 이러한 k-최근접이웃 그래프를 자동으로 만들어줍니다. 더 구체적으로,
1. 입력: 점들의 좌표(또는 점들 사이의 거리함수), (k)값 등.
2. 출력:
(\texttt{graph_tool.generation.generate_knn(points, k, dist=None, ...)})
points
k
dist (기본값: None)
pairs (기본값: False)
exact (기본값: False)
r, max_rk, epsilon, c_stop, max_iter
max_rk: 반복 과정에서 고려할 임의 이웃의 최대 개수. epsilon: 수렴 판정 기준(이웃 집합 변동이 일정 기준 미만이 되면 중단). c_stop=True이면, global clustering coefficient(글로벌 클러스터링 계수)가 더 이상 증가하지 않을 때 중단. max_iter: 최대 반복 횟수 (0이면 제한 없음).directed (기본값: False)
리턴:
w[e]로 해당 간선 e의 거리(distance) 얻을 수 있음.epsilon 이하 등) 스톱.import numpy as np
import graph_tool.all as gt
import matplotlib.pyplot as plt
def demo_generate_knn():
# 1) 임의로 N=50, d=2차원 데이터를 생성
points = np.random.random((50, 2))
# 2) k-최근접 이웃 그래프 생성
k = 5
g, w = gt.generate_knn(
points,
k=k,
dist=None, # None => 유클리디안 거리
pairs=False, # False => 각 노드마다 k=5개 이웃
exact=False, # 근사 방식; True면 정확하지만 느림
r=0.5,
epsilon=1e-3,
directed=False
)
# g: kNN 그래프, w[e]: 간선 e의 거리값
print("[INFO] # of vertices:", g.num_vertices())
print("[INFO] # of edges:", g.num_edges())
# 3) 시각화
# (a) 점의 좌표 => vertex_positions : (vertex->(x,y)) PropertyMap
pos_map = g.new_vertex_property("vector<double>")
for i, v in enumerate(g.vertices()):
pos_map[v] = (points[i,0], points[i,1])
# (b) graph_draw로 그려보기
# - kNN 특성상, 각 점은 최대 k개 선이 연결됨
gt.graph_draw(g, pos=pos_map, edge_pen_width=1.0,
vertex_size=5, output_size=(400,400),
vertex_fill_color="blue",
output=None) # output="knn_demo.png" 하면 파일로 출력
# 4) 간선 거리값 살펴보기
distances = [w[e] for e in g.edges()]
print(f" Min distance: {min(distances):.4f}")
print(f" Max distance: {max(distances):.4f}")
print(f" Avg distance: {np.mean(distances):.4f}")
if __name__ == "__main__":
demo_generate_knn()
def custom_dist(i, j):
"""
사용자 정의 거리 예시:
- 만약 points가 전역 변수에 있다면, i,j 인덱스 바탕으로
좀 더 복잡한 거리 계산 가능(예: 맨해튼, 코사인 유사도 등).
- 여기서는 단순 예시로, i+j의 절댓값 차...
"""
return abs(i - j) * 0.5
def demo_generate_knn_custom():
N = 10 # 총 10개 점(혹은 노드)이 있다고 치자
# 'points' 인자를 int(N)으로 줌
# -> dist(i,j)로 거리를 계산
k = 3
g, w = gt.generate_knn(
points=N,
k=k,
dist=custom_dist,
pairs=False,
exact=True # 정확 모드로
)
print("[INFO] # of vertices:", g.num_vertices())
print("[INFO] # of edges:", g.num_edges())
# 간선 distance 출력
for e in g.edges():
dval = w[e]
print(f"Edge {int(e.source())}-{int(e.target())}, dist={dval:.4f}")
dist(i,j) 함수를 정의해서 임의 거리 체계를 구성할 수 있음.문서에 적힌 참고문헌
이와 같이 (\texttt{graph_tool})의 (\texttt{generate_knn}) 함수는, 대규모/고차원 데이터에서도 효율적으로 k-최근접이웃 그래프를 만들 수 있도록 다양한 옵션을 제공합니다. 실제로는 여러 파라미터(epsilon, r, c_stop) 등을 조정해가며, 정확도와 성능을 균형 있게 사용하면 좋습니다.
아래 내용은 graph-tool 라이브러리의 (triangulation) 함수를 사용해 2차원(또는 3차원) 점 집합에 대해 삼각분할(트라이앙귤레이션, Triangulation) 그래프를 생성하는 방법을 안내합니다. 또한 simple과 delaunay의 차이, 코드 예시, betweenness centrality 계산 방법 등을 포괄하여, 초보자도 쉽게 접근할 수 있게 정리해보았습니다.
simple triangulation(type="simple")
Delaunay triangulation(type="delaunay")
정리: Delaunay가 좀 더 ‘공간적으로 균형’있게 분할하지만, 계산 비용이 더 들 수 있음. Simple 모드는 삽입 순서에 따라 달라지며 상대적으로 구현이 간단.
graph_tool.generation.triangulationg, pos = gt.triangulation(points, type='simple', periodic=False)
파라미터
'simple')'simple' 또는 'delaunay''delaunay'일 때만 유효)반환값
Graph 객체): 삼각분할 결과 그래프VertexPropertyMap): 각 정점의 (x,y) 혹은 (x,y,z) 좌표simple:delaunay:import graph_tool.all as gt
import numpy as np
import math
def simple_triangulation_example():
# (1) 임의의 2D 점 생성 (N=500)
points = np.random.rand(500, 2) * 4.0 # x,y 각각 [0,4) 범위
# (2) Simple triangulation 그래프 생성
g, pos = gt.triangulation(points, type='simple', periodic=False)
print("== Simple Triangulation ==")
print("Num. of vertices:", g.num_vertices()) # 대체로 500
print("Num. of edges :", g.num_edges())
# (3) Edge에 유클리드 거리(weight) 부여
weight = g.new_edge_property("double")
for e in g.edges():
s = e.source()
t = e.target()
# pos[s], pos[t]가 numpy array-like
diff = pos[s] - pos[t]
dist = math.sqrt(diff[0]**2 + diff[1]**2)
weight[e] = dist
# (4) 가중치가 있는 betweenness(중개중심성) 계산
vb, eb = gt.betweenness(g, weight=weight)
# eb: edge betweenness → 시각화 위해 적당히 스케일링
eb.a *= 100
# (5) 그래프 그리기
gt.graph_draw(g, pos=pos,
vertex_fill_color=vb, # 정점색: betweenness기반
edge_pen_width=eb, # 에지 두께: betweenness기반
output="triang_simple.pdf")
print(" - Drawn to triang_simple.pdf")
import graph_tool.all as gt
import numpy as np
import math
def delaunay_triangulation_example():
# 1) 임의의 2D 점 생성
points = np.random.rand(500, 2) * 4.0
# 2) Delaunay triangulation
# periodic=True 로 하면 주기 경계에서의 델로네 분할
g, pos = gt.triangulation(points, type='delaunay', periodic=False)
print("== Delaunay Triangulation ==")
print("Num. of vertices:", g.num_vertices()) # 일반적으로 500
print("Num. of edges :", g.num_edges())
# 3) 엣지 가중치(유클리드 거리)
weight = g.new_edge_property("double")
for e in g.edges():
s = e.source()
t = e.target()
diff = pos[s] - pos[t]
dist = math.sqrt(diff[0]**2 + diff[1]**2)
weight[e] = dist
# 4) betweenness
vb, eb = gt.betweenness(g, weight=weight)
eb.a *= 120 # 에지 두께 스케일
# 5) 그래프 시각화
gt.graph_draw(g, pos=pos,
vertex_fill_color=vb,
edge_pen_width=eb,
output="triang_delaunay.pdf")
print(" - Drawn to triang_delaunay.pdf")
periodic=True도 가능. 이 경우, 점들이 경계를 넘어 wrap-around된다고 생각하고 델로네 분할.def delaunay_3d_example():
points_3d = np.random.rand(200, 3) * 5.0 # (N=200, x,y,z in [0,5)
g3d, pos3d = gt.triangulation(points_3d, type='delaunay', periodic=False)
print("3D Delaunay Triangulation:")
print("Vertices:", g3d.num_vertices(), "Edges:", g3d.num_edges())
# edge 등은 동일하게 가중치 계산 가능 (단, 3차원 거리)
# 시각화는 pos3d를 가지고 2D에 투영 or 다른 tool 써서 3D 시각 가능
g.faces() 등). 아래는 2D 점(500개)에 대해 simple/delaunay 두 방식 모두 실행 후, betweenness 시각화 파일을 각각 저장하는 종합 코드 예시입니다.
import graph_tool.all as gt
import numpy as np
import math
def compare_triangulations():
# 난수로 2D 점 500개 생성
points = np.random.rand(500, 2) * 4.0
# 1) Simple Triangulation
g_simp, pos_simp = gt.triangulation(points, type='simple', periodic=False)
# 2) Delaunay Triangulation
g_dela, pos_dela = gt.triangulation(points, type='delaunay', periodic=False)
# 가중치(거리) 계산 함수
def compute_edge_weight(g, pos):
w = g.new_edge_property("double")
for e in g.edges():
s, t = e.source(), e.target()
dx = pos[s][0] - pos[t][0]
dy = pos[s][1] - pos[t][1]
w[e] = math.sqrt(dx*dx + dy*dy)
return w
w_simp = compute_edge_weight(g_simp, pos_simp)
w_dela = compute_edge_weight(g_dela, pos_dela)
# Betweenness
vb_s, eb_s = gt.betweenness(g_simp, weight=w_simp)
vb_d, eb_d = gt.betweenness(g_dela, weight=w_dela)
eb_s.a *= 100
eb_d.a *= 100
# 시각화
gt.graph_draw(g_simp, pos=pos_simp, vertex_fill_color=vb_s, edge_pen_width=eb_s,
output="simple_vs.pdf")
gt.graph_draw(g_dela, pos=pos_dela, vertex_fill_color=vb_d, edge_pen_width=eb_d,
output="delaunay_vs.pdf")
print("Simple triangulation -> simple_vs.pdf")
print("Delaunay triangulation -> delaunay_vs.pdf")
if __name__ == "__main__":
compare_triangulations()
triangulation() 함수는 2D/3D 점 집합에 대한 단순(Simple) 또는 델로네(Delaunay) 삼각분할을 자동으로 해주는 강력한 도구.이상으로 graph-tool의 삼각분할(triangulation) 함수에 대한 기초 튜토리얼을 마칩니다.
추가적으로, 3D 점이나 periodic 옵션을 다룰 때도 위 코드 구조를 응용하면 쉽게 적용 가능합니다. 즐거운 네트워크 분석 되세요!