[부동산 | Phase3] 아파트 현황조사(고양시) - matplotlib 기본 (4부)



 시각화를 주제로 벌써 4부까지 흘러 왔습니다. 이제 마지막 (3)번 질문으로 matplotlib 살짝 들여다 보기를 완결해 보도록 하겠습니다.



 (3) 공동주택 건물 유형별로 공급되어 있는 세대수는 얼마나 될까?



 이번 질문에 대한 data processing은 [부동산 | Phase2] 지역단위 아파트 현황조사 - Python coding (4부)에서 다루었습니다.


 그리고, 우리는  a12_APTstat_Goyang과 a13_APTstat_Goyang이라는 파일명을 가진 엑셀파일로 a12 DataFrame과 a13 DataFrame을 저장해 두었습니다. 

 a12 DataFrame에서는 피벗테이블 형식으로 '행정동별 건물유형별 세대수 합계' 값을 가공하였고, a13 DataFrame에서는 피벗테이블 형식으로 '행정동별 건물유형별 건령 평균' 값을 가공하였습니다.


 이 포스팅에서는 누적수직막대그래프로 이 데이터들에 대한 Visualization을 진행해 보겠습니다.

 

 우리는 이미 지난 시간 수직막대그래프를 그리는 법을 배웠습니다. 그렇다면 같은 x축 값에 유형이 다른 값을 가진 index로 표현되는 누적수직막대그래프를 그리는 논리는 어떻게 될까요?



matplotlib 누적막대그래프 그리기



 먼저, 필자가 작성한 코드를 아래와 같이, 제시하고 한줄씩 살펴 보겠습니다.


b2 = pd.read_excel('C:\\Users\\USER\\Desktop\\example\\a12_APTstat_Goyang.xlsx').set_index('건물유형')
b2 = b2.fillna(0)

x1 = b2.loc['공동주택',:].reset_index()
x2 = x1.iloc[:,0]

y1 = b2.loc['공동주택',:]
y2 = b2.loc['다세대주택',:]
y3 = b2.loc['다세대주택(도시형생활주택)',:]
y4 = b2.loc['아파트',:]
y5 = b2.loc['연립',:]
y6 = b2.loc['연립주택',:]
y7 = b2.loc['주상복합',:]
y8 = b2.loc['주상복합/아파트',:]
y9 = b2.loc['주택',:]

plt.bar(x2,height=y1, width=0.5, align='center', color='green')
plt.bar(x2,height=y2, bottom=y1, width=0.5, align='center', color='red')
plt.bar(x2,height=y3, bottom=y2+y1, width=0.5, align='center', color='yellow')
plt.bar(x2,height=y4, bottom=y3+y2+y1, width=0.5, align='center', color='blue')
plt.bar(x2,height=y5, bottom=y4+y3+y2+y1, width=0.5, align='center', color='black')
plt.bar(x2,height=y6, bottom=y5+y4+y3+y2+y1, width=0.5, align='center', color='gray')
plt.bar(x2,height=y7, bottom=y6+y5+y4+y3+y2+y1, width=0.5, align='center', color='navy')
plt.bar(x2,height=y8, bottom=y7+y6+y5+y4+y3+y2+y1, width=0.5, align='center', color='purple')
plt.bar(x2,height=y9, bottom=y8+y7+y6+y5+y4+y3+y2+y1, width=0.5, align='center', color='brown')
plt.tick_params(axis="x", labelsize=7, labelrotation=90)
plt.tick_params(axis="y", labelsize=7)
plt.axis([-1,x2.count(),0,35000])
plt.grid(axis='y', linestyle='-.', linewidth=0.5, color='black', alpha=0.3)
plt.tight_layout()

plt.show()



 우선, 우리가 만들어 놓은 피벗테이블 데이터를 누적막대그래프를 그리기 위한 가공 과정이 필요합니다.

 피벗테이블 자체로도 어느 정도 현황 파악이 좋은 요약 보고서 이기 때문에 이러한 누적막대 시각화가 큰 의미를 가질 수 없을지도 모르겠습니다. 하지만, 사용되는 데이터의 특성상 필요한 경우도 있다고 보고 시각화를 한다면 피벗테이블 그 자체만으로는 DataFrame 형태로부터 matplotlib이 인식하기 적당한 array형태로 x축과 y축 값을 배분하는 과정에서 데이터를 배열 형태로 뽑아내는 작업이 필수입니다.


 그렇다면, 누적막대그래프는 어떤 원리로 그려지는가.. 이미 상기 코드를 통해 표출이 되었는데, 이전 bar()메소드에 사용된 height 값에 이번 bar를 그리기 위한 height값을 더하는 방식입니다. bottom이라는 인자를 통해 이번 bar의 시작 위치를 지정해 주는 것입니다. 예를 들어, 기존 bar가 height가 300 이라는 값을 가졌고 이번 bar가 200이라는 값을 가졌다면, bottom이라는 인자에 300값을 줌으로서 이번에 그릴 바는 300부터 시작해서 200을 쌓아서 그리는 것입니다. 이러한 방식으로 유형이 20개 라면 bar()메소드 20개를 써주시면 되겠습니다. 

 Pattern이 반복되어진 부분이 있어 상기 코드도 더욱 간략히 반복문을 써서 줄일 수 있겠으나, 초보 독자분의 이해를 위해 길게 풀어 써 놓은 것일 뿐, 실질 코드 자체의 원리는 매우 간단합니다.


 이 외 주목해 봐야할 몇가지 코드를 더 살펴 보겠습니다.



pandas DataFrame   set_index()와 reset_index()



 1) b2 = pd.read_excel('C:\\Users\\USER\\Desktop\\example\\a12_APTstat_Goyang.xlsx').set_index('건물유형')


 a12로 저장된 엑셀파일을 b2로 명칭한 DataFrame으로 읽어오기 위해, pandas의 read_excel()을 사용하였습니다. 그런데, set_index('건물유형')이라는 메소드도 사용하였습니다. 이 메소드는 엑셀을 DataFrame으로 읽어 들이는 과정에서 '건물유형'이라는 이름을 가진 Series를 index로서 인식하도록 합니다. 즉, 피벗테이블에 열의 형태로 들어 있는 '건물유형'은 이 메소드를 통해 Series가 아닌 Index로 인식되어 집니다.



 2) x1 = b2.loc['공동주택',:].reset_index()


 reset_index()메소드는 set_index()와 달리, index를 integer로 표현된 별도의 인덱스를 새로 부여 합니다. 또한, pandas DataFrame에 대해 loc[] 함수가 사용되었는데, 이 함수는 pandas에서 특정 행, 특정 열을 특정 조건에 따라, 추출하고 싶을 때, index 명을 참조하여 추출하는데 사용됩니다. 자세한 설명은 별도의 주제로 다루도록 하겠습니다.


 여기서 이 코드는 '공동주택'이라는 index로 된 이 DataFrame의 행을 전부 추출하는 것이며, 이렇게 추출된 행은 pandas series형태로 저장되는데, 이 series는 reset_index() 메소드를 통해 기존의 index는 Series로 인식되게 함으로서, 새로운 DataFrame형태로 추출되게 됩니다. 


 즉,  기존 index인 '행정동'이 새로운 Series값으로 인식되고 index는 정수형으로 별도로 다시 부여 되는 것입니다.


 이 코드는 우리가 그린 bar chart의 x축에 행정동을 배열하기 위해 피벗테이블로부터 그 값을 추출할 목적에서 사용된 것입니다.



plt.axis()로 축 스케일 조정하기

 


 3) plt.axis([-1,x2.count(),0,35000])

 

 axis() 메소드는 matplotlib.pyplot에 의해 그려지는 그래프의 x축과 y축의 상세설정을 추가로 조정할 수 있도록 도와 줍니다. 특히, 축의 최소, 최대값 범위를 조정할 수 있습니다.


 axis([xmin, xmax, ymin, ymax])


xmin에는 x축 최소값을, xmax는 x축 최대값을 설정해 x축 범위의 최소값, 최대값을 지정해 줄 수 있습니다.

마찬가지로, y축 최소값을 ymin으로, y축 최대값을 ymax로 지정하게 됩니다.


 우리 데이터를 보겠습니다. 우리 데이터의 x축에는 행정동을 배분하였습니다. 실질 그 자료형이 str임에도 불구하고 그래프를 그려보면 별도 조치 없이도 순서대로 잘 나옵니다. 이를 통해 보았을 때, 자료형이 str인 series의 경우에는 그 인덱스 번호를 사용하여 값을 배열해 그래프를 그려준다는 것을 알 수 있습니다. 그렇다면, '행정동'의 최초값은 '가좌동'인데, 가좌동의 인덱스 번호는 '0' 이 될 것입니다. 이런 경우 가좌동의 막대그래프는 0의 값 위에 표현되어 막대그래프가 반이 잘려 나가 표현되게 됩니다. 이와 같은 이유로 필자는 xmin값을 -1로 설정했습니다. 가좌동의 막대그래프를 온전하게 표현하기 위한 방법인 것입니다.


 xmax값을 보시죠. 필자는 x2.count()를 넣었습니다. 이는 x2라고 하는 데이터프레임의 결측치를 제외한 값의 개수를 넣은 것입니다. 즉, 모든 행정동의 개수가 전부 나오게끔 한 것입니다. 


 ymax값은 그래프가 보기 좋게 표현될 수 있도록 임의로 설정한 것인데, xmax의 값을 설정하는 방식과 마찬가지로, raw data 값이 수집할 때마다 수시로 변경될 수 있다면 이처럼 계산식화 시킬 것을 권장 드립니다.




pandas DataFrame의 fillna() 메소드로 결측치 값채우기


 

 4) b2 = b2.fillna(0)


 pandas DataFrame의 결측치에 관해서는 지난 포스팅에서 일부 설명을 드렸습니다. fillna()라는 메소드는 그러한 결측치 값을 괄호 안에 주어진 값으로 채워주는 기능을 합니다. 최초 데이터를 불러오면, DataFrame에서는 공란을 모두 NaN 결측치로 인식합니다. 이 상태로는 누적막대그래프를 그리기 위한 덧셈 연산을 진행할 수 없게 됩니다. 따라서, fillna(0)을 이용해 결측치값은 모두 0으로 인식되도록 조치한 코드 입니다.



pandas DataFrame   loc[]와 iloc[]



 5) x2 = x1.iloc[:,0]

 

 이 코드에서 사용된 DataFrame.iloc[]는 DataFrame.loc[]와 기능이 같으나, 그 행 또는 열을 지정함에 있어서 int형의 인덱스번호 Series번호를 사용한다는데, 차이점이 있습니다. Sereis 이름을 특정하기 곤란하지만 해당 자료가 DataFrame의 구조상 몇번째에 위치하는지 특정할 수 있는 경우에 loc[]를 대신해 사용할 수 있겠습니다.



자 그럼 이제 우리 코드의 실행결과를 보시겠습니다.



필자의 욕심에선 아직 예쁘게 꾸밀 부분이 많지만, 어찌 되었든 우리의 목적인 누적막대 그래프가 온전히 잘 표현되었습니다.


어느 행정동이든 파란색 막대로 표현된 아파트의 세대공급 수량이 압도적으로 많은 것이 확인됩니다. 한마디로 고양시 주거구역에 공급된 공동주택의 유형 대부분은 '아파트 천지'다 라고 해석할 수 있는 부분입니다.





# 이번 포스팅에서 배운 내용

a. matplotlib 누적막대그래프 그리기

b. pandas DataFrame의 set_index()와 reset_index()

c. pandas DataFrame의 loc[]와 iloc[]

d. plt.axis()로 축 범위 조정하기

e. pandas DataFrame의 fillna() 메소드로 결측치 값채우기 








 지금까지 Data Visualization 진행으로 숨가쁘게 달려 왔습니다. 이번 부동산 아파트 현황조사 주제를 통해서 Python의 pandas, matplotlib 등의 사용례를 살펴 보았구요. 그런데, 여전히 파이썬은 정말 많은 데이터 분석 방법과 시각화 방법을 제공해 줍니다. 추가로 배워 나갈 부분들은 직후 다루고자 하는 무역주제의 Phase1 - Phase2 - Phase3를 통해 또 다시 익혀 나가도록 하겠습니다. 



 아직, 이 블로그의 개설취지인 정부 공공데이터 활용 방안 / 가치 모색은 완결되지 않았습니다. 이제 이 다음 단계이면서 마지막 단계인 분석된 데이터를 토대로 의미 찾기를 진행할 것입니다. 다음 번 포스팅에서는 파이썬의 기술적 이용에 관한 참조글 보다는 독자분들과 소통하는 글.. 분석을 토대로 의미를 찾고 어떻게 활용할 것인지에 대해 논하는 글을 쓰고자 합니다.


 어느 주제를 다뤄도 이와 같은 방식으로 진행할 예정이니, 해당 주제 카테고리의 글은 마지막 포스팅까지 꼭 함께 해주세요.


 긴 글 읽어 주셔서 감사 드리고, 많은 참조되었길 바랍니다.


 다음 포스팅에서 뵐께요.


 


 



반응형

+ Recent posts