TOP
class="layout-aside-left paging-number">
본문 바로가기
[파이썬 Projects]/<파이썬 데이터 분석>

[파이썬] 우리나라 인구 소멸 위기 지역 분석 - 3

by 기록자_Recordian 2024. 4. 30.
728x90
반응형
시작에 앞서
해당 내용은 <파이썬으로 데이터 주무르기> -민형기 저, BJPUBLIC 출판사 의 내용을 토대로 작성되었습니다.
보다 자세한 내용은 해당 교재를 확인하여 주시기 바랍니다.

이전 시간 분석
 

[파이썬] 우리나라 인구 소멸 위기 지역 분석 - 2

시작에 앞서해당 내용은 -민형기 저, BJPUBLIC 출판사 의 내용을 토대로 작성되었습니다.보다 자세한 내용은 해당 교재를 확인하여 주시기 바랍니다.이전 시간 분석  [파이썬] 우리나라 인구 소멸

puppy-foot-it.tistory.com


변수 (pop, draw_korea_raw)의 합계 정보 삭제하기

 
원래 인구 현황을 가지고 있던 pop 변수와 엑셀에서 출발해서 지도를 그리기 위해 만든 draw_korea_raw 변수에서 일반 행정구를 가진 시(성남, 수원 등)의 합계 정보 삭제

# pop 데이터 프레임과 draw_korea_raw 데이터 프레임에서 겹치지 않는 지역 이름을 찾기.
tmp_list = list(set(pop['ID'].unique()) - set(draw_korea_raw['ID'].unique()))

# 겹치지 않는 지역 이름에 해당하는 행을 pop 데이터 프레임에서 삭제.
for tmp in tmp_list:
    pop = pop.drop(pop[pop['ID'] == tmp].index)

# 삭제된 후 남아 있는 pop 데이터 프레임의 지역 이름을 출력.
print(set(pop['ID'].unique()) - set(draw_korea_raw['ID'].unique()))
set()

 

이 코드는 겹치지 않는 지역 이름을 찾고 해당 지역 이름에 해당하는 행을 삭제한 후, 마지막으로 삭제된 지역 이름을 확인.
출력 결과는 빈 집합 {}으로,
모든 pop 데이터 프레임의 지역 이름이 draw_korea_raw 데이터 프레임의 지역 이름과 겹치는 것을 나타냄.

위의 코드는 데이터 정제나 전처리를 위한 것으로 보이며,
두 데이터 프레임 간의 일치 여부를 확인하고 불일치하는 항목을 삭제하는 과정.

 

중복 데이터 삭제하기

두 변수 합치기 (merge)
pop = pd.merge(pop, draw_korea_raw, how='left', on=['ID'])

pop.head()

각 지역별 고유 ID, 좌표 모두 확보 완료


인구수 합계 그리기
def drawKorea(targetData, blockedMap, cmapname):
    gamma = 0.75

    # 흰색 라벨의 최솟값 설정
    whitelabelmin = (max(blockedMap[targetData]) - 
                     min(blockedMap[targetData])*0.25 + \
                     min(blockedMap[targetData]))

    datalabel = targetData

    vmin = min(blockedMap[targetData])
    vmax = max(blockedMap[targetData])

     # 지도 데이터 생성 및 누락된 값 마스킹
    mapdata = blockedMap.pivot_table(index='y', columns='x', values=targetData)
    masked_mapdata = np.ma.masked_where(np.isnan(mapdata), mapdata)

    plt.figure(figsize=(9, 11))
    plt.pcolor(maked_mapdata, vmin=vmin, vmax=vmax, cmap=cmapname, edgecolor='#aaaaaa', linewidth=0.5)

# 지역 이름 표시
    for idx, row in blockedMap.iterrows():
        #광역시는 구 이름이 겹치는 경우가 많아서 시단위 이름도 같이 표시
        #(중구, 서구)
        if len(row['ID'].split())==2:
            dispname = '{}\n{}'.format(row['ID'].split()[0], row['ID'].split()[1])
        elif row['ID'][:2] == '고성':
            dispname = '고성'
        else:
            dispname = row['ID']

    # 서대문구, 서귀포시 같이 이름이 3자 이상인 경우에 작은 글자로 표시
    if len(dispname.splitlines()[-1]) >= 3:
        fontsize, linespacing = 10.0, 1.1
    else:
        fontsize, linespacing = 11, 1.

    annocolor = 'white' if row[targetData] > whitelabelmin else 'black'
    plt.annotate(dispname, (row['x']+0.5, row['y']+0.5), weight='bold',
                 fontsize=fontsize, ha='center', va='center', color=annocolor, linespacing=linespacing)

# 시도 경계 그리기
for path in BORDER_LINES:
    ys, xs = zip(*path)
    plt.plot(xs, ys, c='black', lw=2)

plt.gca().invert_yaxis()

plt.axis('off')

cb = plt.colorbar(shrink=.1, aspect=10)
cb.set_label(datalabel)

plt.tight_layout(
plt.show()
이 함수는 지도 데이터와 함께 지도를 그리고, 각 지역에 대한 데이터 값을 색상으로 시각화.
지도에는 지역 이름과 시도 경계가 표시되며, 함수는 targetData로 선택한 데이터를 시각화하고,
blockedMap은 지도 데이터 프레임을, cmapname은 컬러맵을 나타냄.
함수는 한국의 지리적인 특성을 반영하여 지도를 그림.

 
그러나,

RuntimeError: No mappable was found to use for colorbar creation. First define a mappable such as an image (with imshow) or a contour set (with contourf).

라는 장문의 에러 메시지를 받았다.
 
처음 받아보는 종류의 에러 메시지라 바로 챗GPT에 검색해보니

"이 오류는 색상 막대기를 생성할 때 색상을 매핑할 수 있는 데이터가 없다는 것을 나타냅니다. 즉, 함수에서 사용한 plt.pcolor() 또는 plt.imshow() 등의 함수로 이미지나 등고선 세트와 같은 시각화 요소를 먼저 정의해야 합니다.

이 문제를 해결하려면 drawKorea() 함수에서 plt.pcolor() 또는 plt.imshow() 함수를 사용하여 이미지를 생성한 후에 colorbar 함수를 호출해야 합니다. 그렇지 않으면 맵핑할 데이터가 없어서 오류가 발생합니다. 함수를 수정하여 해당 부분을 고쳐주세요."

 
그래서 다시 코드를 수정하여

def drawKorea(targetData, blockedMap, cmapname):
    gamma = 0.75

    # 흰색 라벨의 최솟값 설정
    whitelabelmin = (max(blockedMap[targetData]) - 
                     min(blockedMap[targetData])*0.25 + \
                     min(blockedMap[targetData]))

    datalabel = targetData

    vmin = min(blockedMap[targetData])
    vmax = max(blockedMap[targetData])

     # 지도 데이터 생성 및 누락된 값 마스킹
    mapdata = blockedMap.pivot_table(index='y', columns='x', values=targetData)
    masked_mapdata = np.ma.masked_where(np.isnan(mapdata), mapdata)

    plt.figure(figsize=(9, 11))
    plt.pcolor(masked_mapdata, vmin=vmin, vmax=vmax, cmap=cmapname, edgecolor='#aaaaaa', linewidth=0.5)

    # 색상 막대 생성
    cb = plt.colorbar(shrink=0.1, aspect=10)
    cb.set_label(datalabel)

# 지역 이름 표시
    for idx, row in blockedMap.iterrows():
        #광역시는 구 이름이 겹치는 경우가 많아서 시단위 이름도 같이 표시
        #(중구, 서구)
        if len(row['ID'].split())==2:
            dispname = '{}\n{}'.format(row['ID'].split()[0], row['ID'].split()[1])
        elif row['ID'][:2] == '고성':
            dispname = '고성'
        else:
            dispname = row['ID']

    # 서대문구, 서귀포시 같이 이름이 3자 이상인 경우에 작은 글자로 표시
    if len(dispname.splitlines()[-1]) >= 3:
        fontsize, linespacing = 10.0, 1.1
    else:
        fontsize, linespacing = 11, 1.

    annocolor = 'white' if row[targetData] > whitelabelmin else 'black'
    plt.annotate(dispname, (row['x']+0.5, row['y']+0.5), weight='bold',
                 fontsize=fontsize, ha='center', va='center', color=annocolor, linespacing=linespacing)

# 시도 경계 그리기
for path in BORDER_LINES:
    ys, xs = zip(*path)
    plt.plot(xs, ys, c='black', lw=2)

plt.gca().invert_yaxis()

plt.axis('off')

plt.tight_layout()
plt.show()

drawKorea 함수 작동

drawKorea 함수를 이용하여 인구수합계를 그려보았으나,

drawKorea('인구수합계', pop, 'Blues')

 
영 시원치 않다...

대한민국 지도 카토그램

MatplotlibDeprecationWarning: Getting the array from a PolyQuadMesh will return the full array in the future (uncompressed). To get this behavior now set the PolyQuadMesh with a 2D array .set_array(data2d).
  cb = plt.colorbar(shrink=0.1, aspect=10)


경고의 뜻은

[출처: Chat GPT]
경고 메시지는 PolyQuadMesh에서 배열을 가져올 때 압축되지 않은 전체 배열을 반환할 것이라는 것을 알려줍니다. 이는 앞으로 변경될 예정이며 현재의 동작을 얻으려면 PolyQuadMesh에 set_array(data2d)를 설정해야 한다는 것을 나타냅니다.

해당 경고는 사용 중인 Matplotlib의 버전에 따라 다를 수 있습니다. 이에 대한 해결책은 현재로서는 경고를 무시하거나 Matplotlib의 새로운 버전으로 업그레이드하는 것입니다. 경고는 코드의 작동에 영향을 주지 않으므로 무시해도 괜찮습니다.

 
그래서 우선 Matplotlib의 버전 업그레이드를 했는데도 결과가 같아서 결국 구글링..

pip install --upgrade matplotlib


위의 인구수합계 그리기에서 사용했던 코드를 재수정했다.

def drawKorea(targetData, blockedMap, cmapname):
    gamma = 0.75

    whitelabelmin = (max(blockedMap[targetData]) - 
                                     min(blockedMap[targetData]))*0.25 + \
                                                                min(blockedMap[targetData])

    datalabel = targetData

    vmin = min(blockedMap[targetData])
    vmax = max(blockedMap[targetData])

    mapdata = blockedMap.pivot_table(index='y', columns='x', values=targetData)
    masked_mapdata = np.ma.masked_where(np.isnan(mapdata), mapdata)
    
    plt.figure(figsize=(9, 11))
    plt.pcolor(masked_mapdata, vmin=vmin, vmax=vmax, cmap=cmapname, 
               edgecolor='#aaaaaa', linewidth=0.5)

    # 지역 이름 표시
    for idx, row in blockedMap.iterrows():
        # 광역시는 구 이름이 겹치는 경우가 많아서 시단위 이름도 같이 표시한다. 
        #(중구, 서구)
        if len(row['ID'].split())==2:
            dispname = '{}\n{}'.format(row['ID'].split()[0], row['ID'].split()[1])
        elif row['ID'][:2]=='고성':
            dispname = '고성'
        else:
            dispname = row['ID']

        # 서대문구, 서귀포시 같이 이름이 3자 이상인 경우에 작은 글자로 표시한다.
        if len(dispname.splitlines()[-1]) >= 3:
            fontsize, linespacing = 10.0, 1.1
        else:
            fontsize, linespacing = 11, 1.

        annocolor = 'white' if row[targetData] > whitelabelmin else 'black'
        plt.annotate(dispname, (row['x']+0.5, row['y']+0.5), weight='bold',
                     fontsize=fontsize, ha='center', va='center', color=annocolor,
                     linespacing=linespacing)

    # 시도 경계 그린다.
    for path in BORDER_LINES:
        ys, xs = zip(*path)
        plt.plot(xs, ys, c='black', lw=2)

    plt.gca().invert_yaxis()

    plt.axis('off')

    cb = plt.colorbar(shrink=.1, aspect=10)
    cb.set_label(datalabel)

    plt.tight_layout()
    plt.show()

 
다시 해보니 잘된다.

drawKorea('인구수합계', pop, 'Blues')

대한민국 인구지도 카토그램

 
여기까지 오느라 너무 진이 빠졌으므로, 다음 시간에 계속
(결론은 코드짤 때 오타 하나라도 조심해야 한다는 것. 시간날 때 기존에 내가 작성했던 것과, 구글링으로 얻은 코드는 어떤 부분이 다른지 찾아봐야겠다)


다음글

[파이썬] 우리나라 인구 소멸 위기 지역 분석 - 4

728x90
반응형