GIS

Python 종 분포 모델링(SDM) (2) - 생물종 Bunch 객체 생성

유병혁 2022. 3. 29. 02:22

안녕하세요? Python 언어용 자유 소프트웨어 머신러닝 라이브러리 'scikit-learn(사이킷런)'에서 제공하는 종 분포 모델링(species distribution modeling) 예제 코드를 시리즈 글로 다시 정리해 봅니다. 이번엔 두번째 글로 실습용 종 분포 데이터셋으로부터 생물종 Bunch 객체를 생성해 보겠습니다. 이전 글은 아래와 같습니다.

 

Python 종 분포 모델링(SDM) (1) - 종 분포 데이터셋

안녕하세요? Python 언어용 자유 소프트웨어 머신러닝 라이브러리 'scikit-learn(사이킷런)'에서 제공하는 종 분포 모델링(species distribution modeling) 예제 코드를 시리즈 글로 다시 정리해 봅니다. 이번

blog.daum.net

먼저, 실습용종 분포 데이터셋 'sklearn.datasets.fetch_species_distributions'을 불러옵니다. 이 데이터셋의 유형은 sklearn.utils.Bunch입니다. Bunch는 키(keys)를 속성으로 노출하는 컨테이너 객체(container object)로써 key, bunch["value_key"], 또는 속성, bunch.value_key로 값에 엑세스할 수 있도록 하여 딕셔너리를 확장합니다.

from sklearn.datasets import fetch_species_distributions
# 종 분포 데이터셋
data = fetch_species_distributions()

이전 글에서 fetch_species_distributions의 속성들을 정리했었습니다. 해당 내용을 참고하여 왼쪽 하단 모서리의 경위도 값(x_left_low_corner, y_left_corner)으로부터 그리드 경위도 수(Nx, Ny)만큼 일정 간격(grid_size)으로 분포하는 모서리 셀의 x, y 좌표를 정의합니다.

"""
모서리 셀의 x, y 좌표
x_left_lower_corner; y_left_lower_corner: 왼쪽 하단 모서리 경도, 위도
grid_size: 그리드 점 사이의 간격(도)
Nx; Ny: 그리드의 경도, 위도 수
"""
xmin = data.x_left_lower_corner + data.grid_size    # -94.80 + 0.05
ymin = data.y_left_lower_corner + data.grid_size    # -56.05 + 0.05
xmax = xmin + (data.Nx * data.grid_size)            # -94.75 + (1212 * 0.05)
ymax = ymin + (data.Ny * data.grid_size)            # -56.00 + (1592 * 0.05)
print('xmin: %f, ymin: %f, xmax: %f, ymax: %f' % (xmin, ymin, xmax, ymax))

출력 결과는 아래와 같습니다.

xmin: -94.750000, ymin: -56.000000, xmax: -34.150000, ymax: 23.600000

위 출력값을 기준으로 일정 간격(grid_size)만큼 분포하는 그리드 셀의 x, y 좌표(xgrid, ygrid)를 정의합니다.

import numpy as np
# 그리드 셀의 x 좌표
xgrid = np.arange(xmin, xmax, data.grid_size)
# 그리드 셀의 y 좌표
ygrid = np.arange(ymin, ymax, data.grid_size)
print('xgrid 차원:' + str(xgrid.shape))
print('ygrid 차원:' + str(ygrid.shape))

현재는 1차원 배열, 즉 벡터입니다.

xgrid 차원:(1212,)
ygrid 차원:(1592,)

xgrid를 확인해 볼까요?

xgrid
array([-94.75, -94.7 , -94.65, ..., -34.3 , -34.25, -34.2 ])

ygrid도 확인해 봅니다!

ygrid
array([-56.  , -55.95, -55.9 , ...,  23.45,  23.5 ,  23.55])

ygrid를 역순으로 정렬해 볼까요?

ygrid[::-1] # 역순으로 정렬
array([ 23.55,  23.5 ,  23.45, ..., -55.9 , -55.95, -56.  ])

np.meshgrid()를 이용하여 좌표 벡터(xgrid, ygrid)에서 좌표 행렬(X, Y)을 반환해 봅니다. 개념은 아래 그림과 같습니다.

그림 출처: https://stackoverflow.com/questions/36013063/what-is-the-purpose-of-meshgrid-in-python-numpy

# x, y 좌표의 그리드
X, Y = np.meshgrid(xgrid, ygrid[::-1])
print('X 차원:' + str(X.shape))
print('Y 차원:' + str(Y.shape))
X 차원:(1592, 1212)
Y 차원:(1592, 1212)

X, Y는 좌표 행렬입니다.

X
array([[-94.75, -94.7 , -94.65, ..., -34.3 , -34.25, -34.2 ],
       [-94.75, -94.7 , -94.65, ..., -34.3 , -34.25, -34.2 ],
       [-94.75, -94.7 , -94.65, ..., -34.3 , -34.25, -34.2 ],
       ...,
       [-94.75, -94.7 , -94.65, ..., -34.3 , -34.25, -34.2 ],
       [-94.75, -94.7 , -94.65, ..., -34.3 , -34.25, -34.2 ],
       [-94.75, -94.7 , -94.65, ..., -34.3 , -34.25, -34.2 ]])
Y
array([[ 23.55,  23.55,  23.55, ...,  23.55,  23.55,  23.55],
       [ 23.5 ,  23.5 ,  23.5 , ...,  23.5 ,  23.5 ,  23.5 ],
       [ 23.45,  23.45,  23.45, ...,  23.45,  23.45,  23.45],
       ...,
       [-55.9 , -55.9 , -55.9 , ..., -55.9 , -55.9 , -55.9 ],
       [-55.95, -55.95, -55.95, ..., -55.95, -55.95, -55.95],
       [-56.  , -56.  , -56.  , ..., -56.  , -56.  , -56.  ]])

이번에는 생물종 Bunch 객체를 반환하는 함수를 아래와 같이 정의합니다.

from sklearn.utils import Bunch
def create_species_bunch(species_name, train, test, coverages, xgrid, ygrid):
    # 생물종 Bunch 객체 생성
    bunch = Bunch(name=" ".join(species_name.split("_")[:2]))
    species_name = species_name.encode("ascii")
    points = dict(test=test, train=train)
    for label, pts in points.items():
        pts = pts[pts["species"] == species_name]
        bunch["pts_%s" % label] = pts
        ix = np.searchsorted(xgrid, pts["dd long"])
        iy = np.searchsorted(ygrid, pts["dd lat"])
        bunch["cov_%s" % label] = coverages[:, -iy, ix].T
    return bunch

생물종을 정의합니다. 갈색목세발가락나무늘보, 숲작은쌀쥐입니다.

species=("bradypus_variegatus_0", "microryzomys_minutus_0")

앞서 정의한 함수와 종 분포 데이터셋 Bunch 객체 속성을 사용하여 2종의 Bunch 객체를 생성합니다.

# 갈색목세발가락나무늘보 Bunch 객체 생성
BV_bunch = create_species_bunch(
    species[0],        # 종명
    data.train,        # 훈련데이터
    data.test,         # 시험데이터
    data.coverages,    # 커버리지: 14개 피처
    xgrid, ygrid       # 그리드 셀의 x, y 좌표
)
# 숲작은쌀쥐 Bunch 객체 생성
MM_bunch = create_species_bunch(
    species[1], data.train, data.test, data.coverages, xgrid, ygrid
)

갈색목세발가락나무늘보 Bunch 객체의 키를 확인해 봅니다.

BV_bunch.keys() # 키

 

dict_keys(['name', 'pts_test', 'cov_test', 'pts_train', 'cov_train'])

키 속성을 확인해볼까요?! name은 종명입니다.

BV_bunch.name # 종명
'bradypus variegatus'

pts_train은 훈련 데이터 좌표를 나타냅니다. 

import pandas as pd
# pts_train
print('pts_train 차원: ' + str(BV_bunch.pts_train.shape))
pd.DataFrame(BV_bunch.pts_train).head()

cov_train은 훈련 데이터에 해당하는 커버리지, 14개 피처입니다.

# cov_train
print('cov_train 차원: ' + str(BV_bunch.cov_train.shape))
pd.DataFrame(BV_bunch.cov_train).head()

pts_test는 시험 데이터 좌표를 나타냅니다.

# pts_test
print('pts_test 차원: ' + str(BV_bunch.pts_test.shape))
pd.DataFrame(BV_bunch.pts_test).head()

cov_test는 시험 데이터에 해당하는 커버리지, 14개 피처입니다.

# cov_test
print('cov_test 차원: ' + str(BV_bunch.cov_test.shape))
pd.DataFrame(BV_bunch.cov_test).head()

위와 같이 생물종 Bunch 객체는 잘 생성되었습니다. 다음으로 평가용 background points(그리드 좌표)를 만들어 둡니다.

# 평가용 background points (그리드 좌표)
np.random.seed(13)
background_points = np.c_[
    np.random.randint(low=0, high=data.Ny, size=10000), # 0부터 1212 사이 난수 10,000개
    np.random.randint(low=0, high=data.Nx, size=10000), # 0부터 1592 사이 난수 10,000개
].T
print('background_points 차원: ' + str(background_points.shape))
background_points 차원: (2, 10000)

두번째 글은 여기까지입니다. 세번째 글에서는 종 출현 데이터만 있기에 사용하는 OneClassSVM을 모델링 도구에 관해 정리해 보겠습니다.

import matplotlib.pyplot as plt
plt.imshow(data.coverages[6])
plt.show()