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

Forecasts for Product Demand (5) 데이터셋 셋업

LearnerToRunner 2023. 1. 11. 11:27

Forecasts for Product Demand

본격적으로 데이터 분석을 시작하기 전에

기본적으로 처리된 데이터셋을 빠르게 불러올 수 있도록 셋업

다루어야 할 데이터가 많기 때문에 클래스를 사용할 예정입니다

 

 

참고 포스트
Pandas read_csv가 너무 느리다면? 대용량 csv 파일 빠르게 불러오기

 

1단계

기본적인 Conversion 및 Date에서

추출가능한 시간정보 추가

 

 

Dataset_Setup 클래스 생성
아래 세 개를 입력받음

a. 원본데이터셋 경로,
b.처리된 데이터 csv 데이터셋 경로
c. 처리된 데이터 parquet 데이터셋 경로
import pandas as pd

"""
pyarrow 설치
pip install pyarrow
"""

import pyarrow.csv as pv
import pyarrow.parquet as pq

class Dataset_Setup():
    def __init__(self, path_orgcsv, path_prcdcsv, path_prcdpq):
        self.path = path_orgcsv # path of the original dataset
        self.path_prcd = path_prcdcsv #path of dataset to be processed
        self.path_parquet = path_prcdpq # path of the dataset to be processed in a parquet format

        self.df_org = pd.read_csv(self.path, parse_dates=['Date']) # original dataset read
        self.df = self.df_org.loc[self.df_org['Warehouse'] != 'Whse_A'].reset_index(drop = True) # dataset with added time features

 


 

Dataset_Setup 클래스 내
기본적인 데이터 conversion 및 시간 특징을 추가하여
csv로 저장하는 메서드를 추가

    def generate_dataset_processed(self):
        """
        Save the processed dataset after converting string to integer and adding time features extracted from 'Date' column
        :return: None
        """
        df = self.df
        """ Data Conversion """
        # Product_Code
        df['Product_Code'] = df['Product_Code'].str.replace('Product_', '').astype(int)
        # Warehouse
        df['Warehouse'] = df['Warehouse'].str.replace('Whse_', '')
        # Product_Category
        df['Product_Category'] = df['Product_Category'].str.replace('Category_', '').astype(int)

        # Order Demand
        df['Order_Demand'] = df['Order_Demand'].replace('[)]', '', regex=True)
        df['Order_Demand'] = df['Order_Demand'].replace('[(]', '-', regex=True)
        df['Order_Demand'] = df['Order_Demand'].astype(int)

        # Basic Time Features
        df['Year'] = df['Date'].dt.year  # 연도
        df['Quarter'] = df['Date'].dt.quarter  # 월
        df['Month'] = df['Date'].dt.month  # 월
        df['Half'] = np.where(df['Month'] <= 6, 1, 2)
        df['Week'] = df['Date'].dt.isocalendar().week  # 주 (week of the year)
        df['DayOW'] = df['Date'].dt.dayofweek  # 요일 (day of the week) FYI) Mon 0 - Sun = 6
        df['Year'] = df['Date'].dt.year.astype('Int16')  # 연도
        df['Month'] = df['Date'].dt.month.astype('Int16')  # 월
        df['DayOW'] = df['Date'].dt.dayofweek.astype('Int16')  # 요일 (day of the week) FYI) Mon 0 - Sun = 6
        df['Year_Month'] = df['Date'].dt.strftime('%Y-%m')  # Time in %Y%m format
        df['Year_Week'] = df['Date'].dt.strftime('%Y-%W')  # Time in %Y%W format

        df.to_csv(self.path_prcd, index=False)

 

Dataset_Setup 클래스 내
처리된 데이터셋을 parquet 형태로 저장하는 메서드 추가

    def convert_processed_dataframe_from_csv_to_parquet(self):
        """
        Writes the processed dataset in a parquet format after reading the processed dataset in csv format
        :return:
        """
        df = pv.read_csv(self.path_prcd)
        pq.write_table(df, self.path_parquet)

 

 

Dataset_Setup 클래스가 호출될 때 자동으로 작동되도록 함

최종 코드
class Dataset_Setup():
    def __init__(self, path_orgcsv, path_prcdcsv, path_prcdpq):
        self.path = path_orgcsv # path of the original dataset
        self.path_prcd = path_prcdcsv #path of dataset to be processed
        self.path_parquet = path_prcdpq # path of the dataset to be processed in a parquet format

        self.df_org = pd.read_csv(self.path, parse_dates=['Date']) # original dataset read
        self.df = self.df_org.loc[self.df_org['Warehouse'] != 'Whse_A'].reset_index(drop = True) # dataset with added time features

        self.generate_dataset_processed() #
        self.convert_processed_dataframe_from_csv_to_parquet()

    def generate_dataset_processed(self):
        """
        Save the processed dataset after converting string to integer and adding time features extracted from 'Date' column
        :return: None
        """
        df = self.df
        """ Data Conversion """
        # Product_Code
        df['Product_Code'] = df['Product_Code'].str.replace('Product_', '').astype(int)
        # Warehouse
        df['Warehouse'] = df['Warehouse'].str.replace('Whse_', '')
        # Product_Category
        df['Product_Category'] = df['Product_Category'].str.replace('Category_', '').astype(int)

        # Order Demand
        df['Order_Demand'] = df['Order_Demand'].replace('[)]', '', regex=True)
        df['Order_Demand'] = df['Order_Demand'].replace('[(]', '-', regex=True)
        df['Order_Demand'] = df['Order_Demand'].astype(int)

        # Basic Time Features
        df['Year'] = df['Date'].dt.year  # 연도
        df['Quarter'] = df['Date'].dt.quarter  # 월
        df['Month'] = df['Date'].dt.month  # 월
        df['Half'] = np.where(df['Month'] <= 6, 1, 2)
        df['Week'] = df['Date'].dt.isocalendar().week  # 주 (week of the year)
        df['DayOW'] = df['Date'].dt.dayofweek  # 요일 (day of the week) FYI) Mon 0 - Sun = 6
        df['Year'] = df['Date'].dt.year.astype('Int16')  # 연도
        df['Month'] = df['Date'].dt.month.astype('Int16')  # 월
        df['DayOW'] = df['Date'].dt.dayofweek.astype('Int16')  # 요일 (day of the week) FYI) Mon 0 - Sun = 6
        df['Year_Month'] = df['Date'].dt.strftime('%Y-%m')  # Time in %Y%m format
        df['Year_Week'] = df['Date'].dt.strftime('%Y-%W')  # Time in %Y%W format

        df.to_csv(self.path_prcd)

    def convert_processed_dataframe_from_csv_to_parquet(self):
        """
        Writes the processed dataset in a parquet format after reading the processed dataset in csv format
        :return:None
        """
        df = pv.read_csv(self.path_prcd)
        pq.write_table(df, self.path_parquet)



path = './archive/Historical Product Demand.csv' # path of the original dataset
path_prcd = './archive/Historical Product Demand(Processed).csv' #path of dataset to be processed
path_parquet = './archive/Historical_Product_Demand(Processed).parquet' # path of the dataset to be processed in a parquet format

# Generation of dataset with conversion and time feature additions in parquet format
# TODO-Inactivate after generation
Dataset_Setup(path_orgcsv=path, path_prcdcsv= path_prcd, path_prcdpq= path_parquet)

 


2단계

Dataset 클래스 생성

데이터분석에 실제로 사용할 데이터 프레임을 제공할 클래스

 

저장된 parquet 을 읽기본적인 Conversion 및 Date에서

추출가능한 시간정보 추가

 


 

3단계

결과비교

(용량관점)

가공된 데이터셋의 용량 50MB가
parquet 형태로 바뀌며 6MB로 줄어듦
약 87% 감소




 

결과비교
(처리시간 관점)

처리 소요시간이 약 100배 수준으로 감소
12.6초 >> 0.16초


def timeit(func):
    from functools import wraps
    import time
    @wraps(func)
    def timeit_wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        total_time = end_time - start_time
        print(f'Function {func.__name__}{args} {kwargs} Took {total_time:.4f} seconds')
        return result
    return timeit_wrapper
    
    
@timeit
def run_class_DatasetSetup():
    Dataset_Setup(path_orgcsv=path, path_prcdcsv=path_prcd, path_prcdpq=path_parquet)
    # 시간의 공정성을 위해 시간 측정당시에는 처리된 데이터프레임을 csv로 저장하고 parquet으로 변환하는 과정을 비활성화했음

@timeit
def run_class_Dataset():
    Dataset(path_pq= path_parquet)

run_class_DatasetSetup()
run_class_Dataset()

 

원본 csv 파일을 읽고 conversion/시간 특성 추가에 걸리는 시간
저장된 parquet을 읽고 pandas 데이터프레임으로 변환하는데 걸리는 시간

 

 


TO-DOs

메인파일 만들기

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

웨어하우스 A 자료 제외하기

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

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

이상치 처리

 

 

728x90