본문 바로가기

카테고리 없음

simulator.get_score(submission) 분석

1) genome.score, _ = simulator.get_score(submission) 실행

get_score함수는 다음과 같다. 이에 대하여 차례대로 분석해 보자.

    def get_score(self, df):
        df = self.subprocess(df) #df는 predict해서 나온 결과. 그 안에 subprocess를 넣으면?
        #out_1, 2, 3가 의미하는 바는 뭘까??
        out_1 = self.cal_schedule_part_1(df)
        out_2 = self.cal_schedule_part_2(df, line='A')
        out_3 = self.cal_schedule_part_2(df, line='B')
        out = out_1 + out_2 + out_3
        out = self.add_stock(out, self.stock)
        order = self.order_rescale(out, self.order)                    
        out, blk_diffs = self.cal_stock(out, order)                    
        score = self.cal_score(blk_diffs) 
        return score, out
    def subprocess(self, df):
        out = df.copy()
        column = 'time'

        #인텍스를 'time'열을 datetime으로 변환한 시간으로 바꾼다.
        out.index = pd.to_datetime(out[column])# 2020-04-01 00:00:00(dtype:object) --> 2020-04-01 00:00:00(dtype : datetime64[ns])
        out = out.drop([column], axis=1) #기존 열을 drop한다.
        out.index.name = column
        return out

여기서 df는 submission파일이다.

학습한 모델을 가지고 predict한 결과.

0) df = self.subprocess(df)

index를 time으로 설정하기 위한 subprocess를 수행한다.

 

1)-1 out_1 = cal_schedule_part_1(df) 

 

df는 submission --> 학습한 모델을 이용해서 predict한 결과.

--> PRT_1,2,3,4는 전부 0이고 Event_A,B,  MOL_A,B에 대한 결과만 있다.

dataframe을 전체적으로 보고 싶을때는 다음과 같이 하면 된다.

with pd.option_context('display.max_rows', None, 'display.max_columns', 5):
    print(df_set)
    columns = ['PRT_1', 'PRT_2', 'PRT_3', 'PRT_4']
    df_set = df[columns] #submission에서 위 4개의 column을 빼 온것
    df_out = df_set * 0

    p = 0.985 # 양품률(원형제작)
    #투입 23일후 원형 생산 완료
    dt = pd.Timedelta(days=23) # 이건또 뭐지? --> Time을 표현하는 객체?series?Components? 덧셈(연산)을 가능하게 한다. 
    end_time = df_out.index[-1]

PRT_1,2,3,4 열을 추출해서 모든 원소에 0을 곱해 df_out을 만들고.

dt는 23일 end_time은 끝나는 시간인  Timestamp('2020-06-30 23:00:00')

 

    for time in df_out.index:
        out_time = time + dt
        if end_time < out_time:
            break
        else:            
            for column in columns: # ['PRT_1', 'PRT_2', 'PRT_3', 'PRT_4']
                set_num = df_set.loc[time, column] #이게 전부 0인데.. 무슨 의미가 있는거지??
                if set_num > 0:
                    out_num = np.sum(np.random.choice(2, set_num, p=[1-p, p]))#set_num집합에서 2개만 선택, 선택 확률은 1-p, p
                    df_out.loc[out_time, column] = out_num

dt_out.index는 모든 날짜에 대한 datetime64타입 원소가 들어있는 DateTimeIndex객체이다.

모든 시간에 대해 반복문을 돈다.(1시간 단위)

 

time + dt #현재 loop에 해당하는 time 에 23일(원형 제작에 걸리는 시간)을 더한다. 제작이 완료될 시점이 end_time보다 크면 제작을 할 수 없으므로(해도 소용없으므로) break한다.

 

그렇지 않으면

모든 columns를 돌면서 set_num를 해당 위치(time,column)의 df_set으로 하고 

set_num가 >0 이면 

out_num을 set_num에서 random하게 선택하는데.. --> 이것에 대해서 다시 자세하게 살펴보면.

이런식의 결과를 낸다. 2개중에 선택한다.(0,1) set_num개를 p=[1-p, p]의 확률로

이런 의미인것이다. 여기서 2-->3으로 바뀌면 p = [?,?,?]이런식으로 바뀌어야한다.

 

out_num은 결과 array의 원소를 싹 더한것이고 df_out의 해당 위치(time,column)에 값을 넣는다.

cal_schedule_part_1 함수의 역할.

set_num은 그 시간에 투입되는 해당 PRT의 개수이다. 양품률을 이용해서 실제로 simulation을 한 다음에 실제로 몇개가 완성이 되었는지를 확인하는것

out_1이 의미하는 것.

submission에 적힌 PRT_투입량에 양품률과 소요시간을 적용하여 생산 simulation을 한 뒤 생산량을 기입한다. 

submission의 PRT_행의 값들이 전부 0이였으므로 결과가 전부 0이다. 

1)-2 out2 = cal_schedule_part_2(self, df, line='A')

 if line == 'A':
            columns = ['Event_A', 'MOL_A']
        elif line == 'B':
            columns = ['Event_B', 'MOL_B']
        else:
            columns = ['Event_A', 'MOL_A']
            
        schedule = df[columns].copy()
        
        schedule['state'] = 0
        schedule['state'] = schedule[columns[0]].apply(lambda x: self.get_state(x))
        schedule['state'] = schedule['state'].fillna(method='ffill')
        schedule['state'] = schedule['state'].fillna(0)
        
        schedule_process = schedule.loc[schedule[columns[0]]=='PROCESS']
        df_out = schedule.drop(schedule.columns, axis=1)
        df_out['PRT_1'] = 0.0
        df_out['PRT_2'] = 0.0
        df_out['PRT_3'] = 0.0
        df_out['PRT_4'] = 0.0
        df_out['MOL_1'] = 0.0
        df_out['MOL_2'] = 0.0
        df_out['MOL_3'] = 0.0
        df_out['MOL_4'] = 0.0

line 이 'A'인지 'B'인지에 따라서 columns를 택하고 schedule변수에 copy한다.

scheudle에 'state'라는 열을 추가하는데 이에 들어가는 값은.

get_state()를 이용해서 apply한 값이다.  그리고 finllna한다. 그렇다면 get_state()는 어떤 함수인가?

 

1)-2-a) get_ state()에 대한 분석.

    def get_state(self, data):
        if 'CHECK' in data:
            return int(data[-1])
        elif 'CHANGE' in data:
            return int(data[-1])
        else:
            return np.nan   

CHECK, CHANGE 이면 data[-1]을 대입하고 아니면 np.nan을 대입한다.  --> data[-1]은 data의 마지막 원소 즉 CHECK_2 면 2 CHECK_다는 뜻.

 

 

fillna(method='ffill')의 역할은 무엇인가? :  결측값을 앞 방향으로 채운다.(fill gaps forward) : 즉 CHECK_2다음에 나오는 PROCESS에 대해서는 2로 채워진다는 뜻.(rfriend.tistory.com/262)

fillna(0) : 나머지 결측값은 0으로 대체한다. 

schedule_process는 shceludeschedule에서 이벤트가 PPROCESS인 행만 고른것

df_out을 초기화한다.

        p = 0.975
        times = schedule_process.index
        for i, time in enumerate(times):
            value = schedule.loc[time, columns[1]] # columns[1] = MOL_A
            state = int(schedule.loc[time, 'state'])
            df_out.loc[time, 'PRT_'+str(state)] = -value
            if i+48 < len(times):
                out_time = times[i+48]
                df_out.loc[out_time, 'MOL_'+str(state)] = value*p

        df_out['BLK_1'] = 0.0
        df_out['BLK_2'] = 0.0
        df_out['BLK_3'] = 0.0
        df_out['BLK_4'] = 0.0
        return df_out

value는 schedule에 해당 위치(time, 'MOL')에 있는 값에 p를 곱한것.

왜 여기서는 그냥 p를 곱했을까 위에서는(원형 생성 공정) simultation을 했는데..

df_out 의 해당 위치(time, 'PRT_) 원소를 -value로 바꾸는것도 잘 이해가 안간다. -->(해결)MOL_A의 써진 양만큼 PRT가 빠져나가가기 때문.

values는 해당 time의 MOL_A 투입 개수이고 .

이를 이용해서 48시간후의 MOL_1or2or,3or,4의 개수를 구한다.(물론 양품률을 곱해서) 

 

1)-3 out3 = cal_schedule_part_2(self, df, line='B')

out2와 결과가 같다. 

 

1)-4 out = out_1 + out_2 +out_3는 어떤 결과를 내는가?

out은 다음과 같은 결과를 낸다. 

 

사용한 PRT_와 만들어진 MOL_의 개수를 입력한 dataframe

1)-4 out = self.add_stock(out, self.stock) , add_stock에 대한 분석.

    def add_stock(self, df, df_stock):
        df_out = df.copy()
        for column in df_out.columns:
            df_out.iloc[0][column] = df_out.iloc[0][column] + df_stock.iloc[0][column]
        return df_out

df = out
df_stock = stock

 

stock은 어떻게 정의되는가?

stock.csv파일이다. 

 

out에 재고를 더한다. 

왜 0번째 row에만 적용하는것이지?

1)-5 order = self.order_rescale(out, self.order)

def order_rescale(df, df_order):
    df_rescale = df.drop(df.columns, axis=1) # 열을 전부 drop한다.
    dt = pd.Timedelta(hours=18) #18시간 Timedelta객체를 생성한다.
    for column in ['BLK_1', 'BLK_2', 'BLK_3', 'BLK_4']:
        for time in df_order.index:
            df_rescale.loc[time+dt, column] = df_order.loc[time, column]
    df_rescale = df_rescale.fillna(0)
    return df_rescale

18시간이 무엇을 뜻하는것인가? 왜 18시간을 더한 시간 row에 df_order의 원소를 집어넣는 것인가?

18이 무엇을 뜻하는지는 모르겠네..-->마감시간을 뜻한다.

 

자르기 공정의 월별 양품률을 이용해서 재고를 계산한다.?

order.csv를 이용해서 매일 18시에 있어야할 재고를 계산하고 이를 (91*4) --> (2184 *4) matrix로 rescale한다. 

 

1)-6 out, blk_diffs = self.cal_stock(out, order)

df = df_out #6.30까지 프로세스를 다 진행했다고 했을때 2184시간별 out(PRT,MOL)
df_order = df_rescale # BLK주문량 : 매일 18:00    

def cal_stock(self, df, df_order):

  df_stock = df * 0
  blk2mol = {}
  blk2mol['BLK_1'] = 'MOL_1'
  blk2mol['BLK_2'] = 'MOL_2'
  blk2mol['BLK_3'] = 'MOL_3'
  blk2mol['BLK_4'] = 'MOL_4'

  cut = {}
  cut['BLK_1'] = 506 #MOL_1, MOL_2는 각각 506개의 BLK_1,2로 잘림.
  cut['BLK_2'] = 506
  cut['BLK_3'] = 400 # 3,4는 400개로 잘림.
  cut['BLK_4'] = 400

  p = {}
  p['BLK_1'] = 0.851 #자르기 양품률
  p['BLK_2'] = 0.901
  blk_diffs = []

  for i, time in enumerate(df.index): #2184번(시간)동안 루프 돈다
      month = time.month # 3,4는 월별로 자르기 양품률이 달라진다.
      if month == 4: #4월이면
          p['BLK_3'] = 0.710
          p['BLK_4'] = 0.700        
      elif month == 5:
          p['BLK_3'] = 0.742
          p['BLK_4'] = 0.732
      elif month == 6:
          p['BLK_3'] = 0.759
          p['BLK_4'] = 0.749
      else:
          p['BLK_3'] = 0.0
          p['BLK_4'] = 0.0
      if i == 0:
          df_stock.iloc[i] = df.iloc[i]# 첫 행은 그대로 대입한다.
      else: #두번때 행 부터는
          df_stock.iloc[i] = df_stock.iloc[i-1] + df.iloc[i] #df_stock의 전 행과 df의 현재행을 더한다.
          for column in df_order.columns: # 4번 반복한다 ['BLK_1', 'BLK_2', 'BLK_3', 'BLK_4']
              val = df_order.loc[time, column] # val은 주문량
              if val > 0: # 주문량이 있으면.
                  mol_col = blk2mol[column] #MOL 1,2,3,4중에 하나
                  mol_num = df_stock.loc[time, mol_col] #MOL의 재고를 살펴본다. 
                  df_stock.loc[time, mol_col] = 0#재고를 mol_num에 저장했으니 이제 0

                  #생성된 BLK에 관한 식.
                  blk_gen = int(mol_num*p[column]*cut[column]) # 재고 * 양품률 * 잘리는개수
                  blk_stock = df_stock.loc[time, column] + blk_gen #(time, BLK_)값과 재고를 더한다.
                  blk_diff = blk_stock - val# 재고와 주문량의 차이를 구한다. 

                  df_stock.loc[time, column] = blk_diff #재고와 주문량의 차이로 대체한다. 
                  blk_diffs.append(blk_diff)

cal stock은 뭘까?

 

blk2mol은  mol을 blk로바꾸는 것?

 

out과 order가 뭔지 정확히 다시 정의할 필요가 있다. 아래 캡처를 참고하자.

 

cut_yield.csv에 적힌대로 월에따라 자르기 양품률을 정의하고

 

 

이것이 order
이것이 out

 

out

1-7) score = self.cal_score(blk_diffs)

    def cal_score(self, blk_diffs):
        # Block Order Difference
        blk_diff_m = 0
        for item in blk_diffs:
            if item < 0:
                blk_diff_m = blk_diff_m + abs(item)
        score = blk_diff_m
        return score

12,898,988

목적함수에 대하여 분석을 해보자. 

 cal_score함수는 단순히 blk_dffs를 더한 값.