1. 주제 : 상점 신용카드 매출 예측

  • 2019.07 ~ 2019.10 에 DACON에서 주최한 상점 신용카드 매출 예측 경진대회의 데이터

  • 데이터 제공자 : 핀테크 기업 FUNDA

  • 문제 : 2019년 2월 28일까지의 카드 거래 데이터를 이용해 2019년 3월 1일 ~ 5월 31일 까지의 상점별 3개월 총 매출 예측하기

2. 데이터 소개 및 문제 정의

데이터 소개

데이터 출처 : DACON

funda_train.csv : 모델 학습용 데이터

  • store_id : 상점의 고유id

  • card_id : 사용한 카드의 고유 id

  • card_company : 비식별화된 카드 회사

  • transcated_date : 거래 날짜

  • transacted_time : 거래 시간

  • installment_term : 할부 개월 수

  • region : 상점이 위치한 지역

  • type_of_business : 상점 업종

  • amount : 거래액 (단위: 미상)

문제 정의

  • 주어진 데이터는 거래액 (amount) 인데, 예측해야 할 값은 ‘상점 별 매출액’ 이다.

  • 또한, store_id별 3월 1일 ~ 5월 31일 매출(3개월)의 총 합을 예측해야 한다.

  • 각 상점별 특정 기간 기준 매출 데이터의 특징을 기반으로 + 3개월 뒤의 매출액을 예측하는 식으로 모델이 구축되야 할 것 같다.

  • 그 특정 기간은 정답 format과 같은 3개월을 기준으로 상점별 특징을 잡는 것이 좋을 것 같다.

3. 데이터 로드 및 살펴보기

Train data 불러오기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import os

# 캔버스 사이즈 적용
plt.rcParams["figure.figsize"] = (12, 9)

# 컬럼 전체 확인 가능하도록 출력 범위 설정
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 10000)

# 불필요한 경고 표시 생략
import warnings
warnings.filterwarnings(action = 'ignore')

# pandas 결과값의 표현 범위 소수점 2자리수로 변경
pd.options.display.float_format = "{:.2f}".format

# 파일 로드위한 directory 확인 및 현재 경로로 설정
a = os.getcwd()
os.chdir(a)
1
df = pd.read_csv("funda_train.csv")
1
2
3
print(df.info())
print(df.describe())
df.head()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6556613 entries, 0 to 6556612
Data columns (total 9 columns):
 #   Column            Dtype  
---  ------            -----  
 0   store_id          int64  
 1   card_id           int64  
 2   card_company      object 
 3   transacted_date   object 
 4   transacted_time   object 
 5   installment_term  int64  
 6   region            object 
 7   type_of_business  object 
 8   amount            float64
dtypes: float64(1), int64(3), object(5)
memory usage: 450.2+ MB
None
        store_id    card_id  installment_term      amount
count 6556613.00 6556613.00        6556613.00  6556613.00
mean     1084.93 2268127.02              0.14    10435.11
std       615.22 1351057.85              1.19    31040.31
min         0.00       0.00              0.00 -2771428.57
25%       586.00 1088828.00              0.00     2142.86
50%      1074.00 2239304.00              0.00     4285.71
75%      1615.00 3438488.00              0.00     8571.43
max      2136.00 4663856.00             93.00  5571428.57
store_id card_id card_company transacted_date transacted_time installment_term region type_of_business amount
0 0 0 b 2016-06-01 13:13 0 NaN 기타 미용업 1857.14
1 0 1 h 2016-06-01 18:12 0 NaN 기타 미용업 857.14
2 0 2 c 2016-06-01 18:52 0 NaN 기타 미용업 2000.00
3 0 3 a 2016-06-01 20:22 0 NaN 기타 미용업 7857.14
4 0 4 c 2016-06-02 11:06 0 NaN 기타 미용업 2000.00
1
2
# 결측치 확인
df.isnull().sum()
store_id                  0
card_id                   0
card_company              0
transacted_date           0
transacted_time           0
installment_term          0
region              2042766
type_of_business    3952609
amount                    0
dtype: int64
1
2
3
4
# 정답지 살펴보기
submission_df = pd.read_csv("submission.csv")
print(submission_df.info())
submission_df.head()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1967 entries, 0 to 1966
Data columns (total 2 columns):
 #   Column    Non-Null Count  Dtype
---  ------    --------------  -----
 0   store_id  1967 non-null   int64
 1   amount    1967 non-null   int64
dtypes: int64(2)
memory usage: 30.9 KB
None
store_id amount
0 0 0
1 1 0
2 2 0
3 4 0
4 5 0
1
submission_df.isnull().sum()
store_id    0
amount      0
dtype: int64
1
submission_df['amount'].unique()
array([0], dtype=int64)

제출 파일인 submission_df의 amount가 모두 0인 것으로 보아, 예측한 결과값을 amount에 추가해야 할 것으로 보인다.

EDA

store_id 데이터 탐색

1
2
print(df['store_id'].unique())
print(submission_df['store_id'].unique())
[   0    1    2 ... 2134 2135 2136]
[   0    1    2 ... 2134 2135 2136]
1
2
print(len(df['store_id']))
print(len(submission_df['store_id']))
6556613
1967
  • train의 store_id는 transcate_date 별 매출 (동일 매장에서 중복 매출 발생) 하여 수가 더 많음

  • 두 데이터 set의 unique() 값은 일치 -> 최종적으로 train 데이터를 통해 ‘매장 별 3개월간 총 매출’ 형식으로 prediction 을 만들어야 함

card_id 데이터 탐색

1
df['card_id'].unique()
array([      0,       1,       2, ..., 4663854, 4663855, 4663856],
      dtype=int64)
1
2
sns.displot(x = df['card_id'], kde=True)
plt.show()

1
2
3
4
5
6
7
# 데이터 범주가 너무 넓어서 상위 20개 분포만 재확인
card_id = df['card_id'].value_counts()[:20].index
counts = df['card_id'].value_counts()[:20]

bar_plot = sns.barplot(x=card_id, y=counts, alpha=0.9, palette='rocket')
plt.xticks(rotation=90)
plt.show()

  • 전체 6556613 개의 데이터 중 겹치지 않는 자료가 4663856개

  • card_id는 한 고객이 여러개의 카드를 가질 가능성도 있고, 특정 카드를 사용할때 매출과 직접적으로 연관을 지을 수 있는 별도의 feature가 없음

  • 만약, 카드별 할인율이나 , 프모로션 제도 등에 대한 feature가 있다면 활용이 가능할 수 도 있음.

  • 현재로선 예측 결과에 직접적인 영향을 주긴 어려운 feature일 것이라 판단됨.

  • drop 하는 것이 바람직해 보인다.

card_company 데이터 탐색

1
df['card_company'].unique()
array(['b', 'h', 'c', 'a', 'f', 'e', 'g', 'd'], dtype=object)
1
2
3
x = df['card_company'].value_counts().index
y = df['card_company'].value_counts()
sns.barplot(x=y, y=x, alpha=0.9, palette='mako');

  • 비식별화된 카드회사 정보인데, 알파벳 순 = value_counts()가 일치

    • 너무 짜여진 데이터 같음 => 모델이 잘못된 방식으로 데이터 인지할 가능성 우려
  • 추가적으로, card_id 와 동일한 이유로 활용하기도 어려움

  • drop 하는 것이 바람직해 보인다.

transacted_date 데이터 탐색

1
2
print(df['transacted_date'])
pd.DataFrame(df['transacted_date']).isnull().sum() #결측치 확인
0          2016-06-01
1          2016-06-01
2          2016-06-01
3          2016-06-01
4          2016-06-02
              ...    
6556608    2019-02-28
6556609    2019-02-28
6556610    2019-02-28
6556611    2019-02-28
6556612    2019-02-28
Name: transacted_date, Length: 6556613, dtype: object
transacted_date    0
dtype: int64
  • df의 시간 범위: 2016-06-01 ~ 2019-02-28

  • 예측에 활용할 주요 feature

  • 예측은 매장 별 3개월 총 매출이므로 ‘일 단위’‘월 단위’ 데이터로 통합해야 함

installment_term 데이터 탐색

1
df['installment_term'].value_counts(sort=True)
0     6327632
3      134709
2       42101
5       23751
6       10792
10       6241
4        4816
12       2699
60       1290
7         553
8         413
24        404
9         349
18        332
15        130
20        116
80         83
11         47
30         43
36         36
16         23
14         12
63          8
83          6
65          6
19          4
72          4
13          3
93          2
23          2
35          2
82          2
22          1
17          1
Name: installment_term, dtype: int64
1
2
#결측치 확인
pd.DataFrame(df['installment_term'].value_counts()).isnull().sum()
installment_term    0
dtype: int64
  • 전체 6556613 개의 데이터 중 일시불인 경우가 6327632 로 대부분이다.

  • 대부분이 일시불 값이므로 할부 T/F로 이진화 하여 feature로 사용하는 것이 더 유용할 것이다.

1
2
3
4
# 시각화 위해 데이터 이진화
df['installment_term2'] = (df['installment_term'] > 0).astype(int) # bool to int (True=1, False=0)
installment = df['installment_term2'].value_counts() 
installment = list(installment)
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
# canvas 크기 설정
plt.figure(figsize=(15,5))


# 그래프1
plt.subplot(121)

# 데이터 추출
count_installment_terms = df['installment_term'].value_counts(sort=True)
count_installment_terms = count_installment_terms[:5,]

# 그래프 1 시각화
sns.barplot(count_installment_terms.index, count_installment_terms.values, alpha=0.8)
plt.title('Top5 Installment term', fontsize = 15)
plt.ylabel('Counts', fontsize=12)
plt.xlabel('installment term', fontsize=12)


# 그래프2
plt.subplot(122)
x = ['Intallment_true', 'Installment_false']
y = installment

# 그래프2 시각화
sns.barplot(x, y, alpha=0.8, palette='crest')
plt.ylabel('Counts', fontsize=12)
plt.title('Installment Payment Status (T/F)', fontsize=15)

plt.show()

type_of_business 데이터 탐색

1
2
print((df['type_of_business'].value_counts())) #데이터 분포 확인
pd.DataFrame(df['type_of_business'].value_counts()).isnull().sum() #결측치 확인
한식 음식점업                     745905
두발 미용업                      178475
의복 소매업                      158234
기타 주점업                      102413
치킨 전문점                       89277
                             ...  
곡물 및 기타 식량작물 재배업               569
주방용품 및 가정용 유리, 요업 제품 소매업       551
배전반 및 전기 자동제어반 제조업             533
그 외 기타 생활용품 도매업                519
신선식품 및 단순 가공식품 도매업             231
Name: type_of_business, Length: 145, dtype: int64
type_of_business    0
dtype: int64
1
2
3
4
# 종류가 너무 많아 상위 20개만 확인
x = df['type_of_business'].value_counts()[:20].index
y = df['type_of_business'].value_counts()[:20]
sns.barplot(x=y, y=x, alpha=0.9, palette='YlOrRd');

  • 범주형 변수

  • 업종 종류가 너무 다양해서 type of business raw 데이터로는 예측을 위한 특징으로 사용하기는 어려울 것으로 판단된다.

  • 그렇다고 dummy화 하기에는 수가 너무 많음

  • store_id와는 명확하게 매칭이 되는 데이터 -> transacted_date 기준으로 분류하면 사용이 가능 할 듯.

region 데이터 탐색

1
df['region'].value_counts().head()
경기 수원시    122029
충북 청주시    116766
경남 창원시    107147
경남 김해시    100673
경기 평택시     82138
Name: region, dtype: int64
1
pd.DataFrame(df['region']).describe()
region
count 4513847
unique 180
top 경기 수원시
freq 122029
1
2
# 결측치 확인
pd.DataFrame(df['region']).isnull().sum()
region    2042766
dtype: int64
1
2
3
4
# 지역이 너무 많아 상위 20개만 확인
x = df['region'].value_counts()[:20].index
y = df['region'].value_counts()[:20]
sns.barplot(x=y, y=x, alpha=0.9, palette='viridis');

  • 범주형 변수

  • type of business 와 마찬가지로 지역의 unique value가 너무 많음 -> raw 데이터로는 예측을 위한 특징 으로 사용하기에 부적합

  • region별 매출 특성을 파악 하는 것에는 사용이 가능할 듯.

변수 탐색 결론

  • store_id : 각 상점을 구분지을 중요 feature. 변형없이 사용

  • card_id, card_company : 매장 별 매출액 분석에 유의미 하지 않으므로 drop (도메인지식 기반 판단)

  • intallment_term : 일시불(0)인 데이터가 압도적으로 많음 -> 일시불 / 할부 로 데이터 이원화 하는 것이 유용

  • type_of_business , region : 범주형 데이터, 다만 range가 너무 커서 dummy할 수는 없음. 시간 & store 기준으로 데이터를 병합하면 매출 특성을 구분하는데 사용할 수 있을 것으로 예상됨

  • transcade_time : 예측해야할 값은 ‘월 단위’. 특정 시간대의 매출 경향성이 전체 월 매출에 영향을 끼치지 않을 것이라 판단

    • 추가로 transcade_date 와 중복되는 경향이 있어 배제

  • transcade_date : ‘일’ 단위 데이터 -> ‘월 단위’ 로 변경 필요 : group by의 기준이 되는 데이터가 되어야 함 (분석의 key value)

    • standard_t(기준 월) 을 기준으로 매출 합계를 예측 해야 함

    • standard_t-2, standard_t-1, standard_t 3개의 데이터 기반 -> standard_t+1, standard_t+2, standard_t+3 을 예측 하는 방식

    • e.g) 2016년 1월 , 2016년 2월, 2016년 3월 매출 데이터 기반 -> 2016년 4월 매출, 2016년 5월 매출, 2016년 6월 매출을 예측하는 식으로 반복 학습 방식으로 3년치 데이터 기반으로 최종적으로 2019년 3월 ~ 5월 매출 예측 (중첩된 예측과 검증으로 예측력 상승을 기대)

    • 연도 & 월 로 하는 경우 데이터 구분이 명확하지 않을 가능성 있음. 특정 시점을 기준으로 Index 식으로 구분하는 것이 더 모델이 인지를 잘 할 것으로 예상

Data Processing - Train data

transcated_data - 파생변수 생성

년/월 추출

1
2
3
4
5
6
7
8
# .str.split으로 년/월 추출

# year
df['transacted_year'] = df['transacted_date'].str.split('-', expand = True).iloc[:, 0].astype(int)

# month
df['transacted_month'] = df['transacted_date'].str.split('-', expand = True).iloc[:, 1].astype(int)
df.head()
store_id card_id card_company transacted_date transacted_time installment_term region type_of_business amount installment_term2 transacted_year transacted_month
0 0 0 b 2016-06-01 13:13 0 NaN 기타 미용업 1857.14 0 2016 6
1 0 1 h 2016-06-01 18:12 0 NaN 기타 미용업 857.14 0 2016 6
2 0 2 c 2016-06-01 18:52 0 NaN 기타 미용업 2000.00 0 2016 6
3 0 3 a 2016-06-01 20:22 0 NaN 기타 미용업 7857.14 0 2016 6
4 0 4 c 2016-06-02 11:06 0 NaN 기타 미용업 2000.00 0 2016 6
  • transacted_date의 시작점이 2016년 6월 1일 이므로 transacted_year에서 2016을 빼고 ‘month’를 기준으로 데이터를 분류하는 index번호처럼 생성

계산 방식은 다음과 같다.

1
2
3
standard_t = (연도-2016)*12 + '월'

  • 2016년의 경우 6월 =6, 7월 =7

  • 2017년의 경우 1월 = 12, 2월 = 24

  • 위와 같이 각 연도별 월을 구분지을 수 있게 가공된다.

기준 시점이 될 std_mth (= standard_month) 생성

1
2
3
# 데이터 병합을 위해 시간 데이터를 standard_t 로 변경하고, 불필요한 컬럼은 drop
df['std_mth'] = (df['transacted_year'] - 2016) * 12 + df['transacted_month']
df.drop(['transacted_year', 'transacted_month', 'transacted_date', 'transacted_time'], axis = 1, inplace = True)
1
df['std_mth'].unique()
array([ 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, 32, 33, 34, 35, 36, 37, 38])

업종 특성, 지역, 할부 평균 - 파생변수 생성

installment_term - 매장별 평균 할부 비율

  • EDA에서 본 바와 같이 대부분이 일시불이므로 일시불 / 할부로 범주를 이원화 하여 사용 (전체 할부 개월 수 로 하기엔 너무 범위가 큼)

  • 다만, 단순 할부 여부는 동일 매장에서 결제 건수가 여러건 발생 하므로 T/F로 입력할 수가 없다. -> 매장별 평균 할부개월 비율로 전처리

1
2
df['installment_term'] = (df['installment_term'] > 0).astype(int) # bool to int (True=1, False=0)
df['installment_term'].value_counts()
0    6327632
1     228981
Name: installment_term, dtype: int64
1
2
3
# 각 매장 기준으로 할부 기간의 평균 계산
installment_term_per_store = df.groupby(['store_id'])['installment_term'].mean()
installment_term_per_store.head()
store_id
0   0.04
1   0.00
2   0.08
4   0.00
5   0.08
Name: installment_term, dtype: float64
1
2
# 결측치 확인
pd.DataFrame(installment_term_per_store).isnull().sum()
installment_term    0
dtype: int64

region - group by로 데이터 셋팅

  • 범주형이지만, 종류가 너무 많아 dummy 하여 사용하기는 어려움 -> 활용을 위해 파생변수 생성 필요 (group by)

  • 결측치가 2042766 개 존재함

  • 결측치를 drop하기에는 너무 많은 데이터 -> 전처리를 통해 group by에 포함되도록 해야 함

1
2
3
# 결측치 전처리
df['region'].fillna('미분류', inplace = True)
df['region'].value_counts().head()
미분류       2042766
경기 수원시     122029
충북 청주시     116766
경남 창원시     107147
경남 김해시     100673
Name: region, dtype: int64
1
2
# 결측치 재확인
df['region'].value_counts().isnull().sum()
0

type_of_business - 데이터 셋팅

  • 범주형이지만, 종류가 너무 많아(145개) dummy 하여 사용하기는 어려움 -> 활용을 위해 파생변수 생성 필요 (group by)

  • 결측치가 3952609 개 존재함

  • 결측치를 drop하기에는 너무 많은 데이터 -> 전처리를 통해 group by에 포함되도록 해야 함

1
2
3
# groupby에 결측을 포함시키기 위해, 결측을 문자로 대체
df['type_of_business'].fillna('미분류', inplace = True)
df['type_of_business'].value_counts().head()
미분류        3952609
한식 음식점업     745905
두발 미용업      178475
의복 소매업      158234
기타 주점업      102413
Name: type_of_business, dtype: int64
1
2
# 결과 재확인
df['type_of_business'].value_counts().isnull().sum()
0

불필요한 변수 제거

  • card_id, card_company는 특징으로 사용하기에는 범주가 너무 세밀하고, 특징으로서 유의하지 않을 것이라 판단되므로 drop
1
df.drop(['card_id', 'card_company'], axis = 1, inplace = True)

중복 데이터 처리

1
2
3
# 'store_id', 'region', 'type_of_business', 'std_mth'를 기준으로 중복 제거
train_df = df.drop_duplicates(subset = ['store_id', 'region', 'type_of_business', 'std_mth'])[['store_id', 'region', 'type_of_business', 'std_mth']]
train_df.head()
store_id region type_of_business std_mth
0 0 미분류 기타 미용업 6
145 0 미분류 기타 미용업 7
323 0 미분류 기타 미용업 8
494 0 미분류 기타 미용업 9
654 0 미분류 기타 미용업 10

평균 할부율 입력 to train_df

1
train_df['평균할부율'] = train_df['store_id'].replace(installment_term_per_store.to_dict())

std_mth(기준월)의 -1, -2, -3 시점에 대한 매장별 매출 / 지역별 매출 / 업종별 매출 파생변수 생성

  • df1에서는 시점 t를, 다른 데이터에서는 시점 t+1 or t-1 을 붙여야 되는 상황

  • t가 유니크 하다면, df2를 shift()해서 공백을 만든 뒤 concat을 하면 된다. (시계열 데이터에서 많이 사용)

  • t가 유니크 하지 않은 경우는 새로운 변수( e.g: t_1)을 만들어서 merge한다.

image.png


  • 단, std_mth는 각 매장별로 값이 존재하고, 필요한 값은 기준 월(std_mth)을 중심으로 -1, -2, -3 개월의 매출 값이다.

  • 이를 위해 for문을 사용하여 i = 1, 2, 3 일때 각각 t_{i} 값이 들어가는 변수를 만들어서 병합할 것이다.

  • 중복 방지를 위해 병합한 변수명 변경 및 drop 작업도 함께 수행한다.

각 시점별 매장의 월 매출 (파생변수)

각 store당 월별 amount 계산
  • standard_t (월): 6(2016년 6월) ~ 38 (2019년 2월)

  • 즉, store_id가 0이라는 매장의 standard_t가 6일때의 매출 , 7일때의 매출… 38일때의 매출을 각각 입력

1
2
3
# store_id와 standard_t에 따른 amount 합계 계산: total_amt_per_mth_and_store
total_amt_per_mth_and_store = df.groupby(['store_id', 'std_mth'], as_index = False)['amount'].sum()
total_amt_per_mth_and_store.head()
store_id std_mth amount
0 0 6 747000.00
1 0 7 1005000.00
2 0 8 871571.43
3 0 9 897857.14
4 0 10 835428.57
  • group by의 경우 지정한 조건에 해당하는 값이 없으면 건너뛴다.

  • 각 지점별로 ‘모든 월’ 에 대한 amount가 들어가야 하므로, 매장별 매출에서 값이 생략된 월들은 0으로 값을 넣어줘야 한다.

  • 그렇지 않을 경우 다른 데이터와 merge 할 경우 에러 발생, 혹은 잘못된 값이 입력될 수 있다.

매장별로 결측된 월이 있는지 확인

1
total_amt_per_mth_and_store.groupby(['store_id'])['std_mth'].count()
store_id
0       33
1       33
2       33
4       33
5       33
        ..
2132    31
2133    32
2134    26
2135    31
2136    22
Name: std_mth, Length: 1967, dtype: int64
  • 몇몇 store_id에서 누락된 값이 보인다.

  • group by에서 생략된 값이 실제 매출이 발생했는데 단순 누락된 값인지, 매장 운영이 되지 않은 기간이어서 0인건지 확인이 어렵다.

  • 이를 위해 pivot_table 활용


  • 누락된 값이 연속적인 경우만 있다면 매출이 발생하지 않은 것으로 가정 하여 0으로 채운다.

    • e.g) 시작점은 2016년 6월이지만, 누락된 매장들은 시작점 보다 늦게 개점하여 누락된 경우
  • 누락된 값이 불연속적이라면, 매출값이 누락된 것이라 가정하고 누락된 값의 ‘전/후’ 값으로 채워넣는다.

1
2
3
# pivot_table로 nan값의 분포 형태 확인
check_nan_amount = pd.pivot_table(df, values = 'amount', index = 'store_id', columns = 'std_mth', aggfunc = 'sum')
check_nan_amount
std_mth 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 32 33 34 35 36 37 38
store_id
0 747000.00 1005000.00 871571.43 897857.14 835428.57 697000.00 761857.14 585642.86 794000.00 720257.14 685285.71 744428.57 682000.00 728285.71 749000.00 840857.14 600571.43 630857.14 812714.29 643142.86 685285.71 848428.57 636142.86 686428.57 707285.71 758714.29 679857.14 651857.14 739000.00 676000.00 874571.43 682857.14 515285.71
1 137214.29 163000.00 118142.86 90428.57 118071.43 111857.14 115571.43 129642.86 160214.29 168428.57 152571.43 107500.00 110357.14 132571.43 107642.86 131357.14 80142.86 110142.86 100714.29 109571.43 94214.29 108357.14 108857.14 80500.00 78285.71 100785.71 92142.86 63571.43 95000.00 80785.71 85285.71 148285.71 77428.57
2 260714.29 82857.14 131428.57 142857.14 109714.29 198571.43 160000.00 180714.29 154285.71 43571.43 201428.57 186428.57 120571.43 207142.86 190000.00 232857.14 266714.29 252857.14 238571.43 299714.29 312857.14 189714.29 283571.43 472857.14 354285.71 689285.71 457857.14 480714.29 510000.00 185428.57 340714.29 407857.14 496857.14
4 733428.57 768928.57 698428.57 936428.57 762714.29 859571.43 1069857.14 689142.86 1050142.86 970285.71 1085171.43 1035857.14 894142.86 1027285.71 1186857.14 972571.43 1060571.43 1189142.86 1010142.86 831571.43 651000.00 908000.00 792214.29 775428.57 881285.71 1050928.57 849285.71 698142.86 828428.57 883000.00 923857.14 944857.14 882285.71
5 342500.00 432714.29 263500.00 232142.86 211571.43 182085.71 147571.43 120957.14 186428.57 169000.00 312857.14 235342.86 475857.14 410914.29 297714.29 291428.57 396157.14 399285.71 441557.14 388428.57 316785.71 370142.86 297857.14 443857.14 563714.29 607071.43 482885.71 195000.00 324928.57 383300.00 399571.43 323000.00 215514.29
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2132 nan nan 281142.86 783428.57 822000.00 941142.86 731142.86 684571.43 701000.00 742428.57 624614.29 566857.14 742857.14 865285.71 898428.57 787857.14 531857.14 1095000.00 1014071.43 580785.71 703857.14 909142.86 938428.57 670571.43 757857.14 753428.57 524142.86 637714.29 938571.43 729857.14 474285.71 571142.86 630428.57
2133 85000.00 367857.14 743571.43 494714.29 178571.43 124285.71 36285.71 31857.14 145114.29 313128.57 300685.71 384057.14 524342.86 425342.86 438257.14 493757.14 421214.29 646628.57 601171.43 433414.29 277342.86 308485.71 484071.43 626071.43 395700.00 421614.29 548942.86 310971.43 192700.00 84714.29 nan 84000.00 116285.71
2134 nan nan nan nan nan 393000.00 678214.29 459071.43 463428.57 446285.71 363571.43 580285.71 486857.14 503642.86 467785.71 431642.86 248714.29 355714.29 374142.86 313785.71 171857.14 245571.43 72357.14 216142.86 209785.71 140714.29 nan nan 84428.57 60785.71 4285.71 209428.57 166000.00
2135 nan nan 357428.57 786000.00 760285.71 751428.57 682857.14 544000.00 656000.00 631000.00 698571.43 611714.29 763857.14 675857.14 575714.29 575857.14 473714.29 505285.71 521857.14 563714.29 443928.57 468285.71 445142.86 577571.43 714428.57 438428.57 566142.86 509857.14 850428.57 589428.57 541857.14 462285.71 404285.71
2136 nan nan nan nan nan nan nan nan nan nan nan 469214.29 2713814.29 2967357.14 3364357.14 3190642.86 3364285.71 2706714.29 2869571.43 1877857.14 2023642.86 2352071.43 2197428.57 2194428.57 2333000.00 1601785.71 1222300.00 2775714.29 2012214.29 2135428.57 2427428.57 1873642.86 2227428.57

1967 rows × 33 columns

  • pivot table을 통해 보았을때, ‘월’ 의 중간 중간 nan값이 발생하는 것으로 보아, 실제 매출은 발생하였으나 누락된 데이터 일 것이라 가정

  • nan값을 바로 앞, 뒤 standard_t의 매출로 채워 넣는다.

1
2
3
4
5
6
# 발생한 nan값을 바로 앞/뒤의 값으로 채워넣는다.
# method = 'ffill', axis = 1 #전
# method = 'bfill', axis = 1 #후

total_amt_per_mth_and_store = check_nan_amount.fillna(method = 'ffill', axis = 1).fillna(method = 'bfill', axis = 1)
total_amt_per_mth_and_store.head(10)
std_mth 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 32 33 34 35 36 37 38
store_id
0 747000.00 1005000.00 871571.43 897857.14 835428.57 697000.00 761857.14 585642.86 794000.00 720257.14 685285.71 744428.57 682000.00 728285.71 749000.00 840857.14 600571.43 630857.14 812714.29 643142.86 685285.71 848428.57 636142.86 686428.57 707285.71 758714.29 679857.14 651857.14 739000.00 676000.00 874571.43 682857.14 515285.71
1 137214.29 163000.00 118142.86 90428.57 118071.43 111857.14 115571.43 129642.86 160214.29 168428.57 152571.43 107500.00 110357.14 132571.43 107642.86 131357.14 80142.86 110142.86 100714.29 109571.43 94214.29 108357.14 108857.14 80500.00 78285.71 100785.71 92142.86 63571.43 95000.00 80785.71 85285.71 148285.71 77428.57
2 260714.29 82857.14 131428.57 142857.14 109714.29 198571.43 160000.00 180714.29 154285.71 43571.43 201428.57 186428.57 120571.43 207142.86 190000.00 232857.14 266714.29 252857.14 238571.43 299714.29 312857.14 189714.29 283571.43 472857.14 354285.71 689285.71 457857.14 480714.29 510000.00 185428.57 340714.29 407857.14 496857.14
4 733428.57 768928.57 698428.57 936428.57 762714.29 859571.43 1069857.14 689142.86 1050142.86 970285.71 1085171.43 1035857.14 894142.86 1027285.71 1186857.14 972571.43 1060571.43 1189142.86 1010142.86 831571.43 651000.00 908000.00 792214.29 775428.57 881285.71 1050928.57 849285.71 698142.86 828428.57 883000.00 923857.14 944857.14 882285.71
5 342500.00 432714.29 263500.00 232142.86 211571.43 182085.71 147571.43 120957.14 186428.57 169000.00 312857.14 235342.86 475857.14 410914.29 297714.29 291428.57 396157.14 399285.71 441557.14 388428.57 316785.71 370142.86 297857.14 443857.14 563714.29 607071.43 482885.71 195000.00 324928.57 383300.00 399571.43 323000.00 215514.29
6 568857.14 568857.14 568857.14 1440142.86 1238857.14 1055428.57 926857.14 885642.86 800357.14 930714.29 855071.43 1029785.71 1071571.43 1037214.29 1054857.14 937857.14 1216285.71 1833571.43 2429500.00 2147714.29 2113357.14 2348714.29 1876857.14 1808357.14 1752285.71 1583785.71 1628785.71 2074071.43 1907642.86 2389142.86 2230285.71 2015500.00 2463857.14
7 107857.14 107857.14 107857.14 375642.86 323642.86 345000.00 291428.57 231614.29 271357.14 249857.14 131500.00 118642.86 53285.71 372285.71 183000.00 527857.14 218214.29 817714.29 750645.71 761571.43 636571.43 339857.14 1039357.14 265714.29 419542.86 462842.86 423128.57 320328.57 420028.57 314385.71 302414.29 136471.43 57971.43
8 192571.43 192571.43 192571.43 192571.43 192571.43 192571.43 735500.00 467857.14 475642.86 603500.00 1074642.86 1144571.43 1030928.57 1375571.43 1078928.57 984500.00 896785.71 514500.00 552214.29 618785.71 461714.29 744500.00 867071.43 1837428.57 1359857.14 1213542.86 1086000.00 1369557.14 1272071.43 1260557.14 1157257.14 1134671.43 1298328.57
9 107142.86 107142.86 107142.86 107142.86 107142.86 637142.86 603571.43 225428.57 287142.86 344428.57 352857.14 208571.43 178571.43 761714.29 535000.00 715714.29 672142.86 634285.71 333714.29 295428.57 628285.71 318571.43 1016857.14 638571.43 276571.43 340000.00 254285.71 926571.43 871428.57 692857.14 662857.14 370000.00 405714.29
10 496714.29 496714.29 496714.29 496714.29 496714.29 496714.29 496714.29 496714.29 496714.29 496714.29 496714.29 492571.43 341857.14 442428.57 438714.29 438571.43 470428.57 144428.57 444714.29 466714.29 722857.14 338571.43 475000.00 290285.71 607857.14 444571.43 641428.57 795571.43 499285.71 590142.86 518428.57 525142.86 654857.14
  • train_df와 병합을 위해 pivot_table 형태인 total_amt_per_mth_and_store 테이블을 stack() 함수를 사용해 동일한 형태의 DataFrame으로 변경

  • stack() : column 과 row를 바꾸는 함수

  • 위의 pivot_table 기준으로보면 store_id, std_mth, amount가 column이 되고, 기존 columns 별로 입력되있던 값이 row가 된다.

1
total_amt_per_mth_and_store = total_amt_per_mth_and_store.stack().reset_index() # index 번호 새로 부여
1
total_amt_per_mth_and_store
store_id std_mth 0
0 0 6 747000.00
1 0 7 1005000.00
2 0 8 871571.43
3 0 9 897857.14
4 0 10 835428.57
... ... ... ...
64906 2136 34 2012214.29
64907 2136 35 2135428.57
64908 2136 36 2427428.57
64909 2136 37 1873642.86
64910 2136 38 2227428.57

64911 rows × 3 columns

1
2
3
# amount로 컬럼명 변경
total_amt_per_mth_and_store.rename({0:"amount"}, axis = 1, inplace = True)
total_amt_per_mth_and_store.head(3)
store_id std_mth amount
0 0 6 747000.00
1 0 7 1005000.00
2 0 8 871571.43
매장별 월 매출 + train_df
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# std_mth + i (i = 1, 2, 3) 시점의 부착
# train_df의 std_mth는 total_amt_per_mth_and_store의 std_mth-i와 부착되어야 하므로, total_amt_per_mth_and_store의 std_mth에 i를 더함

for i in range(1, 4): 
    # i값에 따른 새로운 변수 생성
    total_amt_per_mth_and_store['std_mth_{}'.format(i)] = total_amt_per_mth_and_store['std_mth'] + i
    
    # 두 테이블 데이터 결합
    # 두 table에 모두 std_mth가 존재하므로 drop
    train_df = pd.merge(train_df, total_amt_per_mth_and_store.drop('std_mth', axis = 1), left_on = ['store_id', 'std_mth'], right_on = ['store_id', 'std_mth_{}'.format(i)])
    
    # 변수명 변경: 다음 loop에서 merge할때 중복 column 때문에 _x, _y가 생기는 것 방지
    train_df.rename({"amount":"{}_before_amount".format(i)}, axis = 1, inplace = True)
    
    #필요없어진 변수 drop
    train_df.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)
    total_amt_per_mth_and_store.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)
    
train_df.head()
store_id region type_of_business std_mth 평균할부율 1_before_amount 2_before_amount 3_before_amount
0 0 미분류 기타 미용업 9 0.04 871571.43 1005000.00 747000.00
1 0 미분류 기타 미용업 10 0.04 897857.14 871571.43 1005000.00
2 0 미분류 기타 미용업 11 0.04 835428.57 897857.14 871571.43
3 0 미분류 기타 미용업 12 0.04 697000.00 835428.57 897857.14
4 0 미분류 기타 미용업 13 0.04 761857.14 697000.00 835428.57
  • std_mth의 시작점이 6 -> 9로 바뀐다. (for문이 적용되고 merge되면서 사라진 것)

  • 6월의 amount는 3_before_amount에 입력되어 있다.

  • 일괄적으로 +3이 된 것이기 때문에 ok

  • std_mth 9(=16년 9월)를 기준으로 보았을때

    • 1_before_amount는 16년 8월, 2_before_amount는 16년 7월, 3_before_amount는 16년 6월을 의미한다.
  • 전체적으로 본다면 2016년 6월에 대한 특징 데이터는 소실된다. 하지만 반대로 다른 시점에 특성을 구분할 수 있는 데이터가 늘어남


  • i값을 3으로 한 이유 :

    1) 예측해야 하는 값이 3개월 평균 이기 때문

    2) i가 클수록 유실되는 데이터량이 많아져서 최소화 하기 위해( 1)의 기간도 감안 )

각 시점별 지역의 월 매출 (파생변수)

region(지역) 별 평균 매출 계산
1
2
3
4
5
6
7
8
9
#지역별 매장을 분류(dict) & 중복제거
store_to_region = df[['store_id', 'region']].drop_duplicates().set_index(['store_id'])['region'].to_dict() 

# store_id를 region으로 대체 -> 위에서 사용한 코드 동일하게 사용 가능
total_amt_per_mth_and_store['region'] = total_amt_per_mth_and_store['store_id'].replace(store_to_region)

# 지역별 평균 매출 계산
# total_amt_per_mth_and_store에 region이란 컬럼 추가 후 amt_mean_per_std_mth_and_region 테이블로 변경
amt_mean_per_std_mth_and_region = total_amt_per_mth_and_store.groupby(['region', 'std_mth'], as_index = False)['amount'].mean()
1
amt_mean_per_std_mth_and_region.head(3)
region std_mth amount
0 강원 강릉시 6 623271.75
1 강원 강릉시 7 501311.43
2 강원 강릉시 8 508130.79
  • 위에서 store_id의 누락치를 처리하는 과정에서 nan값을 모두 처리함

  • 즉, store_id를 region으로 대체한 것이기 때문에, pivot_table & stack 등을 통한 결측치 제거는 하지 않아도 됨.

train_df + amt_mean_per_std_mth_and_region
1
2
3
4
5
6
7
8
9
10
11
12
# std_mth + i (i = 1, 2, 3)

for i in range(1, 4):
    amt_mean_per_std_mth_and_region['std_mth_{}'.format(i)] = amt_mean_per_std_mth_and_region['std_mth'] + i
    train_df = pd.merge(train_df, amt_mean_per_std_mth_and_region.drop('std_mth', axis = 1), left_on = ['region', 'std_mth'], right_on = ['region', 'std_mth_{}'.format(i)])
    train_df.rename({"amount":"{}_before_amount_of_region".format(i)}, axis = 1, inplace = True)
    
    # 계산에 사용되고 필요없어진 데이터 drop
    train_df.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)
    amt_mean_per_std_mth_and_region.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)    
    
train_df.head()
store_id region type_of_business std_mth 평균할부율 1_before_amount 2_before_amount 3_before_amount 1_before_amount_of_region 2_before_amount_of_region 3_before_amount_of_region
0 0 미분류 기타 미용업 9 0.04 871571.43 1005000.00 747000.00 761987.42 756108.67 739654.07
1 1 미분류 미분류 9 0.00 118142.86 163000.00 137214.29 761987.42 756108.67 739654.07
2 2 미분류 미분류 9 0.08 131428.57 82857.14 260714.29 761987.42 756108.67 739654.07
3 5 미분류 의복 액세서리 및 모조 장신구 도매업 9 0.08 263500.00 432714.29 342500.00 761987.42 756108.67 739654.07
4 7 미분류 미분류 9 0.01 107857.14 107857.14 107857.14 761987.42 756108.67 739654.07

각 시점별 업종의 월 매출 (파생변수)

type_of_business별 평균 매출 계산
1
2
3
4
5
6
7
8
##업종별 매장을 분류(dict) & 중복제거
store_to_type_of_business = df[['store_id', 'type_of_business']].drop_duplicates().set_index(['store_id'])['type_of_business'].to_dict()

# store_id를 type_of_business으로 대체 -> 위에서 사용한 코드 동일하게 사용 가능
total_amt_per_mth_and_store['type_of_business'] = total_amt_per_mth_and_store['store_id'].replace(store_to_type_of_business)

# 지역별 평균 매출 계산
amount_mean_per_mth_and_type_of_business = total_amt_per_mth_and_store.groupby(['type_of_business', 'std_mth'], as_index = False)['amount'].mean()
amount_mean_per_mth_and_type_of_business + train_df
1
2
3
4
5
6
7
8
9
10
11
12
13
# std_mth + i (i = 1, 2, 3)
# train_df의 std_mth는 total_amt_per_mth_and_store의 std_mth-i와 merge 해야하므로, total_amt_per_mth_and_store의 std_mth에 i를 더한다.

for i in range(1, 4):
    amount_mean_per_mth_and_type_of_business['std_mth_{}'.format(i)] = amount_mean_per_mth_and_type_of_business['std_mth'] + i
    train_df = pd.merge(train_df, amount_mean_per_mth_and_type_of_business.drop('std_mth', axis = 1), left_on = ['type_of_business', 'std_mth'], right_on = ['type_of_business', 'std_mth_{}'.format(i)])
    train_df.rename({"amount":"{}_before_amount_of_type_of_business".format(i)}, axis = 1, inplace = True)
    
    # 계산에 사용되고 필요없어진 데이터 drop
    train_df.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)
    amount_mean_per_mth_and_type_of_business.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)       
    
train_df.head()
store_id region type_of_business std_mth 평균할부율 1_before_amount 2_before_amount 3_before_amount 1_before_amount_of_region 2_before_amount_of_region 3_before_amount_of_region 1_before_amount_of_type_of_business 2_before_amount_of_type_of_business 3_before_amount_of_type_of_business
0 0 미분류 기타 미용업 9 0.04 871571.43 1005000.00 747000.00 761987.42 756108.67 739654.07 761025.00 804979.76 679950.00
1 792 미분류 기타 미용업 9 0.22 681142.86 880857.14 733714.29 761987.42 756108.67 739654.07 761025.00 804979.76 679950.00
2 23 경기 안양시 기타 미용업 9 0.05 879242.86 730857.14 845285.71 828831.71 588733.00 955973.29 761025.00 804979.76 679950.00
3 192 경기 화성시 기타 미용업 9 0.10 579000.00 523428.57 551142.86 1234460.01 1227920.91 1180455.31 761025.00 804979.76 679950.00
4 536 서울 광진구 기타 미용업 9 0.01 96285.71 79857.14 99857.14 3786819.95 3397972.56 3524074.62 761025.00 804979.76 679950.00

label 부착하기 ( std_mth +1, std_mth+2, std_mth+3)

  • label 은 기준월 (std_mth) 에서 각각 +1, +2, +3 인 시점에 대한 amount는 예측 모델을 통해 파악해야 하는 값이다.

  • 이후 에는 model 학습을 위한 데이터 전처리가 들어가기 때문에, raw data인 현상황에서 +1, +2, +3 인 시점의 amount를 입력해 두는 것이 추후 작업에서 유용하다.

1
2
3
4
5
6
7
8
9
10
11
12
# 불필요한 컬럼 drop (중복 컬럼 방지)
total_amt_per_mth_and_store.drop(['region', 'type_of_business'], axis = 1, inplace = True)

# std_mth - i (i = 1, 2, 3)
for i in range(1, 4):
    total_amt_per_mth_and_store['std_mth_{}'.format(i)] = total_amt_per_mth_and_store['std_mth'] - i   
    train_df = pd.merge(train_df, total_amt_per_mth_and_store.drop('std_mth', axis = 1), left_on = ['store_id', 'std_mth'], right_on = ['store_id', 'std_mth_{}'.format(i)])
    train_df.rename({"amount": "Y_{}".format(i)}, axis = 1, inplace = True)
    
    # 계산에 사용되고 필요없어진 데이터 drop
    train_df.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)
    total_amt_per_mth_and_store.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)      
1
train_df[['std_mth','Y_1','Y_2','Y_3']]
std_mth Y_1 Y_2 Y_3
0 9 835428.57 697000.00 761857.14
1 9 725142.86 653428.57 730071.43
2 9 741714.29 608857.14 844285.71
3 9 529000.00 545142.86 449714.29
4 9 87142.86 159928.57 124142.86
... ... ... ... ...
50226 31 13623585.71 10826500.00 12053585.71
50227 32 10826500.00 12053585.71 12916214.29
50228 33 12053585.71 12916214.29 13290000.00
50229 34 12916214.29 13290000.00 15355300.00
50230 35 13290000.00 15355300.00 11063685.71

50231 rows × 4 columns

  • for loop가 수행되면서 각각 i=1 일때, total_amt_per_mth_and_store의 std_mth 기준으로 +1 인 시점의 amount 가 Y_1이 된다.

  • i=2 일때는 std_mth 기준 +2 인 시점의 amount 가 Y_2이 되고, i=3 일때, std_mth 기준 +3 인 시점의 amount 가 Y_3이 된다.

1
2
# Y변수 (미래 3개월의 매출) 생성
train_df['Y'] = train_df['Y_1'] + train_df['Y_2'] + train_df['Y_3']
1
os.getcwd()
'E:\\OneDrive\\Jupyter\\포트폴리오\\[예측] 상점 신용카드 매출 예측하기'
1
train_df.to_csv('E:\\OneDrive\\Jupyter\\포트폴리오\\[예측] 상점 신용카드 매출 예측하기\\train_df.csv')

Train data 살펴보기 - EDA & Data Processing

feature & label 분리

1
train_df.columns
Index(['store_id', 'region', 'type_of_business', 'std_mth', '평균할부율', '1_before_amount', '2_before_amount', '3_before_amount', '1_before_amount_of_region', '2_before_amount_of_region', '3_before_amount_of_region', '1_before_amount_of_type_of_business', '2_before_amount_of_type_of_business', '3_before_amount_of_type_of_business', 'Y_1', 'Y_2', 'Y_3', 'Y'], dtype='object')
1
2
X = train_df.drop(['store_id', 'region', 'type_of_business', 'std_mth', 'Y_1', 'Y_2', 'Y_3', 'Y'], axis = 1)
Y = train_df['Y']

데이터 분할 및 구조 탐색

1
2
3
4
5
from sklearn.model_selection import train_test_split
Train_X, Test_X, Train_Y, Test_Y = train_test_split(X, Y)

# 생성한 train 데이터 확인
Train_X.shape # 특징 대비 샘플이 많다. (특징 37673개,feature는 10개) -> 과적합 우려 없음
(37673, 10)
1
2
# label 데이터 확인
Train_Y.describe()
count       37673.00
mean      3405006.23
std       4845801.46
min       -174785.71
25%       1135857.14
50%       2208285.71
75%       4080285.71
max     172765924.57
Name: Y, dtype: float64
1
sns.boxplot(Train_Y, orient='v', width=0.5)
<AxesSubplot:xlabel='Y'>

  • 전체 매출의 평균은 3434534, 최소 매출은 0 이다.

  • 최대 매출은 172765924 로 값의 차이가 매우 크다.

이상치 제거

  • 값의 변동폭이 큰편이므로 이상치 제거가 필요 하다.
1
2
3
4
5
6
7
8
9
10
import numpy as np
def IQR_rule(val_list): # 한 특징에 포함된 값 (열 벡터)
    # IQR 계산    
    Q1 = np.quantile(val_list, 0.25)
    Q3 = np.quantile(val_list, 0.75)
    IQR = Q3 - Q1
    
    # IQR rule을 결과를 bool list 계산 (True이면 이상치 X, False면 이상치 O)
    not_outlier_condition = (Q3 + 1.5 * IQR > val_list) & (Q1 - 1.5 * IQR < val_list)
    return not_outlier_condition
1
2
3
4
# 이상치가 아닌 label로만 구성된 Y_condition 라는 bool list 생성
Y_condition = IQR_rule(Train_Y)
Train_Y = Train_Y[Y_condition]
Train_X = Train_X[Y_condition]
1
sns.boxplot(Y_condition, orient='v', width=0.5)
<AxesSubplot:xlabel='Y'>

치우침 제거

1
2
# 데이터 편향 확인
Train_X.skew()
평균할부율                                 2.96
1_before_amount                       2.51
2_before_amount                       2.43
3_before_amount                       2.49
1_before_amount_of_region             3.29
2_before_amount_of_region             3.26
3_before_amount_of_region             3.21
1_before_amount_of_type_of_business   1.71
2_before_amount_of_type_of_business   1.87
3_before_amount_of_type_of_business   1.97
dtype: float64
  • 모든 데이터가 1.5를 넘어 좌로 편향되어 있다.
1
2
3
4
5
# 치우침 제거
import numpy as np
biased_variables = Train_X.columns[Train_X.skew().abs() > 1.5] # 왜도의 절대값이 1.5 이상인 컬럼만 가져오기
Train_X[biased_variables] = Train_X[biased_variables] - Train_X[biased_variables].min() + 1 #가장 작은값이 1이 되도록
Train_X[biased_variables] = np.sqrt(Train_X[biased_variables])
1
2
3
# 데이터 편향 재확인

Train_X.skew()
평균할부율                                  2.76
1_before_amount                        0.74
2_before_amount                        0.73
3_before_amount                        0.74
1_before_amount_of_region              1.85
2_before_amount_of_region              1.83
3_before_amount_of_region              1.80
1_before_amount_of_type_of_business   -0.27
2_before_amount_of_type_of_business   -0.23
3_before_amount_of_type_of_business   -0.21
dtype: float64

Data Scaling

1
2
# feature간 스케일 차이 확인
Train_X.max() - Train_X.min()
평균할부율                                    0.38
1_before_amount                       3694.92
2_before_amount                       3595.03
3_before_amount                       3595.03
1_before_amount_of_region             2588.24
2_before_amount_of_region             2588.24
3_before_amount_of_region             2588.24
1_before_amount_of_type_of_business   2271.41
2_before_amount_of_type_of_business   2581.72
3_before_amount_of_type_of_business   2614.04
dtype: float64
  • 데이터 생성할때부터, 몇몇 데이터는 전체 지역의 평균, 혹은 전체 업종의 평균이기 때문에 평균 할부율 등의 값은 스케일이 매우 작을 수 밖에 없다.

  • 확실한 검증을 위해 확인차 실행해본 것 + 생성된 파생변수간에 스케일 차이가 있는지 확인하기 위해 실행

MinMax 스케일링

1
2
3
4
5
6
7
8
9
10
11
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler().fit(Train_X)
s_Train_X = scaler.transform(Train_X)
s_Test_X = scaler.transform(Test_X)

# scaling결과 DataFrame으로 변경
Train_X = pd.DataFrame(s_Train_X, columns = Train_X.columns)
Test_X = pd.DataFrame(s_Test_X, columns = Train_X.columns)

# 불필요한 값 제거 (데이터가 많아 메모리 효율성을 위해 제거)
del s_Train_X, s_Test_X

Modeling

모델 학습

  • 샘플 대비(약 3만개) 특징이 적고(10개), 특징의 타입이 전부 연속형으로 같다.

  • 데이터가 ‘연속형’일때 사용하기 좋은 모델에는 KNN, 신경망등이 대표적이다.

  • 다만, 신경망으로 쓰기엔 feature 수가 상대적으로 적어서 KNN을 선택

  • 나머지는 앙상블 모델을 사용해 예측력을 높이고자 했다.


  • 모델 1. kNN

  • 모델 2. RandomForestRegressor

  • 모델 3. LightGBM

  • 특징 선택: 3 ~ 10개 (기준: f_regression)

1
2
3
4
5
6
# 모델링 모듈 불러오기
from sklearn.model_selection import ParameterGrid
from sklearn.neighbors import KNeighborsRegressor as KNN
from sklearn.ensemble import RandomForestRegressor as RFR
from lightgbm import LGBMRegressor as LGB
from sklearn.feature_selection import *
1
2
3
#Cpu의 개수를 확인 : 작업할때 cpu 를 최대한 활용하기 위해 사양 check 
n_cpu=os.cpu_count()
print("The number of cpus: ",n_cpu)
The number of cpus:  6
1
2
3
# 일반적으로 보유한 cpu의 2배정도의 thread를 보유하고 있다
n_thread=n_cpu*2
print("Expected number of threads:",n_thread)
Expected number of threads: 12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 파라미터 그리드 생성
param_grid = dict() 
# 입력: 모델 함수, 출력: 모델의 하이퍼 파라미터 그리드

# 모델별 파라미터 그리드 생성
param_grid_for_knn = ParameterGrid({"n_neighbors": [1, 3, 5, 7],
                           "metric":['euclidean', 'cosine']})

param_grid_for_RFR = ParameterGrid({"max_depth": [1, 2, 3, 4],
                           "n_estimators":[100, 200],
                                   "max_samples":[0.5, 0.6, 0.7, None]})

param_grid_for_LGB = ParameterGrid({"max_depth": [1, 2, 3, 4],
                                   "n_estimators":[100, 200],
                            "learning_rate": [0.05, 0.1, 0.15]})

# 모델 - 하이퍼 파라미터 그리드를 param_grid에 추가
param_grid[KNN] = param_grid_for_knn
param_grid[RFR] = param_grid_for_RFR
param_grid[LGB] = param_grid_for_LGB
1
param_grid
{sklearn.neighbors._regression.KNeighborsRegressor: <sklearn.model_selection._search.ParameterGrid at 0x1d7fa4899d0>,
 sklearn.ensemble._forest.RandomForestRegressor: <sklearn.model_selection._search.ParameterGrid at 0x1d7fa489940>,
 lightgbm.sklearn.LGBMRegressor: <sklearn.model_selection._search.ParameterGrid at 0x1d7fa4899a0>}
1
param_grid[KNN]
<sklearn.model_selection._search.ParameterGrid at 0x1d7fa4899d0>
1
param_grid[RFR]
<sklearn.model_selection._search.ParameterGrid at 0x1d7fa489940>
1
param_grid[LGB]
<sklearn.model_selection._search.ParameterGrid at 0x1d7fa4899a0>
  • Random Forest

    • feature수가 적어서 max_depth를 낮게 잡아 단순화함 (불필요한 과적합 방지)

    • 트리별 sample(max_samples)는 train_x의 표본이 충분해서 범위를 크게 잡지 않음


  • LightGBM도 동일한 이유
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 출력을 위한 max_iter_num 계산
# 모델이 돌아가는 과정을 출력 (생략 가능)
max_iter_num = 0
for k in range(10, 2, -1):
    for M in param_grid.keys():
        for P in param_grid[M]:
            max_iter_num += 1

#평가지표 MAE 사용
from sklearn.metrics import mean_absolute_error as MAE

# MAE가 작을 수록 좋은 것이기 때문에 비교대상인 best_score을 최대한 크게 설정
best_score = 9999999999
iteration_num = 0 # iteration_num 0으로 초기화

for k in range(10, 2, -1): # 메모리 부담 해소를 위해, 1씩 감소시킴
    # SelectKBest로 모델에 가장 중요한 특성 자동 선택
    selector = SelectKBest(f_regression, k = k).fit(Train_X, Train_Y)
    # 선택된 컬럼을 selector.get_support() 함수로 Train_X의 컬럼으로 선택
    selected_features = Train_X.columns[selector.get_support()]
    
    # 선정된 feature을 각각 Train_X와 Test_X에 입력
    # loop에 따라 Train_X와 Test_X에 들어가는 feature들이 감소 -> 메모리 부담 완화
    Train_X = Train_X[selected_features]
    Test_X = Test_X[selected_features]
    
    
    for M in param_grid.keys():
        for P in param_grid[M]:
            # LightGBM에서 DataFrame이 잘 처리되지 않는 것을 방지하기 위해 .values를 사용
            
            # 모델학습
            model = M(**P).fit(Train_X.values, Train_Y.values)
            
            # 예측
            pred_Y = model.predict(Test_X.values)
            
            # 평가
            score = MAE(Test_Y.values, pred_Y)
            
            if score < best_score:
                best_score = score
                best_model = M
                best_paramter = P
                best_features = selected_features    
                
            iteration_num += 1
            
            # 진행상황 출력 : 몇번째 iter인지, 해당 순번의 best_score은 몇인지
            print("iter_num:{}/{}, score: {}, best_score: {}".format(iteration_num, max_iter_num, round(score, 2), round(best_score, 2)))
iter_num:1/512, score: 4098819.44, best_score: 4098819.44
iter_num:2/512, score: 3399445.36, best_score: 3399445.36
iter_num:3/512, score: 3890470.9, best_score: 3399445.36
iter_num:4/512, score: 4061793.26, best_score: 3399445.36
iter_num:5/512, score: 2111002.08, best_score: 2111002.08
iter_num:6/512, score: 1854831.56, best_score: 1854831.56
iter_num:7/512, score: 1767116.96, best_score: 1767116.96
iter_num:8/512, score: 1732777.37, best_score: 1732777.37
iter_num:9/512, score: 3152779.99, best_score: 1732777.37
iter_num:10/512, score: 3150001.39, best_score: 1732777.37
iter_num:11/512, score: 3152624.5, best_score: 1732777.37
iter_num:12/512, score: 3157880.88, best_score: 1732777.37
iter_num:13/512, score: 3154657.65, best_score: 1732777.37
iter_num:14/512, score: 3152385.96, best_score: 1732777.37
iter_num:15/512, score: 3147677.66, best_score: 1732777.37
iter_num:16/512, score: 3158188.02, best_score: 1732777.37
iter_num:17/512, score: 3856460.89, best_score: 1732777.37
iter_num:18/512, score: 3867556.21, best_score: 1732777.37
iter_num:19/512, score: 3861113.94, best_score: 1732777.37
iter_num:20/512, score: 3859896.4, best_score: 1732777.37
iter_num:21/512, score: 3863969.88, best_score: 1732777.37
iter_num:22/512, score: 3865326.61, best_score: 1732777.37
iter_num:23/512, score: 3863467.44, best_score: 1732777.37
iter_num:24/512, score: 3868027.63, best_score: 1732777.37
iter_num:25/512, score: 4266960.51, best_score: 1732777.37
iter_num:26/512, score: 4290476.57, best_score: 1732777.37
iter_num:27/512, score: 4270209.56, best_score: 1732777.37
iter_num:28/512, score: 4267287.5, best_score: 1732777.37
iter_num:29/512, score: 4275020.55, best_score: 1732777.37
iter_num:30/512, score: 4267420.14, best_score: 1732777.37
iter_num:31/512, score: 4276169.43, best_score: 1732777.37
iter_num:32/512, score: 4276588.04, best_score: 1732777.37
iter_num:33/512, score: 4499405.08, best_score: 1732777.37
iter_num:34/512, score: 4544891.49, best_score: 1732777.37
iter_num:35/512, score: 4553407.97, best_score: 1732777.37
iter_num:36/512, score: 4529068.7, best_score: 1732777.37
iter_num:37/512, score: 4493140.7, best_score: 1732777.37
iter_num:38/512, score: 4529722.09, best_score: 1732777.37
iter_num:39/512, score: 4539751.55, best_score: 1732777.37
iter_num:40/512, score: 4533240.49, best_score: 1732777.37
iter_num:41/512, score: 4206033.49, best_score: 1732777.37
iter_num:42/512, score: 4502153.7, best_score: 1732777.37
iter_num:43/512, score: 4492506.19, best_score: 1732777.37
iter_num:44/512, score: 4613314.8, best_score: 1732777.37
iter_num:45/512, score: 4931800.91, best_score: 1732777.37
iter_num:46/512, score: 5039831.77, best_score: 1732777.37
iter_num:47/512, score: 4846557.52, best_score: 1732777.37
iter_num:48/512, score: 4701203.55, best_score: 1732777.37
iter_num:49/512, score: 4509875.19, best_score: 1732777.37
iter_num:50/512, score: 4513916.76, best_score: 1732777.37
iter_num:51/512, score: 4649127.48, best_score: 1732777.37
iter_num:52/512, score: 4561177.21, best_score: 1732777.37
iter_num:53/512, score: 4649656.48, best_score: 1732777.37
iter_num:54/512, score: 4946335.6, best_score: 1732777.37
iter_num:55/512, score: 4446617.29, best_score: 1732777.37
iter_num:56/512, score: 4933997.66, best_score: 1732777.37
iter_num:57/512, score: 4575151.0, best_score: 1732777.37
iter_num:58/512, score: 4335866.28, best_score: 1732777.37
iter_num:59/512, score: 4661679.77, best_score: 1732777.37
iter_num:60/512, score: 4852176.65, best_score: 1732777.37
iter_num:61/512, score: 4845613.61, best_score: 1732777.37
iter_num:62/512, score: 5241318.96, best_score: 1732777.37
iter_num:63/512, score: 5366193.77, best_score: 1732777.37
iter_num:64/512, score: 5435723.74, best_score: 1732777.37
iter_num:65/512, score: 4115484.34, best_score: 1732777.37
iter_num:66/512, score: 3380563.48, best_score: 1732777.37
iter_num:67/512, score: 3881755.07, best_score: 1732777.37
iter_num:68/512, score: 4051456.18, best_score: 1732777.37
iter_num:69/512, score: 2060785.16, best_score: 1732777.37
iter_num:70/512, score: 1818204.24, best_score: 1732777.37
iter_num:71/512, score: 1735855.0, best_score: 1732777.37
iter_num:72/512, score: 1700359.29, best_score: 1700359.29
iter_num:73/512, score: 3149449.22, best_score: 1700359.29
iter_num:74/512, score: 3149869.11, best_score: 1700359.29
iter_num:75/512, score: 3154312.5, best_score: 1700359.29
iter_num:76/512, score: 3156671.79, best_score: 1700359.29
iter_num:77/512, score: 3148765.16, best_score: 1700359.29
iter_num:78/512, score: 3155157.99, best_score: 1700359.29
iter_num:79/512, score: 3155688.39, best_score: 1700359.29
iter_num:80/512, score: 3157304.39, best_score: 1700359.29
iter_num:81/512, score: 3874084.53, best_score: 1700359.29
iter_num:82/512, score: 3862413.44, best_score: 1700359.29
iter_num:83/512, score: 3848833.84, best_score: 1700359.29
iter_num:84/512, score: 3866346.94, best_score: 1700359.29
iter_num:85/512, score: 3856953.8, best_score: 1700359.29
iter_num:86/512, score: 3865251.27, best_score: 1700359.29
iter_num:87/512, score: 3860226.42, best_score: 1700359.29
iter_num:88/512, score: 3868070.93, best_score: 1700359.29
iter_num:89/512, score: 4263031.61, best_score: 1700359.29
iter_num:90/512, score: 4279142.74, best_score: 1700359.29
iter_num:91/512, score: 4270765.07, best_score: 1700359.29
iter_num:92/512, score: 4268400.28, best_score: 1700359.29
iter_num:93/512, score: 4275205.7, best_score: 1700359.29
iter_num:94/512, score: 4269824.31, best_score: 1700359.29
iter_num:95/512, score: 4257678.78, best_score: 1700359.29
iter_num:96/512, score: 4268876.23, best_score: 1700359.29
iter_num:97/512, score: 4463960.21, best_score: 1700359.29
iter_num:98/512, score: 4536965.48, best_score: 1700359.29
iter_num:99/512, score: 4548273.12, best_score: 1700359.29
iter_num:100/512, score: 4521055.83, best_score: 1700359.29
iter_num:101/512, score: 4540236.36, best_score: 1700359.29
iter_num:102/512, score: 4539898.05, best_score: 1700359.29
iter_num:103/512, score: 4534282.24, best_score: 1700359.29
iter_num:104/512, score: 4529211.59, best_score: 1700359.29
iter_num:105/512, score: 4206033.49, best_score: 1700359.29
iter_num:106/512, score: 4586996.51, best_score: 1700359.29
iter_num:107/512, score: 4624903.02, best_score: 1700359.29
iter_num:108/512, score: 4387477.57, best_score: 1700359.29
iter_num:109/512, score: 4348327.4, best_score: 1700359.29
iter_num:110/512, score: 4124972.64, best_score: 1700359.29
iter_num:111/512, score: 4079566.21, best_score: 1700359.29
iter_num:112/512, score: 3821215.7, best_score: 1700359.29
iter_num:113/512, score: 4600603.3, best_score: 1700359.29
iter_num:114/512, score: 4626244.78, best_score: 1700359.29
iter_num:115/512, score: 4394644.12, best_score: 1700359.29
iter_num:116/512, score: 4046177.52, best_score: 1700359.29
iter_num:117/512, score: 4234874.99, best_score: 1700359.29
iter_num:118/512, score: 4138659.66, best_score: 1700359.29
iter_num:119/512, score: 4104454.76, best_score: 1700359.29
iter_num:120/512, score: 4288354.06, best_score: 1700359.29
iter_num:121/512, score: 4670215.11, best_score: 1700359.29
iter_num:122/512, score: 4440909.12, best_score: 1700359.29
iter_num:123/512, score: 4012723.7, best_score: 1700359.29
iter_num:124/512, score: 3912591.79, best_score: 1700359.29
iter_num:125/512, score: 4203438.91, best_score: 1700359.29
iter_num:126/512, score: 4572227.69, best_score: 1700359.29
iter_num:127/512, score: 4316822.51, best_score: 1700359.29
iter_num:128/512, score: 4479662.06, best_score: 1700359.29
iter_num:129/512, score: 3620926.74, best_score: 1700359.29
iter_num:130/512, score: 3407193.49, best_score: 1700359.29
iter_num:131/512, score: 3953687.13, best_score: 1700359.29
iter_num:132/512, score: 4352872.93, best_score: 1700359.29
iter_num:133/512, score: 2069136.13, best_score: 1700359.29
iter_num:134/512, score: 1826022.16, best_score: 1700359.29
iter_num:135/512, score: 1743515.93, best_score: 1700359.29
iter_num:136/512, score: 1704814.45, best_score: 1700359.29
iter_num:137/512, score: 3149768.16, best_score: 1700359.29
iter_num:138/512, score: 3158944.71, best_score: 1700359.29
iter_num:139/512, score: 3150926.35, best_score: 1700359.29
iter_num:140/512, score: 3160890.99, best_score: 1700359.29
iter_num:141/512, score: 3152383.87, best_score: 1700359.29
iter_num:142/512, score: 3154408.48, best_score: 1700359.29
iter_num:143/512, score: 3157212.8, best_score: 1700359.29
iter_num:144/512, score: 3157567.95, best_score: 1700359.29
iter_num:145/512, score: 3861111.37, best_score: 1700359.29
iter_num:146/512, score: 3864659.73, best_score: 1700359.29
iter_num:147/512, score: 3869631.45, best_score: 1700359.29
iter_num:148/512, score: 3866929.77, best_score: 1700359.29
iter_num:149/512, score: 3859119.87, best_score: 1700359.29
iter_num:150/512, score: 3864453.25, best_score: 1700359.29
iter_num:151/512, score: 3865299.39, best_score: 1700359.29
iter_num:152/512, score: 3869085.67, best_score: 1700359.29
iter_num:153/512, score: 4278817.53, best_score: 1700359.29
iter_num:154/512, score: 4258950.48, best_score: 1700359.29
iter_num:155/512, score: 4269922.42, best_score: 1700359.29
iter_num:156/512, score: 4273461.23, best_score: 1700359.29
iter_num:157/512, score: 4251874.35, best_score: 1700359.29
iter_num:158/512, score: 4265474.27, best_score: 1700359.29
iter_num:159/512, score: 4260720.14, best_score: 1700359.29
iter_num:160/512, score: 4258017.89, best_score: 1700359.29
iter_num:161/512, score: 4484427.87, best_score: 1700359.29
iter_num:162/512, score: 4541001.09, best_score: 1700359.29
iter_num:163/512, score: 4527072.09, best_score: 1700359.29
iter_num:164/512, score: 4547022.48, best_score: 1700359.29
iter_num:165/512, score: 4537502.19, best_score: 1700359.29
iter_num:166/512, score: 4533395.42, best_score: 1700359.29
iter_num:167/512, score: 4534813.47, best_score: 1700359.29
iter_num:168/512, score: 4506146.06, best_score: 1700359.29
iter_num:169/512, score: 4206033.49, best_score: 1700359.29
iter_num:170/512, score: 4583473.78, best_score: 1700359.29
iter_num:171/512, score: 4627799.92, best_score: 1700359.29
iter_num:172/512, score: 4434332.68, best_score: 1700359.29
iter_num:173/512, score: 4312783.11, best_score: 1700359.29
iter_num:174/512, score: 4070508.94, best_score: 1700359.29
iter_num:175/512, score: 4148195.25, best_score: 1700359.29
iter_num:176/512, score: 3905679.26, best_score: 1700359.29
iter_num:177/512, score: 4596815.43, best_score: 1700359.29
iter_num:178/512, score: 4628904.68, best_score: 1700359.29
iter_num:179/512, score: 4403065.58, best_score: 1700359.29
iter_num:180/512, score: 3935324.82, best_score: 1700359.29
iter_num:181/512, score: 3930518.66, best_score: 1700359.29
iter_num:182/512, score: 4144889.62, best_score: 1700359.29
iter_num:183/512, score: 3894463.9, best_score: 1700359.29
iter_num:184/512, score: 4275734.87, best_score: 1700359.29
iter_num:185/512, score: 4671070.85, best_score: 1700359.29
iter_num:186/512, score: 4426433.02, best_score: 1700359.29
iter_num:187/512, score: 4052689.29, best_score: 1700359.29
iter_num:188/512, score: 3797149.12, best_score: 1700359.29
iter_num:189/512, score: 3859996.24, best_score: 1700359.29
iter_num:190/512, score: 4174760.94, best_score: 1700359.29
iter_num:191/512, score: 4183582.82, best_score: 1700359.29
iter_num:192/512, score: 4351819.82, best_score: 1700359.29
iter_num:193/512, score: 2961764.8, best_score: 1700359.29
iter_num:194/512, score: 3347667.3, best_score: 1700359.29
iter_num:195/512, score: 4027002.83, best_score: 1700359.29
iter_num:196/512, score: 4346851.79, best_score: 1700359.29
iter_num:197/512, score: 2072274.62, best_score: 1700359.29
iter_num:198/512, score: 1828137.34, best_score: 1700359.29
iter_num:199/512, score: 1748522.7, best_score: 1700359.29
iter_num:200/512, score: 1711969.28, best_score: 1700359.29
iter_num:201/512, score: 3156880.63, best_score: 1700359.29
iter_num:202/512, score: 3155025.83, best_score: 1700359.29
iter_num:203/512, score: 3155724.81, best_score: 1700359.29
iter_num:204/512, score: 3152377.0, best_score: 1700359.29
iter_num:205/512, score: 3157274.8, best_score: 1700359.29
iter_num:206/512, score: 3158630.78, best_score: 1700359.29
iter_num:207/512, score: 3151275.56, best_score: 1700359.29
iter_num:208/512, score: 3153485.2, best_score: 1700359.29
iter_num:209/512, score: 3871690.55, best_score: 1700359.29
iter_num:210/512, score: 3870703.15, best_score: 1700359.29
iter_num:211/512, score: 3864438.47, best_score: 1700359.29
iter_num:212/512, score: 3863849.48, best_score: 1700359.29
iter_num:213/512, score: 3872923.41, best_score: 1700359.29
iter_num:214/512, score: 3868611.55, best_score: 1700359.29
iter_num:215/512, score: 3862309.2, best_score: 1700359.29
iter_num:216/512, score: 3865538.99, best_score: 1700359.29
iter_num:217/512, score: 4265577.46, best_score: 1700359.29
iter_num:218/512, score: 4265550.77, best_score: 1700359.29
iter_num:219/512, score: 4254952.55, best_score: 1700359.29
iter_num:220/512, score: 4271713.46, best_score: 1700359.29
iter_num:221/512, score: 4263409.6, best_score: 1700359.29
iter_num:222/512, score: 4264160.89, best_score: 1700359.29
iter_num:223/512, score: 4263900.41, best_score: 1700359.29
iter_num:224/512, score: 4261541.72, best_score: 1700359.29
iter_num:225/512, score: 4415429.31, best_score: 1700359.29
iter_num:226/512, score: 4513651.96, best_score: 1700359.29
iter_num:227/512, score: 4538035.3, best_score: 1700359.29
iter_num:228/512, score: 4495018.7, best_score: 1700359.29
iter_num:229/512, score: 4514534.26, best_score: 1700359.29
iter_num:230/512, score: 4539135.62, best_score: 1700359.29
iter_num:231/512, score: 4527473.94, best_score: 1700359.29
iter_num:232/512, score: 4535298.96, best_score: 1700359.29
iter_num:233/512, score: 4206033.49, best_score: 1700359.29
iter_num:234/512, score: 4564191.43, best_score: 1700359.29
iter_num:235/512, score: 4568156.98, best_score: 1700359.29
iter_num:236/512, score: 4471041.19, best_score: 1700359.29
iter_num:237/512, score: 4341062.69, best_score: 1700359.29
iter_num:238/512, score: 4206151.21, best_score: 1700359.29
iter_num:239/512, score: 4049121.43, best_score: 1700359.29
iter_num:240/512, score: 3793365.82, best_score: 1700359.29
iter_num:241/512, score: 4569411.72, best_score: 1700359.29
iter_num:242/512, score: 4628834.08, best_score: 1700359.29
iter_num:243/512, score: 4252564.48, best_score: 1700359.29
iter_num:244/512, score: 3918614.29, best_score: 1700359.29
iter_num:245/512, score: 3979521.07, best_score: 1700359.29
iter_num:246/512, score: 3960366.14, best_score: 1700359.29
iter_num:247/512, score: 4025787.19, best_score: 1700359.29
iter_num:248/512, score: 4020424.75, best_score: 1700359.29
iter_num:249/512, score: 4644907.36, best_score: 1700359.29
iter_num:250/512, score: 4449702.05, best_score: 1700359.29
iter_num:251/512, score: 4095679.92, best_score: 1700359.29
iter_num:252/512, score: 3900321.66, best_score: 1700359.29
iter_num:253/512, score: 4184184.89, best_score: 1700359.29
iter_num:254/512, score: 4469549.65, best_score: 1700359.29
iter_num:255/512, score: 4058843.47, best_score: 1700359.29
iter_num:256/512, score: 3860084.42, best_score: 1700359.29
iter_num:257/512, score: 2593935.95, best_score: 1700359.29
iter_num:258/512, score: 3229919.38, best_score: 1700359.29
iter_num:259/512, score: 3967873.76, best_score: 1700359.29
iter_num:260/512, score: 4262742.99, best_score: 1700359.29
iter_num:261/512, score: 2282169.28, best_score: 1700359.29
iter_num:262/512, score: 2020357.15, best_score: 1700359.29
iter_num:263/512, score: 1951332.49, best_score: 1700359.29
iter_num:264/512, score: 1903785.58, best_score: 1700359.29
iter_num:265/512, score: 3148331.61, best_score: 1700359.29
iter_num:266/512, score: 3151141.76, best_score: 1700359.29
iter_num:267/512, score: 3156476.76, best_score: 1700359.29
iter_num:268/512, score: 3149783.58, best_score: 1700359.29
iter_num:269/512, score: 3156009.26, best_score: 1700359.29
iter_num:270/512, score: 3150029.03, best_score: 1700359.29
iter_num:271/512, score: 3161591.04, best_score: 1700359.29
iter_num:272/512, score: 3154099.95, best_score: 1700359.29
iter_num:273/512, score: 3869956.45, best_score: 1700359.29
iter_num:274/512, score: 3865285.01, best_score: 1700359.29
iter_num:275/512, score: 3876345.67, best_score: 1700359.29
iter_num:276/512, score: 3868369.96, best_score: 1700359.29
iter_num:277/512, score: 3869699.31, best_score: 1700359.29
iter_num:278/512, score: 3860387.6, best_score: 1700359.29
iter_num:279/512, score: 3871790.18, best_score: 1700359.29
iter_num:280/512, score: 3876943.3, best_score: 1700359.29
iter_num:281/512, score: 4283345.58, best_score: 1700359.29
iter_num:282/512, score: 4273497.32, best_score: 1700359.29
iter_num:283/512, score: 4280578.09, best_score: 1700359.29
iter_num:284/512, score: 4258829.28, best_score: 1700359.29
iter_num:285/512, score: 4262152.59, best_score: 1700359.29
iter_num:286/512, score: 4257305.46, best_score: 1700359.29
iter_num:287/512, score: 4259081.36, best_score: 1700359.29
iter_num:288/512, score: 4268759.81, best_score: 1700359.29
iter_num:289/512, score: 4542421.18, best_score: 1700359.29
iter_num:290/512, score: 4486035.52, best_score: 1700359.29
iter_num:291/512, score: 4544747.07, best_score: 1700359.29
iter_num:292/512, score: 4537082.38, best_score: 1700359.29
iter_num:293/512, score: 4503247.4, best_score: 1700359.29
iter_num:294/512, score: 4493731.9, best_score: 1700359.29
iter_num:295/512, score: 4528513.15, best_score: 1700359.29
iter_num:296/512, score: 4532231.0, best_score: 1700359.29
iter_num:297/512, score: 4206033.49, best_score: 1700359.29
iter_num:298/512, score: 4552182.11, best_score: 1700359.29
iter_num:299/512, score: 4554289.17, best_score: 1700359.29
iter_num:300/512, score: 4381352.12, best_score: 1700359.29
iter_num:301/512, score: 4429823.1, best_score: 1700359.29
iter_num:302/512, score: 4297121.4, best_score: 1700359.29
iter_num:303/512, score: 4226519.58, best_score: 1700359.29
iter_num:304/512, score: 4502767.55, best_score: 1700359.29
iter_num:305/512, score: 4554415.57, best_score: 1700359.29
iter_num:306/512, score: 4540400.84, best_score: 1700359.29
iter_num:307/512, score: 4323951.01, best_score: 1700359.29
iter_num:308/512, score: 4488994.36, best_score: 1700359.29
iter_num:309/512, score: 4278331.63, best_score: 1700359.29
iter_num:310/512, score: 4714084.07, best_score: 1700359.29
iter_num:311/512, score: 4458549.8, best_score: 1700359.29
iter_num:312/512, score: 4720716.64, best_score: 1700359.29
iter_num:313/512, score: 4606259.29, best_score: 1700359.29
iter_num:314/512, score: 4394440.19, best_score: 1700359.29
iter_num:315/512, score: 4425787.78, best_score: 1700359.29
iter_num:316/512, score: 4654726.91, best_score: 1700359.29
iter_num:317/512, score: 4654978.22, best_score: 1700359.29
iter_num:318/512, score: 4884047.11, best_score: 1700359.29
iter_num:319/512, score: 4600741.94, best_score: 1700359.29
iter_num:320/512, score: 4765486.53, best_score: 1700359.29
iter_num:321/512, score: 5028960.18, best_score: 1700359.29
iter_num:322/512, score: 4642933.48, best_score: 1700359.29
iter_num:323/512, score: 4264512.55, best_score: 1700359.29
iter_num:324/512, score: 4278777.83, best_score: 1700359.29
iter_num:325/512, score: 2310877.54, best_score: 1700359.29
iter_num:326/512, score: 2060800.36, best_score: 1700359.29
iter_num:327/512, score: 1975905.02, best_score: 1700359.29
iter_num:328/512, score: 1931170.04, best_score: 1700359.29
iter_num:329/512, score: 3150130.36, best_score: 1700359.29
iter_num:330/512, score: 3149828.57, best_score: 1700359.29
iter_num:331/512, score: 3164569.91, best_score: 1700359.29
iter_num:332/512, score: 3152326.86, best_score: 1700359.29
iter_num:333/512, score: 3149492.11, best_score: 1700359.29
iter_num:334/512, score: 3154764.97, best_score: 1700359.29
iter_num:335/512, score: 3153078.45, best_score: 1700359.29
iter_num:336/512, score: 3153626.84, best_score: 1700359.29
iter_num:337/512, score: 3859140.79, best_score: 1700359.29
iter_num:338/512, score: 3875612.95, best_score: 1700359.29
iter_num:339/512, score: 3860121.28, best_score: 1700359.29
iter_num:340/512, score: 3869763.75, best_score: 1700359.29
iter_num:341/512, score: 3859477.33, best_score: 1700359.29
iter_num:342/512, score: 3864192.35, best_score: 1700359.29
iter_num:343/512, score: 3863568.23, best_score: 1700359.29
iter_num:344/512, score: 3858596.51, best_score: 1700359.29
iter_num:345/512, score: 4266255.92, best_score: 1700359.29
iter_num:346/512, score: 4274911.35, best_score: 1700359.29
iter_num:347/512, score: 4274448.13, best_score: 1700359.29
iter_num:348/512, score: 4270553.12, best_score: 1700359.29
iter_num:349/512, score: 4264640.11, best_score: 1700359.29
iter_num:350/512, score: 4276031.95, best_score: 1700359.29
iter_num:351/512, score: 4261050.84, best_score: 1700359.29
iter_num:352/512, score: 4264777.46, best_score: 1700359.29
iter_num:353/512, score: 4515604.64, best_score: 1700359.29
iter_num:354/512, score: 4538092.13, best_score: 1700359.29
iter_num:355/512, score: 4495314.98, best_score: 1700359.29
iter_num:356/512, score: 4528498.3, best_score: 1700359.29
iter_num:357/512, score: 4552987.42, best_score: 1700359.29
iter_num:358/512, score: 4485744.13, best_score: 1700359.29
iter_num:359/512, score: 4536866.46, best_score: 1700359.29
iter_num:360/512, score: 4527983.49, best_score: 1700359.29
iter_num:361/512, score: 4206033.49, best_score: 1700359.29
iter_num:362/512, score: 4551868.13, best_score: 1700359.29
iter_num:363/512, score: 4514868.85, best_score: 1700359.29
iter_num:364/512, score: 4512898.44, best_score: 1700359.29
iter_num:365/512, score: 4405352.14, best_score: 1700359.29
iter_num:366/512, score: 4364333.32, best_score: 1700359.29
iter_num:367/512, score: 4250566.43, best_score: 1700359.29
iter_num:368/512, score: 4426987.81, best_score: 1700359.29
iter_num:369/512, score: 4558985.96, best_score: 1700359.29
iter_num:370/512, score: 4502884.46, best_score: 1700359.29
iter_num:371/512, score: 4508164.22, best_score: 1700359.29
iter_num:372/512, score: 4499088.13, best_score: 1700359.29
iter_num:373/512, score: 4364817.96, best_score: 1700359.29
iter_num:374/512, score: 4683685.7, best_score: 1700359.29
iter_num:375/512, score: 4495751.08, best_score: 1700359.29
iter_num:376/512, score: 4610029.86, best_score: 1700359.29
iter_num:377/512, score: 4573609.49, best_score: 1700359.29
iter_num:378/512, score: 4442883.38, best_score: 1700359.29
iter_num:379/512, score: 4488682.09, best_score: 1700359.29
iter_num:380/512, score: 4581630.63, best_score: 1700359.29
iter_num:381/512, score: 4528705.74, best_score: 1700359.29
iter_num:382/512, score: 4742997.12, best_score: 1700359.29
iter_num:383/512, score: 4540534.96, best_score: 1700359.29
iter_num:384/512, score: 4757753.16, best_score: 1700359.29
iter_num:385/512, score: 4687044.29, best_score: 1700359.29
iter_num:386/512, score: 4666418.36, best_score: 1700359.29
iter_num:387/512, score: 4252304.58, best_score: 1700359.29
iter_num:388/512, score: 4224391.21, best_score: 1700359.29
iter_num:389/512, score: 2296237.74, best_score: 1700359.29
iter_num:390/512, score: 2073080.84, best_score: 1700359.29
iter_num:391/512, score: 1987835.91, best_score: 1700359.29
iter_num:392/512, score: 1952332.46, best_score: 1700359.29
iter_num:393/512, score: 3146877.58, best_score: 1700359.29
iter_num:394/512, score: 3152712.08, best_score: 1700359.29
iter_num:395/512, score: 3151034.73, best_score: 1700359.29
iter_num:396/512, score: 3155064.6, best_score: 1700359.29
iter_num:397/512, score: 3154007.39, best_score: 1700359.29
iter_num:398/512, score: 3158267.14, best_score: 1700359.29
iter_num:399/512, score: 3155755.4, best_score: 1700359.29
iter_num:400/512, score: 3153852.36, best_score: 1700359.29
iter_num:401/512, score: 3867482.45, best_score: 1700359.29
iter_num:402/512, score: 3863229.32, best_score: 1700359.29
iter_num:403/512, score: 3871786.19, best_score: 1700359.29
iter_num:404/512, score: 3870422.28, best_score: 1700359.29
iter_num:405/512, score: 3866265.52, best_score: 1700359.29
iter_num:406/512, score: 3872079.07, best_score: 1700359.29
iter_num:407/512, score: 3859307.01, best_score: 1700359.29
iter_num:408/512, score: 3854848.01, best_score: 1700359.29
iter_num:409/512, score: 4287495.54, best_score: 1700359.29
iter_num:410/512, score: 4263959.2, best_score: 1700359.29
iter_num:411/512, score: 4278215.01, best_score: 1700359.29
iter_num:412/512, score: 4264442.33, best_score: 1700359.29
iter_num:413/512, score: 4273111.94, best_score: 1700359.29
iter_num:414/512, score: 4270912.74, best_score: 1700359.29
iter_num:415/512, score: 4256161.66, best_score: 1700359.29
iter_num:416/512, score: 4258457.76, best_score: 1700359.29
iter_num:417/512, score: 4511149.44, best_score: 1700359.29
iter_num:418/512, score: 4521483.1, best_score: 1700359.29
iter_num:419/512, score: 4531992.75, best_score: 1700359.29
iter_num:420/512, score: 4519005.59, best_score: 1700359.29
iter_num:421/512, score: 4535800.79, best_score: 1700359.29
iter_num:422/512, score: 4497848.09, best_score: 1700359.29
iter_num:423/512, score: 4539390.12, best_score: 1700359.29
iter_num:424/512, score: 4535468.19, best_score: 1700359.29
iter_num:425/512, score: 4206033.49, best_score: 1700359.29
iter_num:426/512, score: 4551868.13, best_score: 1700359.29
iter_num:427/512, score: 4583064.26, best_score: 1700359.29
iter_num:428/512, score: 4618585.19, best_score: 1700359.29
iter_num:429/512, score: 4495382.45, best_score: 1700359.29
iter_num:430/512, score: 4522385.93, best_score: 1700359.29
iter_num:431/512, score: 4283766.33, best_score: 1700359.29
iter_num:432/512, score: 4620270.74, best_score: 1700359.29
iter_num:433/512, score: 4558985.96, best_score: 1700359.29
iter_num:434/512, score: 4524990.32, best_score: 1700359.29
iter_num:435/512, score: 4584294.53, best_score: 1700359.29
iter_num:436/512, score: 4501041.07, best_score: 1700359.29
iter_num:437/512, score: 4510091.3, best_score: 1700359.29
iter_num:438/512, score: 4613941.95, best_score: 1700359.29
iter_num:439/512, score: 4575790.21, best_score: 1700359.29
iter_num:440/512, score: 4606760.33, best_score: 1700359.29
iter_num:441/512, score: 4554226.7, best_score: 1700359.29
iter_num:442/512, score: 4484391.58, best_score: 1700359.29
iter_num:443/512, score: 4568051.14, best_score: 1700359.29
iter_num:444/512, score: 4577131.57, best_score: 1700359.29
iter_num:445/512, score: 4628579.59, best_score: 1700359.29
iter_num:446/512, score: 4757046.51, best_score: 1700359.29
iter_num:447/512, score: 4594551.75, best_score: 1700359.29
iter_num:448/512, score: 4600388.63, best_score: 1700359.29
iter_num:449/512, score: 3929386.88, best_score: 1700359.29
iter_num:450/512, score: 2869881.49, best_score: 1700359.29
iter_num:451/512, score: 2965114.27, best_score: 1700359.29
iter_num:452/512, score: 2933765.14, best_score: 1700359.29
iter_num:453/512, score: 2882339.85, best_score: 1700359.29
iter_num:454/512, score: 2558810.58, best_score: 1700359.29
iter_num:455/512, score: 2473022.35, best_score: 1700359.29
iter_num:456/512, score: 2438094.02, best_score: 1700359.29
iter_num:457/512, score: 3151357.73, best_score: 1700359.29
iter_num:458/512, score: 3155017.37, best_score: 1700359.29
iter_num:459/512, score: 3151041.81, best_score: 1700359.29
iter_num:460/512, score: 3156688.73, best_score: 1700359.29
iter_num:461/512, score: 3153437.93, best_score: 1700359.29
iter_num:462/512, score: 3151963.91, best_score: 1700359.29
iter_num:463/512, score: 3152844.94, best_score: 1700359.29
iter_num:464/512, score: 3147861.64, best_score: 1700359.29
iter_num:465/512, score: 3871728.23, best_score: 1700359.29
iter_num:466/512, score: 3868197.16, best_score: 1700359.29
iter_num:467/512, score: 3865289.61, best_score: 1700359.29
iter_num:468/512, score: 3872603.96, best_score: 1700359.29
iter_num:469/512, score: 3859796.17, best_score: 1700359.29
iter_num:470/512, score: 3870581.56, best_score: 1700359.29
iter_num:471/512, score: 3858592.62, best_score: 1700359.29
iter_num:472/512, score: 3861530.74, best_score: 1700359.29
iter_num:473/512, score: 4289592.58, best_score: 1700359.29
iter_num:474/512, score: 4271343.72, best_score: 1700359.29
iter_num:475/512, score: 4265390.55, best_score: 1700359.29
iter_num:476/512, score: 4266769.77, best_score: 1700359.29
iter_num:477/512, score: 4274665.15, best_score: 1700359.29
iter_num:478/512, score: 4262599.39, best_score: 1700359.29
iter_num:479/512, score: 4259148.55, best_score: 1700359.29
iter_num:480/512, score: 4256639.36, best_score: 1700359.29
iter_num:481/512, score: 4465702.19, best_score: 1700359.29
iter_num:482/512, score: 4509572.65, best_score: 1700359.29
iter_num:483/512, score: 4480950.05, best_score: 1700359.29
iter_num:484/512, score: 4485733.58, best_score: 1700359.29
iter_num:485/512, score: 4538637.97, best_score: 1700359.29
iter_num:486/512, score: 4515052.97, best_score: 1700359.29
iter_num:487/512, score: 4535694.99, best_score: 1700359.29
iter_num:488/512, score: 4529491.41, best_score: 1700359.29
iter_num:489/512, score: 4206033.49, best_score: 1700359.29
iter_num:490/512, score: 4557421.42, best_score: 1700359.29
iter_num:491/512, score: 4591981.77, best_score: 1700359.29
iter_num:492/512, score: 4320524.47, best_score: 1700359.29
iter_num:493/512, score: 4515557.16, best_score: 1700359.29
iter_num:494/512, score: 4314728.21, best_score: 1700359.29
iter_num:495/512, score: 4418932.95, best_score: 1700359.29
iter_num:496/512, score: 4220051.1, best_score: 1700359.29
iter_num:497/512, score: 4564770.4, best_score: 1700359.29
iter_num:498/512, score: 4422980.95, best_score: 1700359.29
iter_num:499/512, score: 4322065.28, best_score: 1700359.29
iter_num:500/512, score: 4286348.46, best_score: 1700359.29
iter_num:501/512, score: 4319233.39, best_score: 1700359.29
iter_num:502/512, score: 4279382.11, best_score: 1700359.29
iter_num:503/512, score: 4221739.1, best_score: 1700359.29
iter_num:504/512, score: 4207797.28, best_score: 1700359.29
iter_num:505/512, score: 4496187.16, best_score: 1700359.29
iter_num:506/512, score: 4409655.72, best_score: 1700359.29
iter_num:507/512, score: 4281440.41, best_score: 1700359.29
iter_num:508/512, score: 4266501.08, best_score: 1700359.29
iter_num:509/512, score: 4254154.24, best_score: 1700359.29
iter_num:510/512, score: 4226251.28, best_score: 1700359.29
iter_num:511/512, score: 4281728.01, best_score: 1700359.29
iter_num:512/512, score: 4201887.53, best_score: 1700359.29

최종 모델 학습

  • 모델 선정과정에서 사용한 Train데이터는 X데이터를 split 한것이었으므로 다시 합쳐줄 필요가 있다.

  • 하지만, split한 데이터들은 biase처리나 sacaling을 했지만, 예측에 사용할 X데이터는 전처리가 되어 있지 않다.

  • 이를 위해 pipeline을 구축해서 X에도 동일한 전처리를 해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def pipeline(X):
    # 치우침 처리
    X[biased_variables] = X[biased_variables] - X[biased_variables].min() + 1
    #Scaling
    X[biased_variables] = np.sqrt(X[biased_variables])        
    
    # DataFrame으로 변형
    X = pd.DataFrame(scaler.transform(X), columns = X.columns)
    
    # 선정된 feature만 X에 할당
    X = X[best_features]
    return X

# 최적의 값을 갖는 모델을 선정하여 fit
model = best_model(**best_paramter).fit(pipeline(X).values, Y)

적용 데이터 구성

1
2
3
4
# 예측해야할 값의 범위 : 2019-03-01 ~ 2019-05-31
# train데이터와 동일 방식으로 처리

submission_df['std_mth'] = (2019 - 2016) * 12 + 2
1
2
3
# region 변수와 type_of_business 변수 부착 
submission_df['region'] = submission_df['store_id'].replace(store_to_region)
submission_df['type_of_business'] = submission_df['store_id'].replace(store_to_type_of_business)

특징 부착

1
2
submission_df['평균할부율'] = submission_df['store_id'].replace(installment_term_per_store.to_dict())
submission_df.head()
store_id amount std_mth region type_of_business 평균할부율
0 0 0 38 미분류 기타 미용업 0.04
1 1 0 38 미분류 미분류 0.00
2 2 0 38 미분류 미분류 0.08
3 4 0 38 서울 종로구 미분류 0.00
4 5 0 38 미분류 의복 액세서리 및 모조 장신구 도매업 0.08
1
2
# 기존 submission_df 파일의 불필요한 컬럼 제거
submission_df.drop('amount', axis = 1, inplace = True)
1
2
3
4
5
6
7
8
9
10
# t - i (i = 1, 2, 3) 시점의 부착
# submission_df의 std_mth는 total_amt_per_mth_and_store의 std_mth-i와 병합되어야 하므로, total_amt_per_mth_and_store의 std_mth에 i를 더했다.

for i in range(1, 4):
    total_amt_per_mth_and_store['std_mth_{}'.format(i)] = total_amt_per_mth_and_store['std_mth'] + i    
    submission_df = pd.merge(submission_df, total_amt_per_mth_and_store.drop('std_mth', axis = 1), left_on = ['store_id', 'std_mth'], right_on = ['store_id', 'std_mth_{}'.format(i)])
    submission_df.rename({"amount":"{}_before_amount".format(i)}, axis = 1, inplace = True)
    submission_df.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)
    total_amt_per_mth_and_store.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)
    
1
2
3
4
5
6
7
8
# 지역 관련 변수 부착
for i in range(1, 4):
    amt_mean_per_std_mth_and_region['std_mth_{}'.format(i)] = amt_mean_per_std_mth_and_region['std_mth'] + i
    submission_df = pd.merge(submission_df, amt_mean_per_std_mth_and_region.drop('std_mth', axis = 1), left_on = ['region', 'std_mth'], right_on = ['region', 'std_mth_{}'.format(i)])
    submission_df.rename({"amount":"{}_before_amount_of_region".format(i)}, axis = 1, inplace = True)
    
    submission_df.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)
    amt_mean_per_std_mth_and_region.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)    
1
2
3
4
5
6
7
8
9
10
11
12
# t - i (i = 1, 2, 3) 시점의 부착
# submission_df의 t는 total_amt_per_mth_and_store의 std_mth-i와 병합되어야 하므로, total_amt_per_mth_and_store의 std_mth에 i를 더했다.

for i in range(1, 4):
    amount_mean_per_mth_and_type_of_business['std_mth_{}'.format(i)] = amount_mean_per_mth_and_type_of_business['std_mth'] + i
    submission_df = pd.merge(submission_df, amount_mean_per_mth_and_type_of_business.drop('std_mth', axis = 1), left_on = ['type_of_business', 'std_mth'], right_on = ['type_of_business', 'std_mth_{}'.format(i)])
    submission_df.rename({"amount":"{}_before_amount_of_type_of_business".format(i)}, axis = 1, inplace = True)
    
    submission_df.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)
    amount_mean_per_mth_and_type_of_business.drop(['std_mth_{}'.format(i)], axis = 1, inplace = True)       
    
submission_df.head()
store_id std_mth region type_of_business 평균할부율 1_before_amount 2_before_amount 3_before_amount 1_before_amount_of_region 2_before_amount_of_region 3_before_amount_of_region 1_before_amount_of_type_of_business 2_before_amount_of_type_of_business 3_before_amount_of_type_of_business
0 0 38 미분류 기타 미용업 0.04 682857.14 874571.43 676000.00 946877.71 1000725.02 988619.51 585125.00 650055.95 558241.67
1 792 38 미분류 기타 미용업 0.22 743214.29 871071.43 973857.14 946877.71 1000725.02 988619.51 585125.00 650055.95 558241.67
2 1828 38 경기 용인시 기타 미용업 0.20 953000.00 816857.14 911957.14 1801050.57 2009935.83 1897274.57 585125.00 650055.95 558241.67
3 23 38 경기 안양시 기타 미용업 0.05 660857.14 999285.71 827571.43 784378.00 642183.20 678844.63 585125.00 650055.95 558241.67
4 192 38 경기 화성시 기타 미용업 0.10 467571.43 550571.43 399142.86 1209348.40 1125180.78 1049586.72 585125.00 650055.95 558241.67
1
2
3
4
5
6
7
submission_X = submission_df[X.columns]
submission_X = pipeline(submission_X)

pred_Y = model.predict(submission_X)

# 제출 양식과 맞추기 위해 pred_Y를 amount로 입력
result = pd.DataFrame({"store_id":submission_df['store_id'].values,"amount":pred_Y})
1
result = result.sort_values(by='store_id')
1
result
store_id amount
0 0 4714475.69
12 1 1527393.67
13 2 1564663.27
612 4 6729287.35
1187 5 4485424.49
... ... ...
609 2132 2883704.29
610 2133 1507944.90
1186 2134 2159169.39
611 2135 2164861.22
1463 2136 10333804.08

1967 rows × 2 columns

결과 제출용 파일 저장

1
result.to_csv('E:\\OneDrive\\Jupyter\\포트폴리오\\[예측] 상점 신용카드 매출 예측하기\\submission.csv', index=False)

제출 결과

result.png

댓글남기기