Kaggle 도전기 - 다이아몬드 가격 예측

안녕하세요 jay입니다.
며칠전 처음으로 Kaggle 데이터로 분석을 해보았습니다.
(사실 전에도 몇번 시도를 해봤지만, 전반적인 흐름의 이해없이 해서 큰 의미가 없었습니다.)
Kaggle이란 데이터 사이언스 경쟁 플랫폼 혹은 
데이터 사이언티스트들 간의 커뮤니티(코드, 질의응답 등)입니다.

이번에 제가 도전한 데이터는 바로 다이아몬드 가격 예측입니다. 
저는 분석 beginner이니 제 분석 과정은 참고만 해주셨으면 좋겠습니다.
링크 : https://www.kaggle.com/shivam2503/diamonds


목차













0. Intro(전반적인 과정 소개)


1. Data load and EDA
Kaggle에서 Data를 load하고 EDA(Exploratory Data Analysis), 탐색적 데이터 분석을 통해 데이터들을 파헤쳐 보겠습니다.
2. Data Preprocessing
데이터를 품질을 올리는 데이터 전처리(Data Preprocessing) 과정을 다양하게 시도해보겠습니다.
3. Modeling
여러가지 feature들을 통해 다이아몬드의 가격을 예측하는 문제, 즉 회귀(Regression)문제이므로 다양한 회귀 알고리즘을 사용함으로써 각각의 알고리즘에 대한 성능을 비교해보도록 하겠습니다. 
4. Visualization and compare
각 알고리즘에 대한 성능을 시각화(Visualization)을 하고 비교(Compare)를 해서 최적의 알고리즘을 찾겠습니다. 또한 제 코드와 Kaggle에서 좋아요수를 많이 받은 Kernel과 비교를 해보겠습니다.





1. Data load and EDA



price : 우리가 예측해야할 수치, 즉 가격입니다.(기준 : 미국 달러)
carat : 다이아몬드의 무게를 의미합니다.
cut : 컷팅 품질을 의미합니다(Fair, Good, Very Good, Premium, Ideal 순으로 좋습니다)
color : 다이아몬드 색깔을 의미합니다. (J부터 시작해서 D까지, D로 갈수록 좋습니다.)
clarity : 다이아몬드의 선명도를 의미합니다. (I1(worst) ~ IF(best)로 구성되어있습니다.)
x : 다이아몬드의 길이(mm)
y : 다이아몬드의 넓이(mm)
z : 다이아몬드의 깊이(mm)
depth : 전체 깊이 퍼센티지를 의미합니다. (z / mean(x, y))
table : 가장 넓은 부분 기준으로 다이아몬드의 상단부분의 넓이를 의미합니다.

데이터에 다운로드 및 상세한 정보는 아래를 참조해주세요.
https://www.kaggle.com/shivam2503/diamonds

이제 본격적으로 코드를 통해 EDA를 해보도록 하겠습니다.

# load diamonds data from own directory

origin = pd.read_csv("./diamonds.csv")
origin.head()
Kaggle에서 다운받은 diamonds.csv를 불러왔습니다. 그 후 head를 통해 간단히 데이터 값을 확인했습니다.



# 53940 rows × 10 columns

drop_Unnamed = origin.copy()
drop_Unnamed.drop(['Unnamed: 0'],axis=1,inplace= True)
drop_Unnamed
Unnamed: 0이라는 필요없는 column이 들어와서 제거를 하고 출력을 해봤습니다. 53904 x 10로 이루어진 데이터라는 것을 알 수 있습니다.



drop_Unnamed.info()
info()를 통해 dataset의 null값, 데이터 갯수, 데이터타입등 다양한 정보를 얻을 수 있습니다. (object는 범주형 데이터(categorical data)를 의미합니다). 위를 봤을 때 결측치가 없다는 것을 알 수 있습니다. 전처리 과정에서 한 번 더 확인해보도록 하겠습니다.



# It shows only continuous data(No categorical)

drop_Unnamed.describe()
describe()를 통해, 연속형 데이터(continuous data)의 count, 표준편차, min, max값 등 다양한 수치를 보여줍니다. (Categorical data는 보여주지 않습니다)



# It shows histogram about only continuous data

drop_Unnamed.hist(bins = 10, figsize=(10,5))
hist를 통해 전반적인 연속형 데이터들의 분포를 확인할 수 있습니다. 데이터들의 분포가 정규화 형태로 나타나야 데이터의 불균형이 일어나지 않습니다.




# Categorical data

sns.countplot(x="color", data=drop_Unnamed, order="DEFGHIJ")
plt.show()
명목형 데이터(Categorical Data)에 대해 살펴볼 차례입니다. 먼저 color 데이터의 분포입니다. D부터 J까지의 색깔들이 있습니다. D로 갈수록 best입니다.(Kaggle 참조) D~J 사이의 데이터 갯수가 불균형하다는 것을 알 수 있습니다.



decreasing_cut = {0:"Ideal",1:"Premium",2:'Very Good',3:"Good",4:'Fair'}


sns.countplot(x="cut", data=drop_Unnamed, order=decreasing_cut.values())
plt.show()
다음은 cut 데이터의 분포입니다. Ideal, Premium, Fair등 5가지 cut 상태가 있습니다. Ideal일수록 좋은 cut입니다. color와 마찬가지로 갯수의 불균형이 일어난 것을 알 수 있습니다.



decreasing_clarity = {0:"IF",1:"VVS1",2:'VVS2',3:"VS1",4:'VS2',5:"SI1",6:"SI2",7:"I1"}

sns.countplot(x="clarity", data=drop_Unnamed, order=decreasing_clarity.values())
plt.show()
다음은 clarity 데이터의 분포입니다. I1으로 갈수록 투명도 상태가 좋습니다. (Kaggle 참고) clarity 또한 데이터 불균형이 일어난 것을 알 수 있습니다.                                                                                
이제 명목형 데이터, 연속형 데이터들의 분포를 자세하게 살펴봤습니다. 이제 저희가 살펴본 데이터의 문제점을 파악했으니 전처리를 진행해보도록 하겠습니다.





2. Data Preprocessing
데이터 전처리는 위와 같은 순서대로 진행을 하도록 하겠습니다. 먼저 NA(Not Available), 중복된 값을 제거 합니다. 그 다음 이상치(Outlier)를 제거 합니다. 그 다음 범주형 데이터를 One hot encoding 시켜줍니다. 그 다음 Feature Selection을 통해 상관도가 높은 최적의 feature들만 선택합니다. 

1. NA, 중복제거


# check N/A value

drop_Unnamed.isnull().sum()

"""
carat      0
cut        0
color      0
clarity    0
depth      0
table      0
price      0
x          0
y          0
z          0
dtype: int64
"""
 위에서 EDA를 했을때도 NA값이 없었고, 다시 한번 더 확인했을 때도 없다는 것을 알 수 있었습니다.


# counting duplicate value

drop_Unnamed.duplicated().sum() # 146
 중복된 값이 146개라는 것을 확인할 수 있습니다. 이를 제거해야합니다.


# check duplicate value

drop_Unnamed[drop_Unnamed.duplicated(keep = False)]
 중복된 모든 row들을 출력해주는 code입니다. 289개는 중복이 포함된 모든 row들까지 출력한 갯수를 의미합니다.


# remove duplicate rows
# 53940 => 53794

rmv_duplicated_row = drop_Unnamed.drop_duplicates()
rmv_duplicated_row
 중복된 모든 열들을 제거했습니다 53940개의 row가 53794로 줄었습니다.




2. 이상점 제거


# check outlier values for box-plot graph

import matplotlib.pyplot as plt
import seaborn as sns
sns.boxplot(data=rmv_duplicated_row['carat'])
plt.show()
 이상치를 제거하기 전 boxplot을 통해 이상치가 얼마나 있나 확인을 해보겠습니다. 아래와 같이 이상치가 많다는 것을 알 수 있습니다. 이제 모든 continuous형 data들의 이상치를 제거해보겠습니다.


# remove outlier method

def rmv_outlier(df, column_name):
       
    rmv_outlier_df = df[np.abs(df[column_name]-df[column_name].mean()) <= (3*df[column_name].std())]
       
    return rmv_outlier_df


# remove carat outlier
# 53794 => 53362
a = rmv_outlier(rmv_duplicated_row, "carat")

# remove depth outlier
# 53362 => 52703
b = rmv_outlier(a, "depth")


# remove x outlier
# 52703 => 52697
c = rmv_outlier(b, "x")

# remove y outlier
# 52697 => 52695
d = rmv_outlier(c, "y")

# remove y outlier
# 52695 => 52681

rmv_outlier_all = rmv_outlier(d, "z")
rmv_outlier_all
 이상치를 제거 하는 방법이 다양하게 있지만 제가 사용한 방법은 Z-score로, 1%에 해당하는 데이터들을 이상치라고 결정하는 방법입니다. 그래서 이상치를 제거하는 함수를 하나 만들고, 연속형 데이터 형태를 가진 컬럼들을 각각 이상치를 하나씩 제거했습니다. 그래서 53794에서 52681까지 데이터들을 제거를 했습니다.


# compare rmv outlier vs didnt for box-plot

import matplotlib.pyplot as plt
import seaborn as sns
sns.boxplot(data=a['carat'])
plt.show()
 이상치를 제거하기 전과 후의 boxplot을 비교해보겠습니다. 아래는 이상치를 제거한 후의 그래프입니다. 위의 그래프에 비해 이상치들이 많이 제거됐다는 것을 알 수 있습니다. 

 아래 왼쪽이 이상치를 제거한 후의 히스토그램이고, 오른쪽은 이상치를 제거하기 전 히스토그램입니다. 이상치를 제거한 후 히스토그램들은 대체적으로 전에 비해 정규분포의 형태를 보인다는 것을 알 수 있습니다.






3. One hot encoding









댓글