과제를 하면서 유용하게 만들었던 부분들을 정리해보고자 한다.
아래의 git_gist에서 풀 코드를 확인 할 수 있다.
https://gist.github.com/GiJungCho/08f767a46a3a07742f59d34ae8451dcf
==전체적 과정 ==
원핫 인코딩을 사용하기 위해 컬럼을 타입별로 나누었고, (ex: 명목형 변수=> object)타입을 변환했습니다. 변환이 되지 않는 컬럼은 이상치 값을 None값로 만든후 변환하였습니다.
파생변수로는 원하는 몸무게와 현재 몸무게를 뺸 컬럼을 생성하였습니다.
힙과 엉덩이 사이즈의 null값을 성,몸무게,키의 평균으로 대체하였습니다.
그럼에도 각각 221,649개의 데이터가 부족하여 그 둘은 키와 몸무게의 평균값으로 null값을 보간하였습니다.
그러나 아직 각각 189개 592개의 null값이 존재하여 그 둘은 몸무게와 키로 sort하여 값을 기준으로 선형보간하였습다.
개인을 식별하는 컬럼은 3개나 되서 id컬럼 social_di1컬럼 zip_code컬럼을 모두 합쳐 ID2컬럼으로 만들고 삭제하였습니다.
더미화에 방해가 되는 컬럼은 직접 커스텀하여 원핫 인코딩 하였습니다. (ex:"1,2,3" 형식)
이후 나머지 object는 sklearn패키지로 더미화 하였습니다.
== 세부 내용 ==
import os
import numpy as np
import pandas as pd
import math #math 모듈을 먼저 import해야 한다.
import matplotlib.pyplot as plt
path = os.getcwd() # 모델 저장할 경로
os_file_list = os.listdir(path)
def data_sorting(data):
All_data = {}
data_key_list = list(data.keys())
for i in range(len(data_key_list)):
All_data[data_key_list[i]] = data[data_key_list[i]]
return All_data
파이썬 파일이 있는 경로를 읽어들여서 거기에 있는 파일 목록을 키로 가져온다.
예를들어 엑셀 파일이 있다면 모든 시트의 이름을 All_data이라는 딕셔너리안에 데이터 프레임 형태로 저장하는 꼴이다.
각각의 데이터들의 설명을 확인해 본 결과, object 타입과 아닌것을 구분해야 할 일이 생겼다.
수치형 변수로 읽어드림에도 object로 해석할 변수(ex)성별)이 있기 때문에 변수를 나누어 주었다.
float_col = ['height', 'weight','want_diet', 'waist' , 'heap' , 'bmi', 'p_price',"p_quantity"]
str_col = ['occupation', 'sex', 'married', 'dise', 'loss_part', 'diet_purpose', 'diet', 'order_id', 'pfid', 'p_name', 'ID_2']
date_col = ["p_created" , "created"]
del_col = ["seq_num","id", "social_id1" , "zip_code"]
해당 전처리 과정을 손보면서 문제가 생겼다.
타입변환이 되지 않는것이다. 고객데이터를 확인하다보니 허리사이즈를 27-28 이런식으로 적어놓은 것이다.
해당 방법은 27.5로 변환하는것이 적절하겠지만 너무나도 많은 데이터와 "??" 등으로 적어놓은 분들이 많아 일일히 전처리 하기에는 시간이 오래걸린다는 점이 있었다. 물론 해당 방법은 기업과제를 할 경우에는 일일히 고쳐주는것이 바람직하다고 생각한다.
def type_change_2(df,change_type= float):
for i,v in enumerate(df):
try:
df[i] = float(v)
except:
df[i] = None
return df
def type_change(df,float_col, str_col, date_col, del_col):
col_list = list(data.columns)
for i,v in enumerate(col_list):
print(v)
if v in float_col:
try:
df[v] = df[v].astype(float)
except:
print(df[v],v,"타입변환 실패한 컬럼, type_change_2 실행으로 변환안되는값 None")
type_change_2(df[v],change_type = float)
elif v in str_col:
df[v] = df[v].astype(str)
elif v in date_col:
try:
df[v] = pd.to_datetime(df[v], format='%Y-%m-%d %H:%M', errors='raise')
except:
print(df[v],"시간 컬럼이 안변함")
pass
elif v in del_col:
del df[v]
return df
data = type_change(data,float_col, str_col, date_col, del_col)
위 방법은 데이터 프레임의 타입을 변환시키는데 변환이 전체로 한번에 되지 않는경우 해당 컬럼안으로 들어가서 문제가 되는 컬럼을 type_chage_2 에서 None 형태로 변환시켜 두고 나중에 타입을 강제로 변환하게 만들었다.
한마디로 이상치들에 None값을 한번에 적용했다
또 파생변수로 현재 몸무게와 원하는 체중을 빼서 뺴야할 체중을 뜻하는 파생변수를 만들었다.
data["want_diet - weight"] = data["weight"] - data["want_diet"]
이런 부분은 인공지능을 함에 있어서 중요하다고 생각한다.
여기까지 완료했는데
na값이 많이 존재하는것을 확인할 수 있었다.
그래서 키 몸무게 성별을 기준으로 평균을 적용해서 이상치를 채웠다.
data = data.groupby(["height","weight","sex"]).apply(lambda x: x.fillna(x.mean())) # na값을 집단별 평균값으로 대체한다.
그렇지만 아직도 다 na값을 채우지 못했기 때문에 한번 더 키와 몸무게를 적용하여 집단의 평균값으로 대체하였다.
data = data.groupby(["height","weight"]).apply(lambda x: x.fillna(x.mean())) # na값을 집단별 평균값으로 대체한다.
그리고 마지막으로 개인을 판단하는 컬럼이 여기저기 떨어져 있었다. 해당 부분을 한개로 합치고 나머지 컬럼은 드롭했다.
data["ID_2"] = data["id"] + data["social_id1"] + data["zip_code"] # data["ID_2"] = str(data["id"]) + "_" + str(data["social_id1
data = data.drop(["p_name","order_id","zip_code"] , axis = 1)
그 이후 제품을 집단별로 나누었는데
DC = ['GDCBEST' ,'GDCMAIL' ,'PDCGOOD']
DEaT = ['MDFFUNC', 'PDFFUNC', 'PDFHSFD', 'MDFMEAL', 'PDFMEAL' ,'MDFFIBE','PDFFIBE']
DE = ['MDEPART' ,'MDEETCC', 'MDEHLCE', 'MDEHRWE']
EM = ['MDGVDCD', 'MDBWEEK' ,'MDGLIKE' ,'MDGFASH', 'MDGBEAT']
data["제품분류"] = 0
for i,v in enumerate(data["pfid"]):
if v[:7] in DC:
data["제품분류"][i]= "DC"
elif v[:7] in DEaT:
data["제품분류"][i]= "DEaT"
elif v[:7] in DE:
data["제품분류"][i]= "DE"
elif v[:7] in EM:
data["제품분류"][i]= "EM"
data.loc[data["제품분류"] == 0,"제품분류"] = "제품분류군 이외"
del data["pfid"]
해당 부분은 원 핫 인코딩을 쓰고 싶지만 제품분류군은 그렇게 쓸수가 없어서 조금 불편하지만 수동으로 구성하였다.
이런식으로 크게 군집화를 한 후 pd.get_dummies를 이용해서 편하게 원핫 인코딩을 적용하였다.
data = pd.get_dummies(data[use_col],dummy_na= False,drop_first = True)
drop_first 옵션은 예를들어 성별이 있다면 0과 1로 인코딩 되서 나올 수 있지만,
0을 제외한 1만 생각해서 0과 1로 한 컬럼에 표현하게 하는 옵션이다.
만약 3가지 분류가 있다면 2가지 분류만 표시하는것이다 둘다 아닌것은 제외하고 표현가능하기 때문이다.
dummy_na옵션은 na값은 na값으로 분류군을 추가하는것이다. 여기서는 na값을 모두 사용해서 생각할 필요가 없지만 나중에 유용하게 적용할 수 있는 옵션일 것이다.
여기까지 하고 정규화는 잘 생각해야 한다고 생각한다 이상치가 많으면
robust 스칼라를 써도 될것이고 아니면 스텐다드 스칼라를 써도 된다. 일단 스텐다드를 적용해보았다.
여기서는 나중에 내가 구성한 모델이 더 잘 맞추는 방향의 스칼라를 적용하면 좋을 것 같다.
from sklearn.preprocessing import StandardScaler
object_list = data.select_dtypes('float').columns.values
Scaler = StandardScaler()
data[object_list] = Scaler.fit_transform(data[object_list])
'파이썬 기초 > 데이터 프레임 다루기' 카테고리의 다른 글
데이터 프레임 모든 컬럼 시각화(plot plt) (0) | 2022.04.28 |
---|---|
데이터 프레임 여러조건에 부합하는 행 가져오기 (0) | 2022.04.27 |