글또9기:영국직장:데이터사이언티스트

글또9기 | 노력과 변명 사이 #tkinter

채유나 chaeyoonaaa 2024. 2. 20. 17:52
반응형

tkinter 는 파이썬에서 모-던하게 그래픽으로 GUI를 생성할 수 있게 하는 패키지입니다. 공식닥스 여기를 참고하고 튜토리얼 몇 개 (추천1 Basic 5시간, 추천2 Full 18시간)를 시작하게 된 계기는 텍스트 프로세싱으로 해결할 수 없는 인풋 한계가 너무 커지면서 입니다.

 

 

 

본디 의료 도메인 특성상 세부 의과 분류가 매우 정확해야 하는데 제가 담당하는 정책 분야에서 (예를 들어 예산 등 리소스 분배 등으로) 의과 분류에 더한 지엽적 논의 사항이 더해지며 모델에 컨트롤 해야 하는 내용이 너무 많습니다. 바꿔 말해, 전처리 비중이 몹시 크고 수작업으로 하드코딩해야 하는 부분이 많습니다. 쉽게 말해 입력값 맵핑 요소가 너무 많습니다. 엑셀로 비유하자면 사용자 입력값(A열)을 모델이 사용하는 클래스(B열)로 재분류하기 위해 A-B열을 매칭할 수 있는 인덱스 맵핑 테이블을 만들어두고 VLOOKUP을 사용할텐데요, A열에 들어가는 경우의 수가 B열 대비 너무 많은 것입니다. 예를 들어 B열에 표준으로 입력된 Obstetrics and Gynaecology(산부인과)는 A열에 사용자 언어로 Obs and Gynae, OB and GYN, O&G 등 약어가 포함되고 and를 기호 &로 바꿔쓰는 경우가 발생합니다. 표준과 다른 입력어를 처리하기 위해 기본적으로는 대소문자 변환 및 띄어쓰기 부분을 함수화하였는데도 regex로 넘기기 어려운 각종 텍스트 프로레싱 사례가 계속해서 발생하는 문제가 있는걸 짐작할 수 있으실 겁니다. (글또 8기에 관련 질문을 올렸던 내용도 있는데 오랜 시간이 지나 히스토리 락이 걸렸네요)

 

 

 

기존 방식은 데이터 과학자 혹은 분석가들이 필요한 모델을 구현할 때마다 스스로 전처리를 하는 '매뉴얼' 방식으로 상당 공수를 차지하였습니다. 자동화된 시스템보다 개인 역량에 영향을 많이 받는 부분으로 고착되어 있었습니다. 아무래도 관련 프로젝트 근무 경험도에 따라 지난 문제 히스토리를 알게 되기도 하고, 가장 많이 들어오는 사용자 인풋에 대한 매핑 파일을 이미 구축해둔 상태기 때문입니다. 예를 들어 {'Obstetrics and Gynaecology' : {'Obs and Gynae', 'OB and GYN', 'O&G'}} 같은 식으로 말입니다. 여기서 가장 문제가 되는 부분은 첫번째 하우스룰이 부재하면서 데이터 웨어하우스에 쌓이는 데이터들은 계속해서 raw data가 적재되고 모델링 nlp 처리규칙을 벗어나는 데이터축적을 감지할 수 없는 부분입니다. 두번째로 지속적으로 업데이트 되는 비지니스 상황에 따라 담당 인원이 추가 맵핑 세칙을 만들곤 하는데 이것이 기존 (매뉴얼 전처리작업에 바탕을 둔) 모델들에 동기화 반영이 어렵다는 점입니다. 예를 들어 산부인과 정책 중에는 산과만 해당하는 부분이 있고 반대로 부인과에만 해당하게 되는 내용들이 있습니다. Obstetrics and Gynaecology 안에서 Obstetrics만 별도 컨트롤 해야 하는 부분은 통상적인 Midwifery들의 루틴 업무를 포함하고 Gynaecology는 부인건강을 전문적으로 보는 Gynecologists가 플러그인 되어야 하는 등입니다.

 

 

 

"일로만 채워지는 성취욕이 있는 것 같아요 ... 일할 때가 제일 저 스스로를 건강하게 굴릴 수 있는 것 같기도 해요. 해야 할 목적이 있으면 거기에 맞춰서 저를 가꾸기도 하고 ... 지칠 때? 계획해 둔 게 많은데 시간이 없을 때, 그런데 나는 그 계획을 다 이루고 싶고 능력이 안될 때 이럴 때 저는 지치는 거 같아요 (아이유, "겨울나기는 핑계고 | EP.38")

https://youtu.be/nVXNlMInalo?si=2Cuu83jf_4yFAkBH&t=3167

 

 

기술 부채라고 하기도 애매했던 것이, 본 문제는 동일 문제가 발생하는 모든 관련 프로젝트 전체를 아울러 보는 리더가 없었기 때문에 문제인지 자체가 안되어 있었습니다. 그런데 제가 음, 1년차 때 일을 좀 잘했어요. 그래서 여러 팀섹션/사람에게 흩어져 있던 관련 모델링 부분들이 결국 저에게로 통하게끔 되었습니다. 당연히 제가 모르던 일들을 더 배우고 medical에 한정 되어 있던 메인 도메인을 dental 및 다른 clinical professions들에게까지 확장하면서 오너십을 점점 가져오다 보니 그제서야 문제 사이즈가 이쯤 보이게 되었습니다. 다음 두번째 문제로는 작은 프로젝트 하나에서 20%를 차지하던 전처리 과정이 4-5번씩 개별 모델마다 반복되는 걸 경험하면서 (혼자에게는) 큰 일이 되고 그마저도 각각 결과 동기화는 또 제가 알아서 개별적으로 해줘야 하니 '유지보수'에만 공수가 너무 커지는 겁니다. 정말 필요한 '모델 개선'은 점차 뒷전이 되구요. 그래서 이를 해결해야겠다 야심차게 마음먹고 input text processing 개선 계획을 세웠음에도 (지금의 제가) 실행 능력이 부족하다는 한계만 번번히 인정하고 넘어간 1년이었니다.

 

 

 

프로젝트 근속 2년차가 되며 가장 우선적으로 해결하려 별도 집중 시간을 뺀 결과, 우선 급한대로 엑셀로 데이터 콜렉션으로 넘겨주는 엔트리들에게 드롭박스를 지정해주고 반드시 주어진 포맷 안에서만 입력하도록 업무 프로토콜을 업데이트 할 수 있었습니다. 기존 데이터들과 연계해야 하고 엔트리 포인트들에서 운영 또한 온전하게 제가 바란대로 실행되진 않겠지만 ... 아쉬운대로 2024년부터 새로 입력되는 데이터들은 DB관리 관점에서 적정 표준을 따르게끔 설정해둔 것으로 만족합니다. 다음 두번째는 모델링 팀에서 모두가 단일화된 인풋 표준을 쓰게끔 하는 부분입니다. GUI 구현을 하여 모델러들 입력 자체를 주어진 값 안에서만 선택할 수 있게 제한하자는 아이디어에 도달하게 됩니다. 부서 내 tkinter로 app 개발을 한 동료가 있어서 보일러 플레이트를 받아올 수 있었습니다.

 

 

 

#GUI in Python

import tkinter

def GUI():
    root = tkinter.Tk()
    # gui params
    root.title('Behaviours App')
    root.geometry("500x500")

    # funcs
    def StartApp():
        global filtering_specialty
        global plot_number
        global filtering_gender
        global filtering_ethnicity
        global filtering_nationality
        global filename

        filtering_specialty = filtering_specialty_input.get()
        plot_number = plot_number_input.get()
        filtering_gender = filtering_gender_input.get()
        filtering_ethnicity = filtering_ethnicity_input.get()
        filtering_nationality = filtering_nationality_input.get()
        filename = filename_input.get()

    # (중간생략)

    # ---------- user inputs ----------
    # enter filtering_specialty
    tkinter.Label(root, text="====================").pack()
    filtering_specialty_input = tkinter.StringVar(root)
    tkinter.Label(root, text="Enter Filtering Specialty:").pack()
    tkinter.Entry(root, textvariable=filtering_specialty_input).pack()
    # (이하 반복생략)

    window.mainloop()
 

 

 

 

위 포멧 코드를 활용하여 MVP를 빠르게 구현한 결과는 아래 스크린 캡쳐입니다. 제가 변환해야 했던 건 동료가 설정한 인풋 스트링 부분을 드롭박스로 바꾸는 부분이었습니다. (저는 사용자가 마음대로 입력할 여지가 너무 큰 걸 해결하고 싶으므로 입력 옵션을 주어진 값 안에서만 선택하도록 제한해야 하니까요) 당연히 드롭박스 선택으로 들어갈 부분 정보는 별도 컨피그로 넣어두었구요.

 

 

 

 

위에서 거기에 최소한의 테마를 더하기 위해 ttk를 추가합니다. 제 동료 또한 이전에 최소 기능으로만 작업을 했던 거라 디자인은 전혀 신경쓰지 않은 app을 조금 개선할 여지가 있었습니다.

import tkinter as tk
from tkinter import ttk

def show():
    '''
    Collect the selections
    '''
    ttk.Label(results_frame, text="Allocations Model: " + droplist_model.get()).pack()
    # (이하 반복생략)

# GUI window settings
window = tk.Tk()
window.title('Run - Allocations Model')
window.geometry('550x550')

# Load input options from configs - dropdown boxes
droplist_model = tk.StringVar()
droplist_model.set('Which Allocations Model?')
menu_model = tk.OptionMenu(window, droplist_model, *model_groups)
menu_model.pack()
# (이하 반복생략)

window.mainloop()
 

 

 

추가로 드롭박스에서 콤보박스로 피쳐를 변환하고 이벤트를 케이스를 추가하여 결과값을 저장, 추출 후 후반부 모델링으로 연계할 수 있게끔 기능 구현합니다.

def extract():
    '''
    Collect the selections
    '''
    model = string_model.get()
    # (이하 반복생략)
    return model, region, aggregated_group, professional_group, fund, spread, method, scenario, year

# Create a title widget
label_title = ttk.Label(window, text='Select Your Model Inputs', font='Arial 18 bold')
label_title.pack(pady=15)


# Configure the selections
'''
comboboxes for selecting an input from each dropdown list of modelling options: 커멘트 디테일 생략
'''
input_frame1 = ttk.Frame(window)
string_model = tk.StringVar(value = 'Allocations Model?')
combo_model = ttk.Combobox(input_frame1, textvariable=string_model)
combo_model['values'] = model_groups
combo_model.pack(side='left', padx=10)
combo_model.bind('<<ComboboxSelected>>', lambda event: label_model.config(text=f'Selected model: {string_model.get()}'))
label_model = ttk.Label(input_frame1, text='Modelling')
label_model.pack(side='left')
input_frame1.pack(pady=10)

# (이하 반복생략)

window.mainloop()
 

 

 

이렇게으로 초기 MVP를 디벨롭한 결과는 아래 스크린 캡쳐입니다.

 

 

해당 내용은 보일러플레이트 코드블락들을 (기꺼이) 저에게 공유해준 동료에게 당연히 돌려주었어요.

 

 

이렇게 Stage 1 GUI 작성을 마치고 저는 Stage 2 메인 코드 수정 작업으로 넘어온 상태입니다. tkinter 콤보박스에서 겟한 이벤트들을 추출하는 것까지 성공한 덕분에 메인 코드에 (기존에는 각자가 가진 외부 파일로) 로드하던 맵핑 프로세스들을 모두 바꿔야 합니다. 이 부분까지 완료되면 상당히 의미있는 성과로 기록될 거 같단 기대를 하면서 열심히 하고 있습니다. 이러한 노-력을 좀 더 일찍부터 더 많이 할 수도 있었는데 말입니다, 능력이 안되고 지쳤던 과정을 아이유님의 말을 빌려 변명합니다: "계획해 둔 게 많은데 시간이 없을 때, 그런데 나는 그 계획을 다 이루고 싶고 능력이 안될 때 이럴 때 저는 지치는 거 같아요" . 무엇보다도 아직 할일이 몹시 많이 남은 상태라 이번 한 해동안 글또 9기-10기까지 도중에 자체목표 달성을 했다는 소식을 전할 수 있게 부지런해보겠습니다.

 

 

 

+

오늘은 글또 제출 마감일입니다. 글또 9기에서 데이터 과학자의 글쓰기 티스토리로 발행하고 있던 중 금방 고쳐질 줄 알았던 접속에러가 너무 오래 지속되어서요. 기술요소가 많은 부분은 티블로 올리자 정했지만 ... 오류는 나아질 기미가 보이지 않고 드레프트로 따로 백업해 둔 내용을 네이버 블로그로 대신 발행하게 되었습니다. 추후 이 글은 티스토리로 옮겨질 수 있습니다!  옮겨왔습니다.

 

 

반응형