빅데이터(파이썬)/DA_Forecasts for Product Demand

Forecasts for Product Demand (4) 데이터 정제

LearnerToRunner 2023. 1. 9. 17:54

Forecasts for Product Demand

데이터 정제

 

데이터 결측치 처리

 

 

데이터셋에 결측치는 얼마나 존재하나?

Date 칼럼에만 결측치가 존재
전체 데이터의 1% 수준
pd_profiling

pd_profiling 보고서에서 확인

 

 

""" Missing Values """
print(df.isnull().sum())
print(df.isnull().mean())


 

Date 칼럼에만 결측치가 분포한다
결측치 발생에 규칙이 더 있을까?

웨어하우스 A에서만 Date 결측치가 발생
Order Demand 양수, 음수가 59:41 비율로 존재

어하우스 A에서만 Date 결측치가 발생 근거
cnt_cols = len(df_null.columns)
for i, col in enumerate(df_null.columns):
    plt.pie(df_null[col].value_counts(), labels = df_null[col].value_counts().index)
    plt.title(f'Missing Values by {col}')
    plt.legend()
    plt.show()
    
# 결측치: Order Demand 음수/양수 비율 확인하기
df_null['Positive_Demand'] = np.where(df_null['Order_Demand']>=0, 1, 0)
plt.pie(df_null['Positive_Demand'].value_counts(), labels = df_null['Positive_Demand'].value_counts().index, autopct='%.0f')
plt.legend()
plt.title("Positive/Negative Demand Proportion")
plt.show()

 

결측치가 있는 데이터의 제품코드/웨어하우스 구성

 

결측치가 있는 데이터의 제품카테고리/Order Demand 구성
결측치 데이터 중 demand가 0 이상/미만의 비율은 59:41

 

 


결측치 처리

 

 

웨어하우스 별 오더 Demand 비율은?
웨어하우스 A 데이터 수는 전체의 14.6%를 차지하지만
웨어하우스 A에서 발생하는 Order Demand는 전체의 2.81%에 불과

근거
pd profiling 레포트

 

# 웨어하우스 A의 Date 데이터 범위
print(df[df['Warehouse'] == 'A']['Date'].describe())

 

# 웨어하우스 별 총 수량 및 비중
total_demand = df['Order_Demand'].sum()
for wh in df['Warehouse'].unique():
    wh_demand = df[df['Warehouse'] == wh]['Order_Demand'].sum()
    print(wh, wh_demand, f'({wh_demand/total_demand*100:.2f}%)')

# 웨어하우스 별 오더 총수량, 평균수량, 표준편차, 데이터 수
print(df.groupby(['Warehouse']).agg({'Order_Demand': ['sum', 'mean', 'std', 'count']}))

 

웨어하우스 A에서 발생한 Demand는 전체 Demand의 2.81%에 불과하다

 

# 웨어하우스 별 오더 총수량, 평균수량, 표준편차, 데이터 수
print(df.groupby(['Warehouse']).agg({'Product_Code': ['nunique'], 'Product_Category':['nunique']}))

Order Demand 규모가 작으나 취급하는 제품과 카테고리 수는 많다. 과연 수익성이 괜찮을까 싶은 생각도 든다.


 

null 데이터를 drop 해야할까? 웨어하우스 A를 분석에서 제외해야할까?

웨어하우스 A 데이터는 분석에서 제외하기로 결정함

Null 데이터의 수와 order demand가 
웨어하우스 A, 전체 데이터 셋에서 차지하는 비율은 크지 않음
(데이터 수, Order demand 모두)


하지만 모델의 정확성을 높이기 위해 데이터가 적은 2011, 2017년 데이터는 제외할 예정.
웨어하우스 A의 null 값이 2011, 2017일 경우 학습데이터 일관성을 해칠 수 있음

모델의 예측 정확성을 향상하기 위해 웨어하우스 A 데이터는 제외함


# Date 결측치 데이터 수와 Order Demand 합의 비중 : 웨어하우스 A & 전체데이터
df_null = df[df['Date'].isnull()]
df_whA = df[df['Warehouse'] == 'A']

print(f'Null count / WH A count = {len(df_null) / len(df_whA)*100:.4f}%') #null 데이터가 WH A 데이터에서 차지하는 비중
print(f"Null demand / WH A demand = {df_null['Order_Demand'].sum() / df_whA['Order_Demand'].sum()*100:.4f}%")

print(f'Null count / total count = {len(df_null) / len(df)*100:.4f}%') #null 데이터가 전체 데이터에서 차지하는 비중
print(f"Null demand / total demand = {df_null['Order_Demand'].sum() / df['Order_Demand'].sum()*100:.4f}%")

print(f'WH A count / total count = {len(df_whA) / len(df)*100:.4f}%') #WH A 데이터가 전체 데이터에서 차지하는 비중
print(f"WH A demand / total demand = {df_whA['Order_Demand'].sum() / df['Order_Demand'].sum()*100:.4f}%")

# 데이터 / Order Demand 구성 확인
df_null['OD_Pos'] = np.where(df_null['Order_Demand']>=0, 1, 0)
df_whA['OD_Pos'] = np.where(df_whA['Order_Demand']>=0, 1, 0)
grp_null = df_null.groupby('OD_Pos', as_index=False).agg({'Order_Demand':['sum', 'count']})
grp_whA = df_whA.groupby('OD_Pos', as_index=False).agg({'Order_Demand':['sum', 'count']})
print(grp_null)
print(grp_whA)

 

null(위), WH A(아래) 데이터의 양/음 order demand 합계 및 카운트


중복값 처리

 

 

중복값이 있는가? 있다면 전체데이터셋 중 비율은?
웨어하우스 A 데이터를 제외한 데이터셋에서 11.34%가 중복값으로 나옴

데이터셋 제공자가 중복값에 대한 설명이 없고
매일 수차례의 Order Demand 수정이 일어나는 것을 고려하여

중복값은 중복값이 아닌
동일한 수량의 오더를 추가로 넣은것으로 간주하기로 함



df = df.loc[df['Warehouse'] != 'A']

# Duplicate check
df_dupe = df[df.duplicated()]
idx_dupe = df_dupe.index.tolist()
df_check = df.copy()
# df_check['Dupe'] = np.where(df_check.index in idx_dupe, 1, 0)
print(f'Percentage of dupe = {len(df_dupe)/len(df)*100:.2f}%')
print(df_dupe[['Product_Code', 'Warehouse', 'Product_Category', 'Date', 'Order_Demand']].sort_values(by=['Warehouse', 'Date', 'Order_Demand']))

display_all_on()
print(df_check[(df_check['Date'] == datetime.datetime(2012,1,10)) & (df_check['Warehouse'] == 'C')][['Product_Category', 'Product_Code', 'Order_Demand']].sort_values(by=['Product_Category', 'Product_Code', 'Order_Demand']))

2012년 1월 10일 창고 C의 데이터


TO-DOs
결측치 처리, 중복 데이터 처리

 

2011년, 2017년 데이터 drop 하기main 파일 만들어서 EDA에서 추가한 특징 재현하기

오더취소 횟수, 취소량 특징으로 추가하기

추가한 특징을 토대로 segmentation 진행하기

이상치 처리

728x90