Milky's note

부동산 데이터 전처리 본문

데이터 분석/데이터분석 연습

부동산 데이터 전처리

밀뿌 2022. 1. 11. 15:09

쉬운 데이터 분석 문제이다. 

아직 시각화는 나오지 않고 단순히 데이터만 전처리하는 과정이지만, 하나씩 해보면서 끈기랑 통찰력을 길러야겠다.

코랩에서 풀었고, 깃에 소스도 올려놓았는데 블로그에도 정리할 겸 올리게 되었다.

추후에  시각화도 추가할 예정이다.

 

1. 라이브러리 로드

import pandas as pd 

2. 데이터 프레임 로드 (https://bit.ly/ds-house-price)

df = pd.read_csv('https://bit.ly/ds-house-price')
 
df
 
 
지역명규모구분연도월분양가격(㎡)01234...45004501450245034504

 

서울 전체 2015 10 5841
서울 전용면적 60㎡이하 2015 10 5652
서울 전용면적 60㎡초과 85㎡이하 2015 10 5882
서울 전용면적 85㎡초과 102㎡이하 2015 10 5721
서울 전용면적 102㎡초과 2015 10 5879
... ... ... ... ...
제주 전체 2020 2 3955
제주 전용면적 60㎡이하 2020 2 4039
제주 전용면적 60㎡초과 85㎡이하 2020 2 3962
제주 전용면적 85㎡초과 102㎡이하 2020 2 NaN
제주 전용면적 102㎡초과 2020 2 3601

4505 rows × 5 columns

3. 컬럼 재정의(rename)

분양가격(㎡) -> 분양가격
df=df.rename(columns={'분양가격(㎡)' : '분양가격'})
df

 

 
지역명규모구분연도월분양가격01234...45004501450245034504

 

서울 전체 2015 10 5841
서울 전용면적 60㎡이하 2015 10 5652
서울 전용면적 60㎡초과 85㎡이하 2015 10 5882
서울 전용면적 85㎡초과 102㎡이하 2015 10 5721
서울 전용면적 102㎡초과 2015 10 5879
... ... ... ... ...
제주 전체 2020 2 3955
제주 전용면적 60㎡이하 2020 2 4039
제주 전용면적 60㎡초과 85㎡이하 2020 2 3962
제주 전용면적 85㎡초과 102㎡이하 2020 2 NaN
제주 전용면적 102㎡초과 2020 2 3601

4505 rows × 5 columns

4. 빈 값과 Data Type 확인

df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4505 entries, 0 to 4504
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   지역명     4505 non-null   object
 1   규모구분    4505 non-null   object
 2   연도      4505 non-null   int64 
 3   월       4505 non-null   int64 
 4   분양가격    4210 non-null   object
dtypes: int64(2), object(3)
memory usage: 176.1+ KB

 

5. 통계값 확인

df.describe()

 

연도월countmeanstdmin25%50%75%max
 
4505.000000 4505.000000
2017.452830 6.566038
1.311432 3.595519
2015.000000 1.000000
2016.000000 3.000000
2017.000000 7.000000
2019.000000 10.000000
2020.000000 12.000000

 

6. 분양가격 column을 int 타입으로 변환(전처리 과정 표시하기)

df['분양가격']=df['분양가격'].astype(int)

 

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_37700/2121692590.py in 
----> 1 df['분양가격'].astype(int)

.
.
.

ValueError: invalid literal for int() with base 10: '  '​


데이터 타입을 바꾸려고 했는데 분양가격 컬럼에 공백이 있어서 int 타입으로 데이터 변환이 되지 않는다. 먼저, 분양가격 컬럼에 있는 공백을 제거해주고 다시 변환을 진행하여야한다.

공백제거를 할 때는

컬럼.str.strip() 를 사용한다.

df['분양가격']=df['분양가격'].str.strip()
df

 

 
지역명규모구분연도월분양가격01234...45004501450245034504
 
서울 전체 2015 10 5841
서울 전용면적 60㎡이하 2015 10 5652
서울 전용면적 60㎡초과 85㎡이하 2015 10 5882
서울 전용면적 85㎡초과 102㎡이하 2015 10 5721
서울 전용면적 102㎡초과 2015 10 5879
... ... ... ... ...
제주 전체 2020 2 3955
제주 전용면적 60㎡이하 2020 2 4039
제주 전용면적 60㎡초과 85㎡이하 2020 2 3962
제주 전용면적 85㎡초과 102㎡이하 2020 2 NaN
제주 전용면적 102㎡초과 2020 2 3601

4505 rows × 5 columns

df['분양가격']=df['분양가격'].astype(int)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_37700/2121692590.py in <module>
----> 1 df['분양가격'].astype(int)

.
.
.

ValueError: invalid literal for int() with base 10: ''

공백을 제거하고 데이터 타입을 바꾸려고 했는데 분양가격 컬럼에 빈 공백이 있어서 int 타입으로 데이터 변환이 되지 않는다. 분양가격 컬럼에 있는 빈 공백을 제거해주고 다시 변환을 진행하여야한다. 이 때 빈 공백은 0으로 치환한다.

 

loc 를 사용하여, 해당 컬럼의 조건에 맞는 데이터를 치환한다.

df.loc[df['분양가격'] == '', '분양가격']=0
df['분양가격']=df['분양가격'].astype(int)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_37700/2121692590.py in <module>
----> 1 df['분양가격'].astype(int)

.
.
.

ValueError: cannot convert float NaN to integer

이번에는 NaN 값에 또 걸려버렸다. NaN 값도 마찬가지로 0으로 채워준다.

NaN 값을 채울 때는 fillna를 이용해서 채워준다.

df['분양가격']=df['분양가격'].fillna(0)
 
df['분양가격']=df['분양가격'].astype(int)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_37700/2121692590.py in <module>
----> 1 df['분양가격'].astype(int)

.
.
.

ValueError: invalid literal for int() with base 10: '6,657'

또 오류가 발생하였다. 숫자에 컴마 (,)가 들어가 있어서 형변환이 불가하여 발생하였다. 컴마를 제거하고 다시 형변환을 해야겠다.

컴마를 제거하는 방법은 공백을 제거할 때와 비슷한 문법을 사용한다.

컬럼.str.replace('변경하려는 값, '치환하려는 값')

df['분양가격']=df['분양가격'].str.replace(',', '')
 
df['분양가격']=df['분양가격'].astype(int)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_37700/2121692590.py in <module>
----> 1 df['분양가격'].astype(int)

.
.
.

ValueError: cannot convert float NaN to integer

여러문자들을 치환하니까 다시 NaN 값이 생겼다. 이도 역시 아까와 마찬가지고 0으로 바꿔준다.

df['분양가격']=df['분양가격'].fillna(0)
df['분양가격']=df['분양가격'].astype(int)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_37700/2121692590.py in <module>
----> 1 df['분양가격'].astype(int)

.
.
.

ValueError: invalid literal for int() with base 10: '-'

또..........!! 오류다. 이번에는 대시(-)가 있어서 데이터 형변환이 되지 않았다. 마찬가지로 치환해준다!!

 
df['분양가격']=df['분양가격'].str.replace('-','')
df['분양가격']=df['분양가격'].astype(int)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_37700/2121692590.py in <module>
----> 1 df['분양가격'].astype(int)

.
.
.

ValueError: cannot convert float NaN to integer

다시 NaN 값이 생겼다. 다시.. 0으로 채워준다.

 
df['분양가격']=df['분양가격'].fillna(0)
 
df['분양가격']=df['분양가격'].astype(int)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_37700/2121692590.py in <module>
----> 1 df['분양가격'].astype(int)

.
.
.

ValueError: invalid literal for int() with base 10: ''

이번엔 다시.. ㅎ 공백이 생겼다... 이것도 다시 0으로 치환..

 
df.loc[df['분양가격'] == '', '분양가격']=0
 
df['분양가격'] =df['분양가격'].astype(int)
 
df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4505 entries, 0 to 4504
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   지역명     4505 non-null   object
 1   규모구분    4505 non-null   object
 2   연도      4505 non-null   int64 
 3   월       4505 non-null   int64 
 4   분양가격    4505 non-null   int32 
dtypes: int32(1), int64(2), object(2)
memory usage: 158.5+ KB

 

7. 규모구분 column에 불필요한 '전용면적' 제거

df['규모구분']=df['규모구분'].str.replace('전용면적','')
df['규모구분'].value_counts()

전체               901
 60㎡이하           901
 60㎡초과 85㎡이하     901
 85㎡초과 102㎡이하    901
 102㎡초과          901
Name: 규모구분, dtype: int64

 
 

8. 지역명 별 평균 분양가격 확인

 
df.groupby('지역명')['분양가격'].mean()

지역명
강원    2339.807547
경기    4072.667925
경남    2761.275472
경북    2432.128302
광주    2450.728302
대구    3538.920755
대전    2479.135849
부산    3679.920755
서울    7225.762264
세종    2815.098113
울산    1826.101887
인천    3578.433962
전남    2270.177358
전북    2322.060377
제주    2979.407547
충남    2388.324528
충북    2316.871698
Name: 분양가격, dtype: float64

 
 

9. 분양가격이 100보다 작은 행 제거

df.loc[df['분양가격']<100]
 

지역명규모구분연도월분양가격28293481113...44614488449344994503

 

광주 85㎡초과 102㎡이하 2015 10 0
광주 102㎡초과 2015 10 0
대전 102㎡초과 2015 10 0
제주 60㎡이하 2015 10 0
광주 85㎡초과 102㎡이하 2015 11 0
... ... ... ... ...
세종 60㎡이하 2020 2 0
전남 85㎡초과 102㎡이하 2020 2 0
경북 85㎡초과 102㎡이하 2020 2 0
경남 102㎡초과 2020 2 0
제주 85㎡초과 102㎡이하 2020 2 0

320 rows × 5 columns

320개의 컬럼이 분양가격이 100보다 작다. 이 컬럼들을 삭제한다.

특정 조건에 만족하는 행을 제거하고자 할 때는

1. index를 list로 가져온다

2. drop을 활용하여 행을 제거한다

idx = df.loc[df['분양가격'] < 100].index
idx

Int64Index([  28,   29,   34,   81,  113,  114,  119,  166,  198,  199,
            ...
            4418, 4448, 4453, 4458, 4459, 4461, 4488, 4493, 4499, 4503],
           dtype='int64', length=320)

 
df=df.drop(idx, axis=0)
#행 기준을 frop 하므로 axis=0
df.info()
# 4505건에서 320건을 제거하여 4185건이 나오는 걸 확인

<class 'pandas.core.frame.DataFrame'>
Int64Index: 4185 entries, 0 to 4504
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   지역명     4185 non-null   object
 1   규모구분    4185 non-null   object
 2   연도      4185 non-null   int64 
 3   월       4185 non-null   int64 
 4   분양가격    4185 non-null   int32 
dtypes: int32(1), int64(2), object(2)
memory usage: 179.8+ KB

 

10. 연도 별 평균 분양가격 확인

df.groupby('연도')['분양가격'].mean()

연도
2015    2788.707819
2016    2934.250000
2017    3143.311795
2018    3326.951034
2019    3693.422149
2020    3853.960526
Name: 분양가격, dtype: float64

 
 

11. 피벗 테이블 활용해서 확인

행인덱스: 연도열인덱스: 규모구분값: 분양가격
pd.pivot_table(df, columns='연도', index='규모구분',values='분양가격')
 
 
연도201520162017201820192020규모구분102㎡초과60㎡이하60㎡초과 85㎡이하85㎡초과 102㎡이하전체

 

2980.977778 3148.099476 3427.649746 3468.355932 4039.854839 4187.566667
2712.583333 2848.144279 3112.538071 3286.184783 3486.910112 3615.968750
2694.490196 2816.965686 2981.950980 3227.458128 3538.545918 3594.852941
2884.395833 3067.380435 3204.075145 3467.184211 3933.538462 4532.090909
2694.862745 2816.073529 3008.279412 3235.098522 3515.974490 3603.911765

12. 연도별, 규모별 평균 분양가격 확인

df.groupby(['연도', '규모구분'])['분양가격'].mean()

연도    규모구분         
2015   102㎡초과          2980.977778
       60㎡이하           2712.583333
       60㎡초과 85㎡이하     2694.490196
       85㎡초과 102㎡이하    2884.395833
      전체               2694.862745
2016   102㎡초과          3148.099476
       60㎡이하           2848.144279
       60㎡초과 85㎡이하     2816.965686
       85㎡초과 102㎡이하    3067.380435
      전체               2816.073529
2017   102㎡초과          3427.649746
       60㎡이하           3112.538071
       60㎡초과 85㎡이하     2981.950980
       85㎡초과 102㎡이하    3204.075145
      전체               3008.279412
2018   102㎡초과          3468.355932
       60㎡이하           3286.184783
       60㎡초과 85㎡이하     3227.458128
       85㎡초과 102㎡이하    3467.184211
      전체               3235.098522
2019   102㎡초과          4039.854839
       60㎡이하           3486.910112
       60㎡초과 85㎡이하     3538.545918
       85㎡초과 102㎡이하    3933.538462
      전체               3515.974490
2020   102㎡초과          4187.566667
       60㎡이하           3615.968750
       60㎡초과 85㎡이하     3594.852941
       85㎡초과 102㎡이하    4532.090909
      전체               3603.911765
Name: 분양가격, dtype: float64

 
 
이상으로 전처리를 완료하였다.
중간 중간에 전처리가 자꾸 안되어서 짜증이 났는데 그래도 하면서 재미있었다.
실제로는 저런 데이터는 더 무궁무진할텐데 끈기있게 분석하고 탐색하는 법도 길러야겠다.
 
Comments