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파일이다.
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을 한 뒤 생산량을 기입한다.
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')
1)-4 out = out_1 + out_2 +out_3는 어떤 결과를 내는가?
out은 다음과 같은 결과를 낸다.
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에 재고를 더한다.
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에 적힌대로 월에따라 자르기 양품률을 정의하고
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
목적함수에 대하여 분석을 해보자.
cal_score함수는 단순히 blk_dffs를 더한 값.