앞에서 실행해 본 PySAL의 Moran’s I 샘플은 내장된 예제 데이터를 이용해 훌륭히 자기상관관계를 분석하고 있지만, 우리가 아는 데이터도 아니고 자료가 지도로 보이는 것도 아니어서 좀 많이 답답하다.
QGIS에 불러와 시각적으로 보이는 데이터를 가지고 분석을 한다면, 그 의미도 명확히 이해 할 수 있고 분석 결과도 좀 더 시각적으로 잘 표현할 수 있다. 이제 QGIS와 PySAL을 결합하여 분석을 해 보자.
먼저 아래의 링크에서 샘플로 사용할 파일을 받자.
http://open.gaia3d.com/data/pysal/sample_dataset.zip
다운로드 받은 압축파일을 C:\QgisSpatialStat\data 폴더에 모두 압축 풀어주자.
이 중에서 ‘인구분포.shp’ 파일이 이번에 사용할 샘플 파일이다.
QGIS 로 돌아가 레이어-벡터 레이어 추가… 메뉴를 이용해 ‘인구분포.shp’ 파일을 불러보자.
[탐색] 버튼을 눌러 파일 선택용 대화상자를 열어 C:\QgisSpatialStat\data 에 있는 인구분포.shp 파일을 선택해 열어주면 된다.
좌표계 선택 화면에서는 필터에 5181 라고 입력하여 EPSG:5181인 Korea 2000: 중부원점 좌표계를 선택해 주면 된다.
그러면 다음과 같이 우리나라의 행정구역이 보이는 인구분포 데이터가 보인다.
상단 툴바 중 아래 그림에 있는 속성테이블 열기 버튼을 누르면 현재 선택된 레이어의 속성을 볼 수 있다.
속성테이블 열기 버튼으로 열린 테이블의 컬럼 중 ‘노인비율’ 컬럼이 우리가 공간자기상관관계 분석을 위해 사용할 컬럼이다.
이제 일단 아래의 코드를 PyCharm의 global_morans_i.py의 편집창에 복사해 붙여 넣어 보자.
# coding=utf-8
from pysal import W, Moran import numpy as np import qgis from qgis.core import * from qgis.gui import QgsMessageBar from PyQt4.QtGui import QProgressBar from PyQt4.QtCore import * import matplotlib.pyplot as plt
# 전역변수 설정 TEST_DIST = 100000 NAME_FIELD = "SGG" VALUE_FIELD = u"노인비율"
########################## # 레이어에서 정보 추출
# 레이어 선택 oLayer = iface.activeLayer() if not oLayer: raise UserWarning(u"레이어를 먼저 선택해야 합니다.") # 종료
layerName = oLayer.name() layerType = oLayer.geometryType() crs = oLayer.crs()
# ID 리스트 확보 oIDs = oLayer.allFeatureIds()
# Progress 생성 progressMessageBar = iface.messageBar().createMessage(u"레이어 정보 수집중...") progress = QProgressBar() progress.setMaximum(len(oIDs)) progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) progressMessageBar.layout().addWidget(progress) iface.messageBar().pushWidget(progressMessageBar, iface.messageBar().INFO)
# centroid,value(y),name 모으기 centroidList = [] dataList = [] nameList = [] for i, oID in enumerate(oIDs): progress.setValue(i)
iFeature = oLayer.getFeatures(QgsFeatureRequest(oID)).next() iGeom = iFeature.geometry().centroid() centroidList.append(iGeom) data = iFeature[VALUE_FIELD] dataList.append(data) name = iFeature[NAME_FIELD] nameList.append(name)
# 통계 대상 값 수집 y = np.array(dataList)
# Progress 제거 iface.messageBar().clearWidgets()
# Weight Matrix 계산 위한 정보 수집 neighbors = {} weights = {} for iID, iCent in zip(oIDs, centroidList): iRowNeighbors = [] iRowWeights = [] for jID, jCent in zip(oIDs, centroidList): # 동일 지역인 경우 제외 if iID == jID: continue # 기준거리 이내인 경우 인접한 것으로 기록 dist = iCent.distance(jCent) if dist <= TEST_DIST: iRowNeighbors.append(jID) iRowWeights.append(1) # iID 지역에 대한 인접 지역 및 가중치 기록 neighbors[iID] = iRowNeighbors weights[iID] = iRowWeights
# 인접지역과 가중치를 기준으로 현재 testDist의 Weight Matrix 계산 w |