코드 보기
# 그림 6 (비공간) 두 지표 나란히: 학원 비중(LQ) vs 학원 밀도
dd = ind2.dropna(subset=["density"])
fig, ax = plt.subplots(figsize=(11, 8))
ax.scatter(dd.loc[~dd["ac_town"], "lq"], dd.loc[~dd["ac_town"], "density"], s=22, color="#9ecae1", alpha=0.8, label="그 외 동")
ax.scatter(dd.loc[dd["ac_town"], "lq"], dd.loc[dd["ac_town"], "density"], s=45, color="#b2182b", edgecolor="white", linewidth=0.5, label="학원 특화 동")
ax.set_xscale("symlog", linthresh=1); ax.set_yscale("log")
ax.axvline(1, color="gray", ls="--", lw=1); ax.axhline(dd["density"].median(), color="gray", ls="--", lw=1)
ax.set_xlabel("학원 입지계수 LQ (동 매출 속 비중, 1 = 서울 평균)"); ax.set_ylabel("학원 밀도 (학생 1인당 학원 매출, 만 원/분기, 로그)")
lab = pd.concat([dd.nlargest(6, "density"), dd.nlargest(6, "lq")]).drop_duplicates()
OFF = {"노량진2동": (8, 4, "left"), "대치4동": (-8, 8, "right"), "명일2동": (8, 8, "left"), "대치2동": (-8, 4, "right"), "대치1동": (8, 4, "left"),
"반포3동": (-8, 6, "right"), "목5동": (8, 6, "left"), "중계1동": (8, -12, "left"), "돈암1동": (8, 6, "left"), "반포2동": (8, -14, "left"),
"신정7동": (8, -10, "left"), "방이1동": (-8, -12, "right")}
for r in lab.itertuples():
dx, dy, ha = OFF.get(r.dong_nm, (6, 4, "left"))
ax.annotate(r.dong_nm, (r.lq, r.density), (dx, dy), textcoords="offset points", ha=ha, fontsize=10, fontweight="bold", path_effects=halo)
ax.set_title("③ 학원 '비중'(LQ)과 '학생 1인당 학원 매출'은 같은 동네를 가리키는가", fontsize=14)
ax.grid(alpha=0.25); ax.legend(loc="lower right")
plt.tight_layout()
plt.savefig("image/academy3_fig3_lq_density.png", dpi=150)
plt.show()
print(f"LQ와 밀도의 상관계수(순위 기준) = {spearmanr(dd['lq'], dd['density'])[0]:+.2f}")
print("학원 특화 동의 밀도 중앙값 %.0f만 vs 그 외 %.0f만" % (dd[dd.ac_town].density.median(), dd[~dd.ac_town].density.median()))
print("LQ 상위 5동의 밀도(만원):", ", ".join(f"{r.dong_nm} LQ {r.lq:.1f} / {r.density:.0f}" for r in dd.nlargest(5, "lq").itertuples()))
print("밀도 상위 5동의 LQ:", ", ".join(f"{r.dong_nm} {r.density:.0f}만 / LQ {r.lq:.1f}" for r in dd.nlargest(5, "density").itertuples()))