본문 바로가기
프로그래밍/SciPy

[Scipy] 3. 관측된 (x, y, z) 데이터로부터 xy 평면에 격자형 좌표에 대한 z값을 보간법(Interpolation)으로 추정하기 (feat. griddata)

by 부자 꽁냥이 2023. 1. 15.

이번 포스팅에서는 주어진 $(x, y, z)$로부터 격자형 구조를 갖는 $(x', y')$에 대한 $z'$값을 보간법(Interpolation)으로 추정하는 방법에 대해서 알아본다.


   griddata를 이용한 보간법 추정

포스팅 제목이 뭔가 거창한데 아래 그림을 보면 쉽게 이해될 수 있다. 먼저 주어진 $(x, y, z)$에 대해서 $z$를 제외한 $(x, y)$가 아래 왼쪽 그림이다. 이때 오른쪽 그림에서 격자형 구조를 갖는 $(x', y')$은 빨간 점이다. 이때 빨간 점에 대응하는 $z'$값을 주어진 데이터 $(x, y, z)$를 보간법을 이용하여 추정하겠다는 것이다. 이때  주어진 $(x, y)$로 이루어진 Convex Hull(오른쪽 그림에서 초록 경계) 내에서 보간법 추정이 이루어진다. Convex Hull 바깥 부분은 외삽(Extrapolation)으로 추정한다고 하는데 여기에서는 다루지 않는다. 외삽을 이용한 부분은 여기를 참고하기 바란다.

 

이렇게 격자형 구조 데이터에 대해서 보간법으로 추정하는 이유는 보통 등고선도를 그리기 위해서이다. 설명은 여기까지하고 바로 코드로 알아보자. 먼저 임의로 관측 데이터를 만들어보자.

 

import matplotlib.pyplot as plt
plt.rcParams['axes.unicode_minus']=False
import numpy as np

from scipy.interpolate import griddata

np.random.seed(100)

## 관측 데이터
real_sample_size = 50
x = np.random.uniform(-2, 2 , real_sample_size)
y = np.random.uniform(-2, 2, real_sample_size)
z = x*np.exp(-x**2-y**2)

## 관측 데이터 시각화
fig = plt.figure(figsize=(8,8))
fig.set_facecolor('white')
ax = fig.add_subplot()
ax.scatter(x, y, color='k', alpha=0.5, s=10)

plt.show()

 

 

Scipy에서는 griddata를 이용하여 격자 구조 데이터에 대한 $z$값을 보간법으로 추정할 수 있게 해 준다. griddata 사용법은 다음과 같다.

 

griddata( 관측 데이터 x, y 행렬, z 벡터, (격자 구조 X좌표 행렬, 격자 구조 Y좌표 행렬), 보간 방법)

 

griddata에서는 보간 방법으로 'nearest', 'linear', 'cubic'을 제공하고 있다. 이때 'linear', 'cubic'을 사용하면 관측된 $(x, y)$ 데이터의 Convex Hull 바깥 영역은 nan이 된다. 각 방법에 대해서 보간이 어떻게 이루어지는지 등고선도를 그려서 확인해 보자.

 

from scipy.interpolate import griddata

## 관측된 데이터를 이용하여 격자 데이터 생성
grid_size = 100
x_range = np.linspace(-2.2, 2.2, grid_size) ## x 범위
y_range = np.linspace(-2.2, 2.2, grid_size) ## y 범위
X, Y = np.meshgrid(x_range, y_range) ## XY 격자 데이터

fig, axs = plt.subplots(1, 3, figsize=(24, 8))
fig.set_facecolor('white')

method_list = ['nearest', 'linear', 'cubic']
for i, method in enumerate(method_list):
    ax = axs[i]
    Z = griddata(np.c_[x, y], z, (X, Y), method=method) ## Z 격자 데이터
    contour1 = ax.contour(X, Y, Z, levels=10, colors='k', linewidths=1, linestyles='--') ## 등고선
    contour2 = ax.contourf(X, Y, Z, levels=256, cmap='jet')

    ax.clabel(contour1, contour1.levels, inline=True) ## contour 라벨
    ax.scatter(x, y, color='k', alpha=0.5, s=5) ## 산점도 추가
    ax.set_title(method, fontsize=20)
plt.show()

 

앞에서 말한 바와 같이 'linear', 'cubic'은 관측된 $(x, y)$ 데이터의 Convex Hull 바깥 영역에 대해서 아무것도 그려지지 않는 것을 알 수 있다.


댓글


맨 위로