주소가 들어 있는 데이터는 전부 공간 데이터인데 대부분의 분석가는 그 지리 정보를 버립니다. 이 편은 버리지 않습니다. 동네 경계에 범죄 건수와 코로나 결과를 붙여 단계구분도로 그립니다.
Every dataset with an address in it is spatial data, and most analysts throw the geography away. This session keeps it: neighbourhood boundaries joined to crime counts and COVID outcomes, rendered as choropleth maps.
도구는 단순합니다. GeoPandas는 기하 정보를 담은 열 하나가 더 붙은 Pandas DataFrame이라 merge, groupby, 불리언 마스킹이 이미 아는 대로 동작합니다. 단순하지 않은 것은 통계입니다. 아래 지도에서 결론을 끌어내기 전에 그 경계를 분명히 해 둘 값어치가 있습니다.
The tooling is simple: GeoPandas is a Pandas DataFrame with one extra column holding geometry, so merge, groupby and boolean masking all work as they already do. What is not simple is the statistics, and it is worth being clear about that boundary before drawing conclusions from any of the maps.
GeoPandas가 더해 주는 것What GeoPandas adds
GeoDataFrame은 평범한 DataFrame에 활성 기하 열이 하나 붙은 것입니다. 그 열에는 shapely 객체 — 점, 선, 다각형 — 가 담깁니다. 그 열이 공간 연산을 열어 줍니다.
A GeoDataFrame is an ordinary DataFrame plus an active geometry column containing shapely objects — points, lines, polygons. That column unlocks spatial operations.
.plot(column="x")— 단계구분도. 다각형을 값으로 색칠합니다..sjoin()— 공간 결합. 키가 아니라 포함·교차 관계로 행을 맞춥니다. 좌표 표에 "이 점은 어느 동네인가"를 붙이는 방법입니다..to_crs()— 좌표계 사이 재투영..area,.centroid,.buffer(),.distance()— 기하 측정값.
.plot(column="x")— choropleth, colouring each polygon by a value..sjoin()— spatial join, matching rows by containment or intersection rather than by key. This is how you attach "which neighbourhood is this point in" to a table of coordinates..to_crs()— reproject between coordinate systems..area,.centroid,.buffer(),.distance()— geometric measures.
파일 형식은 둘이 나옵니다. 셰이프파일은 오래된 표준이고 사실 형제 파일 묶음입니다. .shp, .shx, .dbf, .prj가 함께 다녀야 하고 .shp 하나만으로는 열리지 않습니다. GeoJSON은 단일 파일로 된 현대적 대안이고 모든 면에서 다루기 쉽습니다.
Two file formats show up. Shapefiles are the legacy standard and are actually a set of sibling files — .shp, .shx, .dbf, .prj — that must travel together; a lone .shp will not open. GeoJSON is the modern single-file alternative and is easier in every respect.
좌표계 함정The coordinate reference system trap
가장 확실하게 잘못되는 지점입니다. 좌표계는 굽은 지구 위의 위치를 숫자로 어떻게 옮길지를 정의합니다.
This is the one thing that reliably goes wrong. A CRS defines how positions on a curved Earth map to numbers.
- EPSG:4326 (WGS84)은 생 위경도입니다. GPS가 내보내는 형식이고 대부분의 데이터가 이 형태로 옵니다. 단위가 도입니다. 경도 1도는 적도에서 약 111km, 극에서 0km입니다.
- 투영 좌표계 — UTM 존, 평면직각 — 는 단위가 미터이고 국소적으로 면적이나 거리를 보존합니다.
- EPSG:4326 (WGS84) is raw latitude/longitude. It is what GPS emits and what most data ships in. Its units are degrees, and a degree of longitude is about 111 km at the equator and 0 km at the poles.
- Projected systems — UTM zones, state plane — have units of metres and preserve area or distance locally.
import geopandas as gpd
gdf = gpd.read_file("neighbourhoods.geojson")
print(gdf.crs) # check this FIRST, every time
gdf = gdf.to_crs(epsg=3857) # or a local UTM zone for real accuracy
gdf["area_km2"] = gdf.area / 1e6
gdf["crime_density"] = gdf["n"] / gdf["area_km2"]단계구분도를 정직하게 읽기Reading a choropleth honestly
아래 모든 지도에 걸리는 문제가 둘 있습니다. 둘 다 보여 주기 쉽고 잊기 쉽습니다.
Two problems affect every map below, and both are easy to demonstrate and easy to forget.
가변적 공간단위 문제. 경계는 행정적 선택이지 세계의 사실이 아닙니다. 다시 그으면 패턴이 바뀌고 때로는 뒤집힙니다. 게리맨더링과 같은 기제입니다. "X 동네가 가장 나쁘다"는 현상만큼이나 선택된 분할을 두고 하는 진술입니다.
The modifiable areal unit problem. The boundaries are an administrative choice, not a fact about the world. Redraw them and the pattern changes, sometimes reversing. This is the same mechanism as gerrymandering, and it means "neighbourhood X is worst" is a statement about the chosen partition as much as about the phenomenon.
발생률이 아니라 인구. 원시 건수 지도는 사실상 인구 지도입니다. 밀집한 동네에 범죄와 확진자가 많은 건 사람이 많기 때문입니다. 코로나 데이터가 cases와 case_rate, deaths와 death_rate를 함께 들고 있는 이유가 정확히 이것입니다. 원시 건수를 그리면 "어디에 사람이 많은가"에 답하게 됩니다. 그건 대개 묻고 싶은 질문이 아닙니다.
Population, not incidence. A raw count map is largely a population map. Dense neighbourhoods have more crimes and more cases because they have more people. This is exactly why such data carries both cases and case_rate, and both deaths and death_rate. Mapping the raw count answers "where are there many people", which is rarely the question.
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
gdf.plot(column="cases", cmap="Greens", scheme="quantiles", k=5,
linewidth=0.6, edgecolor="0.6", ax=axes[0], legend=True)
axes[0].set_title("raw counts - mostly a population map")
gdf.plot(column="case_rate", cmap="viridis", scheme="quantiles", k=5,
linewidth=0.6, edgecolor="0.6", ax=axes[1], legend=True)
axes[1].set_title("rate per 100k - the actual question")
for ax in axes:
ax.set_axis_off()색 선택도 보이는 것보다 중요합니다. 한 방향으로만 커지는 양에는 순차형, 의미 있는 중간값이 있으면 발산형, 무지개는 절대 쓰지 마십시오. 데이터에 없는 시각적 경계를 만들어 냅니다. 위에서 쓴 Greens와 viridis는 둘 다 순차형이고 지각적으로 균일합니다.
Colour choice matters more than it looks. Use a sequential palette for quantities that only go up, a diverging palette when there is a meaningful midpoint, and never a rainbow — it manufactures visual boundaries that are not in the data. Greens and viridis above are both sequential and perceptually uniform.
이 편이 넘지 않는 선The line this post does not cross
여기까지는 전부 기술입니다. 공간 추론 — 군집이 우연 이상인지 검정하거나 공간 데이터에 회귀를 적합하는 것 — 에는 이 편이 쓰지 않는 장치가 필요합니다. 이유는 토블러의 제1법칙입니다. 가까운 것은 먼 것보다 서로 더 관련되어 있습니다.
Everything above is description. Spatial inference — testing whether clustering exceeds chance, or fitting a regression on spatial data — needs machinery this session does not use, and the reason is Tobler first law: near things are more related than distant things.
실무에서In practice
- 기하 계산 전에 항상
gdf.crs를 확인하십시오. EPSG:4326이 찍히는데 면적이나 거리를 재려는 참이면 먼저 재투영하십시오. 이 확인 하나가 공간 버그의 가장 흔한 부류를 막습니다. - 결합을 검증하십시오. 이름으로 경계와 속성 데이터를 붙이는 건 취약합니다. "Downtown"과 "DOWNTOWN"과 "Downtown LA"는 맞지 않습니다. 병합 후 결합된 열의 결측을 확인하십시오. 매칭 안 된 다각형은 지도에서 빈 구멍으로 나타나고 0으로 오해하기 쉽습니다. 이름보다
fid같은 안정적 ID로 결합하는 편이 훨씬 안전합니다. - 웹에 올릴 때는 기하를 단순화하십시오. 상세한 경계는 메가바이트 단위가 됩니다.
gdf.geometry.simplify(tolerance)는 지도 축척에서 눈에 띄는 차이 없이 파일 크기를 한 자릿수 줄입니다. - 작은 분모는 가짜 극단값을 만듭니다. 인구 200명인 동네에서 사망 2건이면 사망률이 시 평균의 열 배이고 근거는 사실상 없습니다. 인구가 적은 지역이 순전히 통계적인 이유로 비율 지도를 지배합니다. 경험적 베이즈 축소가 표준 해법입니다. 소지역 추정치를 전체 평균 쪽으로 당겨 줍니다.
- Always check
gdf.crsbefore computing anything geometric. If it prints EPSG:4326 and you are about to measure area or distance, reproject first. This single check prevents the most common class of spatial bug. - Verify the join. Merging boundaries to attribute data by name is fragile: "Downtown", "DOWNTOWN" and "Downtown LA" do not match. After any merge, check for nulls in the joined columns — unmatched polygons render as blank holes and are easy to mistake for zeros. Joining on a stable ID such as
fidis far safer than joining on a name. - Simplify geometry for the web. Detailed boundaries can run to megabytes.
gdf.geometry.simplify(tolerance)cuts file size by an order of magnitude with no visible difference at map zoom levels. - Small denominators produce fake extremes. A neighbourhood of 200 people with two deaths has a death rate ten times the city average and essentially no information behind it. Sparsely populated areas dominate rate maps for purely statistical reasons. Empirical Bayes smoothing shrinks small-area estimates toward the global mean and is the standard fix.
더 나아가기: 공간 통계Going further: spatial statistics
- Moran의 I는 관측된 군집이 우연을 넘는지 검정합니다. PySAL 생태계의
esda.Moran입니다. 국소 Moran(LISA)은 어느 지역이 군집을 이루는지 짚어 줍니다. 대개는 그쪽이 원하는 답입니다. - 공간 가중 행렬이 "이웃"의 정의입니다. 인접(경계 공유)이나 거리 기반입니다. 이 선택이 이후의 모든 결과를 좌우하므로 명시적으로 밝히십시오.
- 공간 시차 모형은 이웃 결과의 공간가중평균을 회귀변수로 넣어 실제 파급을 모형화합니다.
- 공간 오차 모형은 평균식은 두고 공간 상관을 오차항에 넣습니다. 공간 패턴이 진짜 이웃 효과가 아니라 빠진 지리적 변수를 반영할 때 씁니다.
- Moran I tests whether observed clustering exceeds chance —
esda.Moranin the PySAL ecosystem. Local Moran (LISA) identifies which areas form clusters, which is usually what you actually want. - Spatial weights matrices define what "neighbour" means: contiguity (sharing a border) or distance-based. This choice drives every result that follows, so state it explicitly.
- Spatial lag models include a spatially weighted average of neighbours outcomes as a regressor, modelling genuine spillover.
- Spatial error models leave the mean equation alone and put the spatial correlation in the error term. Use these when the pattern reflects omitted geographic variables rather than a real neighbour effect.
시차 모형과 오차 모형의 구분은 기술적인 게 아니라 실질적입니다. 하나는 이웃의 결과가 당신에게 영향을 준다고 말하고 다른 하나는 당신과 이웃이 관측되지 않은 조건을 공유한다고 말합니다. 함의하는 정책이 다릅니다.
The distinction between the lag and error models is substantive rather than technical: one says your neighbours outcomes affect yours, the other says you and your neighbours share unobserved conditions. Those imply different policies.
소매 입지 선정, 지역별 보험 요율, 역학 감시, 물류 네트워크 설계, 부동산 감정 — 공간 오차항을 넣은 헤도닉 모형은 자산 평가에서 사실상 표준입니다. 모두에서 지리는 장식이 아닙니다. 공간 상관을 무시하면 이전 편의 회귀가 그랬듯 자신 있게 틀린 표준오차를 얻습니다.
Retail site selection, insurance pricing by geography, epidemiological surveillance, logistics network design, and real estate valuation — hedonic models with spatial error terms are close to standard practice in property assessment. In all of them the geography is not decoration: ignoring spatial correlation gives you standard errors that are confidently wrong, in exactly the way the previous post regression was.