반응형
1. 회원사 - 참여자 자동매칭 프로그램 (Python) 개요
이 코드는 “참여자가 면접을 희망하는하는 회원사” 와 “회원사가 면접을 원하는 참여자” 정보를 바탕으로,
정해진 시간대와 10분 단위 슬롯(시간칸)에 맞춰 면접 매칭 테이블을 자동으로 생성합니다.
- 참여자-회사 간 우선순위 점수(예: 1지망=5점, 2지망=4점 등)를 계산
- 양쪽(참여자, 회사) 모두 원하는 매칭일수록 높은 점수가 되어 먼저 매칭
- 시간대가 겹치지 않도록(동일 시간대에 한 참여자가 두 회사를 면접 못 하도록) 배정
- 결과를 엑셀 파일(
매칭결과.xlsx
)로 저장
이 코드를 실행하면 다음과 같은 단계를 거칩니다.
- 엑셀 파일 선택:
- “참여자→회원사” 희망 순위 엑셀 파일
- “회원사→참여자” 희망 순위 엑셀 파일
- 데이터 로딩 & 전처리
- 매칭 알고리즘 수행
- 결과 엑셀 생성 & 저장
2. 주요 로직 개요
(A) 참여자-회원사 우선순위 점수
- 참여자가 1순위(1지망)로 고른 회사면 5점, 2순위면 4점, … 5순위면 1점
- 회사가 1순위(1지망)로 고른 참여자면 5점, 2순위면 4점, … 5순위면 1점
- “참여자 우선순위 점수” + “회사 우선순위 점수”의 합으로 매칭 우선도를 정함
- 예: 어떤 참여자가 그 회사를 1순위(5점), 회사도 그 참여자를 2순위(4점)라 했다면, 합은 9점
(B) 시간대와 서브슬롯
- 프로그램 안에는 아래처럼 시간표(time_table)가 정의되어 있습니다.
time_table = { "09:00-10:00": ["도우", "디스코", "루시드프로모", "마루프런티어", "미도리얼코"], "10:00-11:00": ["건물과사람들", "국진", "더큐브컴퍼니", "더피알커뮤니케이션", "태복플래닝"], ... }
- 예를 들어 “09:00-10:00” 에는 5개 회사(도우, 디스코, 루시드프로모, 마루프런티어, 미도리얼코)가 면접을 진행.
- 각 시간대에 10분 간격으로 0, 10, 20, 30, 40, 50 총 6개의 슬롯을 둡니다.
- 따라서 한 회사는 1시간 동안 최대 6명의 지원자를 면접 가능.
(C) 매칭 순서
- 모든 (참여자, 회원사) 쌍에 대해 우선순위 합계를 계산해 리스트에 담는다.
- 그 리스트를 점수가 높은 순(내림차순)으로 정렬.
- 높은 점수 쌍부터 차례대로
- 그 회사가 속한 시간대에서 빈 슬롯(그리고 참여자가 그 시간대에 다른 면접이 없는 슬롯)을 찾는다.
- 있으면 배정하고, 없으면(슬롯이 다 찼으면) 패스.
- 최종 매칭 결과를 엑셀로 저장.
3. 코드 한 줄씩 이해하기
아래는 코드 전체를 구조 별로 나눈 뒤 간단한 주석과 함께 설명합니다.
3-1. 모듈 임포트
import pandas as pd
import tkinter as tk
from tkinter import filedialog
- pandas: 엑셀 파일을 쉽게 읽고 쓰기 위한 라이브러리
- tkinter: 파이썬 기본 GUI 라이브러리 (파일 선택 창을 띄우기 위해 사용)
3-2. 엑셀 파일을 선택하는 함수
def load_excel_file(title="엑셀 파일을 선택하세요"):
"""엑셀 파일을 불러오는 간단한 함수"""
root = tk.Tk()
root.withdraw()
file_path = filedialog.askopenfilename(
title=title,
filetypes=[("Excel files", "*.xlsx *.xls")]
)
root.destroy()
return file_path
tk.Tk()
→ tkinter 윈도우 생성root.withdraw()
→ 보이지 않도록(숨김) 설정filedialog.askopenfilename(...)
→ 파일 선택 대화창 열기title
: 창 제목filetypes
: 확장자 필터 (여기서는 .xlsx, .xls)
root.destroy()
→ 사용 끝났으므로 창 닫기- 최종적으로 선택된 파일 경로(
file_path
)를 반환.
이 함수:
- “어떤 파일을 열고 싶나요?” 같은 안내 창을 띄우고,
- 사용자가 직접 엑셀 파일을 선택하면 그 경로를 받아옴.
3-3. main()
함수
이 프로그램의 중심 함수입니다.
맨 아래의
if __name__ == "__main__":
main()
를 통해 스크립트를 직접 실행할 때 main()
가 호출됩니다.
3-3-1) 엑셀 파일 불러오기 (
print("1) 참여자 희망기업 엑셀을 선택하세요. (열 제목 없이, 첫 줄부터 데이터인 파일)")
participant_file = load_excel_file("참여자 -> 회원사 희망 순위 엑셀을 선택")
if not participant_file:
print("파일이 선택되지 않았습니다. 종료합니다.")
return
- 참여자 희망기업 엑셀 파일을 먼저 선택.
- 만약 취소 등을 해서
participant_file
경로가 비었다면, 프로그램을 종료.
print("2) 회원사 희망참여자 엑셀을 선택하세요. (열 제목 없이, 첫 줄부터 데이터인 파일)")
company_file = load_excel_file("회원사 -> 참여자 희망 순위 엑셀을 선택")
if not company_file:
print("파일이 선택되지 않았습니다. 종료합니다.")
return
- 다음으로 회원사 희망참여자 엑셀 파일을 선택.
3-3-2) 엑셀 읽기
df_participant = pd.read_excel(
participant_file,
header=None,
names=["이름","1지망","2지망","3지망","4지망","5지망"],
dtype=str
)
df_company = pd.read_excel(
company_file,
header=None,
names=["회사명","1지망","2지망","3지망","4지망","5지망"],
dtype=str
)
pandas.read_excel()
함수를 이용해 엑셀 파일을 DataFrame 형태로 불러옵니다.header=None
→ 엑셀에 별도의 컬럼 제목 행이 없다고 가정.
(맨 윗줄부터 실제 데이터가 들어있다고 보는 것)names=[...]
→ 우리가 직접 6개의 열 이름을 붙여줌.
(A열=이름, B열=1지망, … F열=5지망)dtype=str
→ 모든 값을 문자열로 읽음(숫자, 날짜가 섞여 있어도 에러 방지).
df_participant.dropna(how='all', inplace=True)
df_company.dropna(how='all', inplace=True)
- 모든 칸이 비어있는 행(결측치만 있는 행) 은 제거.
3-3-3) 시간표 설정
time_table = {
"09:00-10:00": ["도우", "디스코", "루시드프로모", "마루프런티어", "미도리얼코"],
"10:00-11:00": ["건물과사람들", "국진", "더큐브컴퍼니", "더피알커뮤니케이션", "태복플래닝"],
"11:00-12:00": ["씨엘케이", "애드파워", "에이치와이마케팅그룹", "와이낫플래닝", "콘텐츠 민주주의"],
"12:00-13:00": ["상림디엠텍", "유성", "신림피앤디", "쓰리에스씨앤에프", "씨앤디플래닝"],
"13:00-14:00": [], # 점심 시간 (면접 없음)
"15:00-16:00": ["유당디앤씨", "세보", "데이터노우즈", "한국자산매입", "홈스페이"]
}
sub_slots = [0, 10, 20, 30, 40, 50]
time_table
:- 키(key) = 시간 구간 (예:
"09:00-10:00"
) - 값(value) = 그 시간대에 면접을 보는 5개 회사 이름(리스트)
- 키(key) = 시간 구간 (예:
sub_slots
: 한 시간에 0,10,20,30,40,50 분 시작하는 6개의 면접 슬롯을 의미.
3-3-4) 참여자 우선순위, 회원사 우선순위 정리
participant_pref = {}
for idx, row in df_participant.iterrows():
name = row["이름"]
if pd.isna(name):
continue
name = name.strip()
if not name:
continue
participant_pref[name] = {}
for i in range(1,6):
comp = row[f"{i}지망"]
if pd.isna(comp):
continue
comp = comp.strip()
if not comp:
continue
score = 6 - i # (i=1 → 5점, i=2 → 4점 ...)
participant_pref[name][comp] = score
df_participant.iterrows()
→ 참여자 엑셀의 각 행(row)을 순회.row["이름"]
→ 이 행의 “이름” 열 값 (참여자 이름).row["1지망"] ~ row["5지망"]
→ 1순위 ~ 5순위 회사명.- 순위 i에 대해 점수는
6 - i
. (1 → 5점, 2 → 4점, 5 → 1점)
- 순위 i에 대해 점수는
- 이렇게 해서
participant_pref
딕셔너리에participant_pref["참여자이름"] = { "회사A": 점수, "회사B": 점수, ... }
형태로 저장.
company_pref = {}
for idx, row in df_company.iterrows():
comp_name = row["회사명"]
...
company_pref[comp_name] = {}
...
company_pref[comp_name][p_name] = score
- 마찬가지로 회원사 엑셀을 돌며,
회사가 1지망, 2지망으로 원하는 참여자 목록을 점수화해 저장.company_pref["회사명"] = { "참여자이름": 점수, ... }
3-3-5) 회원사가 어느 시간대에 속하는지 매핑
company_to_time = {}
for tslot, clist in time_table.items():
for c in clist:
company_to_time[c] = tslot
- 예:
company_to_time["도우"] = "09:00-10:00"
company_to_time["디스코"] = "09:00-10:00"
- 등등.
3-3-6) (참여자, 회원사) 쌍별 점수 계산 & 리스트화
all_participants = list(participant_pref.keys())
all_companies = list(company_pref.keys())
pair_list = []
for p in all_participants:
for c in all_companies:
p_score = participant_pref[p].get(c, 0)
c_score = company_pref[c].get(p, 0) if c in company_pref else 0
total_score = p_score + c_score
if total_score > 0 and (c in company_to_time):
pair_list.append((total_score, p, c))
- 모든 참여자
p
와 모든 회사c
에 대해 “참여자가 c를 원하는 점수” + “회사 c가 p를 원하는 점수” =total_score
. - 이 점수가 0보다 크고, 해당 회사가
time_table
에 존재한다면(즉 면접이 있는 회사라면), 리스트에 추가.
pair_list.sort(key=lambda x: x[0], reverse=True)
(점수, 참여자, 회사)
형태의 튜플을 점수 기준으로 내림차순 정렬.
3-3-7) 매칭 구조 준비
matches = {}
participant_busy = {}
for tslot in time_table.keys():
matches[tslot] = {}
for c in time_table[tslot]:
matches[tslot][c] = []
for p in all_participants:
participant_busy[p] = {}
for tslot in time_table.keys():
participant_busy[p][tslot] = set()
matches[시간대][회사] = [(슬롯번호, 참여자이름), ...]
형태.participant_busy[참여자][시간대] = {이미 배정된 슬롯번호들}
- 한 시간대에 한 참여자는 두 면접을 동시에 볼 수 없으므로, 슬롯이 겹치지 않도록 추적.
3-3-8) 매칭 로직
for total_score, p, c in pair_list:
tslot = company_to_time[c]
# 1) 회사 c가 이미 6명 배정됐다면 넘어감
if len(matches[tslot][c]) >= len(sub_slots):
continue
used_by_p = participant_busy[p][tslot]
used_by_c = [slot for (slot, _) in matches[tslot][c]]
...
for s in sub_slots:
if (s not in used_by_p) and (s not in used_by_c):
available_slot = s
break
if available_slot is not None:
matches[tslot][c].append((available_slot, p))
participant_busy[p][tslot].add(available_slot)
- 점수가 높은 쌍부터 순회
- 그 회사가 속한 시간대(
tslot
)에서,- 회사가 이미 6명 배정됐는지 체크(슬롯=6개)
- 참여자가 이미 다른 회사와 같은 슬롯을 쓰는지 체크
- 가능한 첫 슬롯(
available_slot
)을 찾으면, 거기에 배정 - 배정 후엔
participant_busy[p][tslot]
에 그 슬롯을 기록.
이 과정을 거치면, 우선순위가 높은 (참여자, 회사) 조합부터 차곡차곡 매칭이 이뤄집니다.
3-3-9) 결과 만들기 & 엑셀 저장
result_rows = []
for tslot, comp_dict in matches.items():
for c, assigned_list in comp_dict.items():
for (s, p) in assigned_list:
result_rows.append({
"시간대": tslot,
"회사명": c,
"서브슬롯(분)": s,
"참여자": p
})
result_df = pd.DataFrame(result_rows)
result_df = result_df.sort_values(by=["시간대","서브슬롯(분)"])
output_file = "매칭결과.xlsx"
result_df.to_excel(output_file, index=False)
print(f"매칭 결과가 '{output_file}'로 저장되었습니다.")
matches
딕셔너리에 쌓인 정보를 순회하며,
“시간대, 회사명, 서브슬롯, 참여자” 형태로 리스트 생성.pandas.DataFrame(...)
로 묶어주고, “시간대→서브슬롯(분)” 순으로 정렬.to_excel(...)
으로 저장.
이로써 최종 “시간대/회사/슬롯별 누가 면접 보나” 가
매칭결과.xlsx
파일에 나타납니다.
4. 사용된 파이썬 함수
아래는 위 코드에서 사용된 함수들을 간단히 정리한 표입니다.
함수(메서드) | 역할 및 설명 |
---|---|
load_excel_file(title) |
tkinter로 “파일 열기” 대화창을 띄워서 사용자가 엑셀 파일을 선택하도록 함. 선택된 파일 경로를 리턴 |
pd.read_excel(...) |
pandas의 엑셀 파일 읽기 함수. DataFrame 형태로 만들어줌 |
DataFrame.dropna(...) |
결측치(빈 값) 제거. how='all' 이면 “해당 행의 모든 값이 NaN일 때” 제거 |
DataFrame.iterrows() |
DataFrame의 각 행(row)을 순회할 때 사용 |
string.strip() |
문자열 양쪽 공백 제거 |
sort_values(...) |
pandas DataFrame을 특정 컬럼 기준으로 정렬 |
to_excel(...) |
pandas DataFrame을 엑셀 파일로 저장 |
tkinter.Tk() , destroy() |
tkinter 윈도우를 열고 닫는 메서드 |
filedialog.askopenfilename |
파일 열기 대화창을 띄우는 함수 |
5. 실행
- 파이썬 환경에서(예: Anaconda Prompt, 혹은 Visual Studio Code 등), 이 스크립트(
매칭데이.py
예시)를 실행합니다. - 1) 참여자 희망기업 엑셀 파일을 선택 → 열어서 로딩
- 2) 회원사 희망참여자 엑셀 파일을 선택 → 열어서 로딩
- 자동으로 매칭 로직이 실행되어, 최종적으로 “매칭결과.xlsx” 파일이 생성됩니다.
- 같은 폴더(또는 실행한 경로)에 저장됨
- 매칭결과.xlsx를 열어보면,
시간대별로(예:09:00-10:00
),회사명
,서브슬롯(분)
,참여자
정보가 담겨 있음.
6. 결론 및 요약
- 이 프로그램은 “참여자→회사, 회사→참여자” 각각 최대 5순위까지의 희망 정보를 읽어,
서로 원하는 정도에 따라 점수를 매기고,
시간과 슬롯(10분 단위)을 겹치지 않게 매칭시키는 자동화 툴입니다. - 핵심 구조:
1) 우선순위 점수 합 계산
2) 높은 점수부터 빈 슬롯을 배정
3) 결과를 엑셀로 저장
반응형
'인공지능과 오토메이션 > Automation' 카테고리의 다른 글
매력일자리 보강 관련 사전안내 - 공공데이터포털 API 신청 (0) | 2025.05.17 |
---|---|
클로드 MCP 활용한 AI 에이전트 (0) | 2025.04.27 |
메타인지 프로젝트: AI 어시스트턴트 (0) | 2025.04.20 |
AD-SAIZ #2 : 메타인지 프로젝트 (간단버전) (0) | 2025.04.20 |
🎓 한국부동산마케팅협회 AI 부트캠프 멤버십 프로그램 (0) | 2025.04.09 |