일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 파이썬
- PostgreSQL
- 그로스해킹
- 데이터분석
- not in
- SQL
- 데이터시각화
- GROUPBY
- hackerrank
- matplotlib
- 데이터리안 웨비나
- solvesql
- having
- 결측값
- join
- pandas
- airflow 설치
- Round
- seaborn
- SQLite
- 전처리
- MySQL
- 머신러닝
- Limit
- airflow.cfg
- 프로그래머스
- TRUNCATE
- Oracle
- 다중 JOIN
- SUM
- Today
- Total
Milky's note
부동산 데이터 전처리 본문
쉬운 데이터 분석 문제이다.
아직 시각화는 나오지 않고 단순히 데이터만 전처리하는 과정이지만, 하나씩 해보면서 끈기랑 통찰력을 길러야겠다.
코랩에서 풀었고, 깃에 소스도 올려놓았는데 블로그에도 정리할 겸 올리게 되었다.
추후에 시각화도 추가할 예정이다.
1. 라이브러리 로드
import pandas as pd
2. 데이터 프레임 로드 (https://bit.ly/ds-house-price)
df = pd.read_csv('https://bit.ly/ds-house-price')
df
서울 | 전체 | 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
서울 | 전체 | 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()
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
서울 | 전체 | 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='분양가격')
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
'데이터 분석 > 데이터분석 연습' 카테고리의 다른 글
가상 쇼핑몰 고객 주문데이터 3. 고객 이탈률 퍼널 분석 (1) | 2022.05.28 |
---|---|
가상 쇼핑몰 고객 주문데이터 2. 고객 Retention 코호트 분석 (0) | 2022.05.28 |
가상 쇼핑몰 고객 주문데이터 1. 데이터 전처리 (0) | 2022.05.28 |
카페 상권 분석 (2) | 2022.05.26 |
전국 주차장 데이터 (0) | 2022.05.25 |