03-06) MainQuest-02

slow_starter·2025년 7월 13일
0

모두의연구소-DS4기

목록 보기
27/30
post-thumbnail

두 번째 Quest 할 때 어이없는 실수를 저질렀던 기억이 났다.
현업 때도 간혹 저지르는 실수인데 두 테이블을 join할 때,
key값을 잘못 가져다 쓰면 행이 늘어나게 되는 부분이다.
(코드를 짤 때 실수를 안하는 것도 중요하지만, row건수가 말이 되는지
결국 그 필드에서의 배경 지식도 중요할 것 같음.)

01. 데이터 불러오기, 확인

  • 사실 Github에 다 정리되어 있는데, 복습하는 느낌으로 재정리
    하고 있다.
  • 이걸 세 번째 직장 구하고 나서 주말에 부랴부랴 한다는게 너무
    웃긴 일이지만, 산다는게 내가 컨트롤 할 수 없는 일들이 정말
    많다는 걸 배워가는 과정이 아닐까 싶다.
import pandas as pd
import numpy as np
import seaborn as sns
cc_df = pd.read_csv('data/fraud.csv')
pd.set_option('display.max_columns', 50) # 컬럼 수 최대 50개까지 보여줌!
# cc_df의 컬럼명과 자료형을 확인합니다.
cc_df.info()
# 기초적인 기술 통계량 계산
cc_df.describe()

02. 불필요한 컬럼 제거

  • 이건 제조업, 금융권, 공공기관, 정부(공무원) 어딜 가나 똑같을 것이다.
  • 결국 종사하는 업에 대한 배경지식이 쌓여야, 어느 컬럼이 필요하고,
    어느 컬럼이 불필요한지, 그리고 어떤 데이터를 결합해야 내가 원하는
    종류의 분석(회귀분석부터, 딥러닝까지)이 가능한지 '견적'이 나오거든.
  • 그래서 원래 데이터 분석가, 데이터 사이언티스트나 개발자가 오롯이
    자신의 '전문 역량' 만으로 커리어를 쌓아나가기는 좀 어렵다.
    • 오류가 좀 있다한들('25년 7월 기준), gpt plus, Gemini pro, anthropic 등은 어지간한 중급, 고급 개발자보다 코드를 더 잘 짠다. 훨씬 빠르게.
    • 반도체 회사에서 python, C++을 만지면, '반도체 엔지니어' 중에
      데이터 분석이나 프로그래밍에 특화된 사람이라고 봐야 합당할 듯
    • 마찬가지로 첫 번째 직장 동료들이 증권사, 카드사 등으로 이직한
      경우도 좀 있었는데 결국 그 회사 업에 맞는 일들을 하고 Python이나
      머신러닝, 딥러닝 등의 스킬은 부수적으로 따라가는 경우가 일반적인 듯.
# Q. job 컬럼에 포함된 값이 몇 종류인지 확인합니다.
# [[YOUR CODE]]
cc_df['job'].nunique()
# Q. cc_num 컬럼에 포함된 값이 몇 종류인지 확인합니다.
# [[YOUR CODE]]
cc_df['cc_num'].nunique()
# 불필요한 컬럼들을 제거합니다.
cc_df.drop(['merchant','first','last','street','city','state','zip','job','trans_num','unix_time'], axis = 1, inplace= True)

# cc_num 컬럼의 값을 기준으로 정렬합니다.
cc_df.sort_values('cc_num')

03. 구매금액의 z-score 계산

  • z-score는 고등학생 때부터 자주 들었던 개념이다. 현재의 경우에는
    '구매금액' 컬럼에서 '구매금액'의 평균을 빼주고 '구매금액' 컬럼의 표준편차로 나누면 된다.
# cc_num 컬럼의 값마다 데이터 개수를 계산합니다.
cc_df['cc_num'].value_counts()
amt_info = cc_df.groupby('cc_num')['amt'].agg(['mean','std']).reset_index()
amt_info.to_pickle('./amt_info.pkl')
# Q. cc_num 컬럼을 기준으로, cc_df와 amt_info 데이터를 합쳐서 cc_df에 저장합니다.
# (left merge를 수행합니다.)
# [[YOUR CODE]]
cc_df = cc_df.merge(amt_info, on = 'cc_num', how = 'left')
# Q. 결제금액(amt)의 z-score를 계산하여 amt_z 컬럼에 저장합니다.
# 평균: mean, 표준편차: std
# [[YOUR CODE]]
cc_df['amt_z'] = (cc_df['amt']-cc_df['mean'])/(cc_df['std'])
# z-score 계산이 완료되었으니 mean, std 컬럼을 제거합니다.
cc_df.drop(['mean','std'], axis = 1, inplace = True)
# cc_num, category 컬럼의 값마다 결제금액(amt)의 평균, 표준편차를 계산하여 cat_info에 저장합니다.
cat_info = cc_df.groupby(['cc_num','category'])['amt'].agg(['mean','std']).reset_index()
cat_info.to_pickle('./cat_info.pkl')
# Q. cc_num 컬럼을 기준으로, cc_df와 cat_info 데이터를 합쳐서 cc_df에 저장합니다.
# (left merge를 수행합니다.)
# [[YOUR CODE]]
cc_df = cc_df.merge(cat_info, on = ['cc_num','category'], how = 'left') # on이 key값, how가 join 방법
cc_df.shape
# Q. 결제금액(amt)의 z-score를 계산하여 cat_amt_z 컬럼에 저장합니다.
# 평균: mean, 표준편차: std
# [[YOUR CODE]]
cc_df['cat_amt_z'] = (cc_df['amt'] - cc_df['mean'])/cc_df['std']
# z-score 계산이 완료되었으니 mean, std 컬럼을 제거합니다.

cc_df.drop(['mean','std'], axis =1 , inplace = True)

04. 결재 시간 관련 feature 분석

# Q. trans_date_trans_time 컬럼에서 시간 값을 추출하여 hour 컬럼에 저장합니다.
# (힌트: datetime 자료형을 이용합니다.)
# [[YOUR CODE]]
cc_df['hour'] = pd.to_datetime(cc_df['trans_date_trans_time']).dt.hour
# 결제시간을 morning, afternoon, night, evening으로 분류하기 위해 함수를 정의합니다.

def hour_func(x):
    if (x >= 6) & (x < 12):
        return 'morning'
    elif (x >= 12) & (x < 18):
        return 'afternoon'
    elif (x >= 18) & (x < 23):
        return 'night'
    else:
        return 'evening'
# Q. hour 컬럼에 hour_func 함수를 적용한 값을 hour_cat 컬럼에 저장합니다.
# [[YOUR CODE]]
cc_df['hour_cat'] = cc_df['hour'].apply(lambda x: hour_func(x))
# Q. 시간대별로 데이터 수를 계산하여 출력합니다.
# [[YOUR CODE]]
cc_df['hour'].value_counts().sort_index() # value_counts?로?
# cc_num 컬럼의 값마다 amt 컬럼의 데이터 수를 계산하여 all_cnt 변수로 저장합니다.
all_cnt = cc_df.groupby('cc_num')['amt'].count().reset_index()
# cc_num, hour_cat 컬럼의 값마다 amt 컬럼의 데이터 수를 계산하여 hour_cnt 변수로 저장합니다.
hour_cnt = cc_df.groupby(['cc_num','hour_cat'])['amt'].count().reset_index()
# Q. cc_num 컬럼을 기준으로 hour_cnt와 all_cnt를 합칩니다.
# (hour_cnt에서 left merge를 수행합니다.)
# [[YOUR CODE]]
hour_cnt = hour_cnt.merge(all_cnt, on='cc_num',how='left')
# Q. amt_x와 amt_y 컬럼의 이름을 각각 hour_cnt, total_cnt로 변경합니다.
# [[YOUR CODE]]
hour_cnt = hour_cnt.rename(columns={'amt_x':'hour_cnt','amt_y':'total_cnt'})
# Q. 전체 거래 건수(total_cnt)에 대한 시간대별 거래 건수(hour_cnt)의 비율을 계산하여 
# hour_perc 컬럼에 저장합니다.
# [[YOUR CODE]]
hour_cnt['hour_perc'] = hour_cnt['hour_cnt'] / hour_cnt['total_cnt']
hour_cnt = hour_cnt[['cc_num','hour_cat','hour_perc']]
hour_cnt.to_pickle('./hour_cnt.pkl')
# Q. cc_num, hour_cat 컬럼을 기준으로 cc_df와 hour_cnt 데이터를 합칩니다.
# (cc_df에서 left merge를 수행합니다.)

# [[YOUR CODE]]
cc_df = cc_df.merge(hour_cnt, on = ['cc_num','hour_cat'], how='left')
# 시간 관련 feature 분석이 완료되었으므로 불필요해진 컬럼들을 제거합니다.
cc_df.drop(['trans_date_trans_time', 'hour', 'hour_cat'], axis =1 , inplace = True)

05. 거리 관련 feature 분석

# 거리 계산에 필요한 geopy 라이브러리를 설치합니다.
!pip install geopy
from geopy.distance import distance
# 이렇게 위도와 경도 값으로 두 지점 사이의 거리를 구할 수 있습니다.
distance((48.8878, -118.2105), (49.159047, -118.186462)).km
# 고객의 위치와 상점의 위치 사이의 거리를 계산하여 distance 컬럼에 저장합니다.
# (모든 데이터가 계산되므로 실행 시간이 오래 걸릴 수 있습니다.
cc_df['distance'] = cc_df.apply(lambda x: distance((x['lat'], x['long']), (x['merch_lat'], x['merch_long'])).km, axis = 1)
from datetime import datetime
# 데이터 10000개만 계산해도 시간이 이렇게 걸립니다.

start_time =  datetime.now()
cc_df.head(10000).apply(lambda x: distance((x['lat'], x['long']), (x['merch_lat'], x['merch_long'])).km, axis = 1)
datetime.now() - start_time
# Q. cc_num 컬럼의 값마다 distance의 평균, 표준편차를 계산하여 dist_info 변수에 저장합니다.

# [[YOUR CODE]]
dist_info = cc_df.groupby(['cc_num'])['distance'].agg(['mean','std']).reset_index()
# dist_info
dist_info.to_pickle('./dist_info.pkl')
# Q. cc_num 컬럼을 기준으로 cc_df와 dist_info 데이터를 합칩니다.
# (cc_df에서 left merge를 수행합니다.)

# [[YOUR CODE]]
cc_df = cc_df.merge(dist_info, on = 'cc_num', how='left')
# Q. distance 값의 z-score를 계산하여 dist_z 컬럼에 저장합니다.
# [[YOUR CODE]]
cc_df['dist_z'] = (cc_df['distance'] - cc_df['mean'])/(cc_df['std'])
# 불필요해진 컬럼들을 제거합니다.
cc_df.drop(['lat','long','merch_lat','merch_long','mean','std'], axis = 1, inplace = True)

06. 나이 feature 만들기

# Q. dob 컬럼에서 연도 값만 추출하여 dob 컬럼에 저장합니다.

# [[YOUR CODE]]

cc_df['dob'] = pd.to_datetime(cc_df['dob']).dt.year
# cc_df.head()

07. 범주형 데이터의 one-hot encoding

# 범주형 컬럼 'category'에 몇 종류의 값이 있는지 확인해봅시다.
cc_df['category'].nunique()
# Q. cc_df의 범주형 데이터에 원-핫 인코딩을 적용합니다.
# (drop_first 옵션은 True로 설정합니다.)

# [[YOUR CODE]]
cc_df = pd.get_dummies(cc_df, columns=['category', 'gender'], drop_first=True)
# 이제 불필요해진 cc_num 컬럼을 제거합니다.
cc_df.drop('cc_num', axis = 1, inplace = True)
profile
2025화이팅!

0개의 댓글