GIS

PyQGIS: 종 출현 위치의 공간적 간격 조정(spatial thinning) 구현하기

유병혁 2024. 8. 12. 21:40

안녕하세요? 이번 글은 종 분포 모델링에서 종 출현 위치의 "공간적 간격 조정(spatial thinning)"을 QGIS에서 구현해 보도록 하겠습니다.

종 분포 모델링에서 중요한 단계 중 하나는 인근 관측치들이 다수 존재할 경우, 데이터 집합으로 인해 모델 결과에 영향을 미칠 수 있는 지리적 샘플링 편향(geographic sampling bias)의 잠재적 효과를 제한하는 것입니다. 분석가는 선택된 공간해상도에 따라 각 픽셀 당 하나의 출현 기록만 임의로 선택하여 위치 데이터 간격을 넓혀 밀도를 낮추는 작업을 하는데 이것을 공간적 간격 조정이라고 합니다.

 

먼저 QGIS에서 특정 생물종의 출현 좌표를 열어보겠습니다. 출처는 GBIF입니다.

 

먼저, 종 분포 모델링의 공간해상도를 기준으로 한 랜덤 래스터 레이어를 생성합니다. 여기서는 랜덤 레스터 레이어 생성 (정규 분포)를 선택해 보겠습니다.

 

원하는 범위는 출현 좌표 레이어로부터 계산하겠습니다.

 

공간해상도는 30m로 정의하겠습니다.

 

결과는 다음과 같습니다.

 

직관적 이해를 돕기 위해 아래와 같이 조정해 봤습니다. 현재 픽셀당 2개 이상 출현 좌표가 위치한 것을 확인할 수 있습니다. 공간적 간격 조정을 통해 픽셀당 1개의 출현 좌표만 임의 선택되도록 조치해 보겠습니다.

 

해당 작업은 PyQGIS를 통해 아래와 같이 적용합니다.

import random
import processing
from qgis.core import QgsProject, QgsFeature, QgsGeometry

# 레이어 불러오기

point_layer = QgsProject.instance().mapLayersByName("presence")[0]
raster_layer = QgsProject.instance().mapLayersByName("raster")[0]

# Step 1: 포인트 레이어에 래스터 값 샘플링
sampled = processing.run(
    "qgis:rastersampling",
    {
        "INPUT": point_layer,
        "RASTERCOPY": raster_layer,
        "COLUMN_PREFIX": "raster_value_",
        "OUTPUT": "memory:",
    },
)

sampled_layer = sampled["OUTPUT"]

# Step 2: 격자별로 포인트 그룹화 및 임의의 포인트 선택
raster_value_index = sampled_layer.fields().indexFromName("raster_value_1")
grouped_features = {}

for feature in sampled_layer.getFeatures():
    raster_value = feature[raster_value_index]
    if raster_value not in grouped_features:
        grouped_features[raster_value] = []
    grouped_features[raster_value].append(feature)
selected_features = []
for raster_value, features in grouped_features.items():
    if len(features) > 1:
        selected_feature = random.choice(features)
    else:
        selected_feature = features[0]
    selected_features.append(selected_feature)

# Step 3: 선택된 포인트들을 새로운 레이어로 생성
selected_layer = QgsVectorLayer(
    "Point?crs={}".format(point_layer.crs().authid()), "remove_duplicates", "memory"
)
selected_layer.dataProvider().addAttributes(sampled_layer.fields())
selected_layer.updateFields()

with edit(selected_layer):
    for feature in selected_features:
        selected_layer.addFeature(feature)

# Step 4: QGIS에 레이어 추가
QgsProject.instance().addMapLayer(selected_layer)

print("완료되었습니다! 'remove_duplicates' 레이어를 확인하세요.")

 

결과는 다음과 같습니다.

 

참고로, 아래 그림은 30m급 랜덤 래스터 레이어와 출현 좌표를 함께 표현한 것입니다. 육안상으로는 6개 좌표가 보이며 공간적 간격 조정이 필요한 좌표는 없어 보입니다. 한가지 유의할 점은 동일 위치를 공유하는 중복 좌표들이 존재한다는 것입니다. 예를 들면 아래 6개 좌표는 실제로 25개 좌표로 구성되어 있습니다.