오타점수/부분합 엑셀 시트에 적용

This commit is contained in:
devdra9
2025-01-20 17:56:46 +09:00
parent d69a2a331e
commit c3b97cc9fd
4 changed files with 65 additions and 31 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
_old_excel_files/
output/
input/
*.xlsx

View File

@@ -1532,3 +1532,11 @@
2025-01-18 17:33:15,690 - INFO - 변환 성공: 워드(한글)-005686-홍유하.hwp -> 워드(한글)-005686-홍유하.hml
2025-01-18 17:33:15,916 - INFO - 변환 성공: 워드(한글)-005687-강태원.hwp -> 워드(한글)-005687-강태원.hml
2025-01-18 17:33:16,364 - INFO - 변환 성공: 워드(한글)-005688-정지예.hwp -> 워드(한글)-005688-정지예.hml
2025-01-20 14:32:03,574 - INFO - 변환 성공: 워드(한글)-005172-김서인.hwp -> 워드(한글)-005172-김서인.hml
2025-01-20 14:32:03,980 - INFO - 변환 성공: 워드(한글)-005174-지율.hwp -> 워드(한글)-005174-지율.hml
2025-01-20 14:32:04,227 - INFO - 변환 성공: 워드(한글)-005175-문지환.hwp -> 워드(한글)-005175-문지환.hml
2025-01-20 14:32:04,561 - INFO - 변환 성공: 워드(한글)-005176-이세영.hwp -> 워드(한글)-005176-이세영.hml
2025-01-20 14:32:04,881 - INFO - 변환 성공: 워드(한글)-005177-김은유.hwp -> 워드(한글)-005177-김은유.hml
2025-01-20 14:32:05,103 - INFO - 변환 성공: 워드(한글)-005179-손민준.hwp -> 워드(한글)-005179-손민준.hml
2025-01-20 14:32:05,346 - INFO - 변환 성공: 워드(한글)-005180-도정원.hwp -> 워드(한글)-005180-도정원.hml
2025-01-20 14:32:07,797 - INFO - 변환 성공: 정답.hwp -> 정답.hml

View File

@@ -16,6 +16,12 @@ class XMLScorer:
# 채점 기준 로드
self.scoring_criteria = self._load_scoring_criteria(scoring_criteria_path)
def set_typo_score(self, score):
self.typo_score = score
def get_typo_score(self):
return self.typo_score
# 채점 기준파일 로드(JSON 파일)
def _load_scoring_criteria(self, file_path):
with open(file_path, 'r', encoding='utf-8') as f:
@@ -37,9 +43,7 @@ class XMLScorer:
return result
else:
return result
# result = root.xpath(second_xpath)
# print(f'result : {result}')
# return result
except ET.XPathEvalError as e:
return None
else:
@@ -141,6 +145,7 @@ class XMLScorer:
previous_first_digit = first_digit
id = criterion_id
xpath = criterion['path']
xpath2 = criterion['path2']
search_value = criterion['searchValue']
@@ -191,15 +196,18 @@ class XMLScorer:
else:
actual_answer = result[0]
if "오타감점" in category:
points = self.get_typo_score()
scoring = {
'id': id,
'category': category, # 채점 분류
'item': item, # 채점 항목
'right_answer': right_answer, # 정답
'actual_answer': actual_answer, # 실제 작성 답안
'points': 0,
'points': points,
'deductions': [] # 각 기준별 감점 내역
}
scoring['points'] = points
# 점수 차감 조건
# 1. 정답이 실수형으로 반환받은 경우는 채점항목의 부분점수 합산 결과이므로
@@ -210,8 +218,8 @@ class XMLScorer:
scoring['points'] = actual_answer
elif type(actual_answer) is int:
# 오차범위 5 이상이면 감점
if abs(actual_answer - right_answer) > 5:
# 오차범위 3 이상이면 감점
if abs(actual_answer - right_answer) > 3:
scoring['points'] -= points
else:
# right_answer(JSON파일 내 valuer값) null일 경우 점수감점 없이 진행
@@ -244,8 +252,6 @@ class XMLScorer:
}
def binary_to_chartxml(self, xml_path):
print(f'binary_to_chartxml {xml_path}')
tree = ET.parse(xml_path)
root = tree.getroot()
@@ -339,24 +345,25 @@ class XMLScorer:
# result_diff 배열의 길이를 맨 앞에 저장
temp = 40 - min(len(result_diff)*2, 40)
self.set_typo_score(temp)
result_diff.insert(0, temp)
return result_diff
# XML 파일 채점
def score_directory(self, xml_directory, answer_path):
# xml 파일 불러오기
xml_files = Path(xml_directory).glob('*.hml')
# 결과 저장할 리스트
results = []
for xml_file in xml_files:
result = {}
chart_xml = self.binary_to_chartxml(xml_file)
result['score'] = self._score_xml_file(xml_file, chart_xml)
result['typo'] = self.typo_check(answer_path, xml_file)
result['score'] = self._score_xml_file(xml_file, chart_xml)
# result['score']['score_results'][2]['points'] = result['typo'][0]
results.append(result)
return results
@@ -368,6 +375,7 @@ class XMLScorer:
number = match.group(1)
name = match.group(2)
return number, name
return None, None
def export_to_excel(self, results, output_path=None):
@@ -400,29 +408,46 @@ class XMLScorer:
else:
detail_row = {'채점항목':f"{number}-{name}"}
for i, scoring in enumerate(result['score_results']):
# detail_row[scoring['item']] = scoring['points']
detail_row[f'{i+1}'] = scoring['points']
section_num = None
partial_idx = 0
for i, score_result in enumerate(result['score_results']):
current_section = int(score_result['id'].split('-')[0])
if section_num is None:
section_num = current_section
if current_section != section_num:
# 이전 섹션의 부분합을 출력
detail_row[f'[{section_num}]합계'] = result['partial_scores'][partial_idx]['score']
partial_idx += 1
section_num = current_section
detail_row[f'{i+1}'] = score_result['points']
# 마지막 섹션의 부분합을 출력
if section_num is not None and partial_idx < len(result['partial_scores']):
detail_row[f'[{section_num}]합계'] = result['partial_scores'][partial_idx]['score']
detail_row['총점'] = result.get('total_score', 0)
detail_data.append(detail_row)
summary_df = pd.DataFrame(summary_data)
detail_df = pd.DataFrame(detail_data).transpose()
# detail_df = pd.DataFrame(detail_data)
for temp in results:
result = temp['typo']
typo_data.append(result)
type_df = pd.DataFrame(typo_data).transpose()
typo_df = pd.DataFrame(typo_data).transpose()
# detail_df = pd.DataFrame(detail_data)
# detail_df.iloc[3] = typo_df.iloc[0]
# ExcelWriter 객체 생성
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
summary_df.to_excel(writer, sheet_name='채점결과요약', index=False)
detail_df.to_excel(writer, sheet_name='채점상세내역', index=False)
type_df.to_excel(writer, sheet_name='오타내역', index=False)
typo_df.to_excel(writer, sheet_name='오타내역', index=False)
# 열 너비 자동 조정
# for sheet_name in writer.sheets:

View File

@@ -1,5 +1,5 @@
{
"0-1":{
"0-01":{
"path":"boolean(//PAGEMARGIN[(@Bottom='5668'or @Bottom='5669') and (@Footer='2834' or @Footer='2835') and @Gutter='0' and (@Header='2834' or @Header='2835') and (@Left='5668' or @Left='5669') and (@Right='5668' or @Right='5669') and (@Top='5668' or @Top='5669')])",
"path2": null,
"searchValue": null,
@@ -8,7 +8,7 @@
"category": "용지설정",
"item": "A4용지, 왼쪽/오른쪽/위쪽/아래쪽 (각20mm), 머리말/꼬리말 (10mm), 제본(0mm)"
},
"0-2":{
"0-02":{
"path":"boolean(//FONTFACE[@Lang='Hangul']/FONT[@Id=//CHARSHAPE/FONTID/@Hangul]/@Name='바탕' and //CHARSHAPE/@Height='1000' and //PARASHAPE/PARAMARGIN/@LineSpacing='160' and //PARASHAPE/@Align='Justify')",
"path2": null,
"searchValue": null,
@@ -17,7 +17,7 @@
"category": "기본설정",
"item": "글꼴 (바탕, 10pt), 양쪽정렬, 줄간격 (160%)"
},
"0-3":{
"0-03":{
"path":"",
"path2": null,
"searchValue": null,
@@ -26,7 +26,7 @@
"category": "오타감점",
"item": "오타 1개 -2점"
},
"1-1":{
"1-01":{
"path": "//TEXTART[@Text='{searchValue}']/TEXTARTSHAPE/@FontName",
"path2": null,
"searchValue": "전통주페어링특강안내",
@@ -35,7 +35,7 @@
"category": "글맵시",
"item":"문구 (전통주페어링특강안내)/① 글씨체 : 휴먼옛체"
},
"1-2": {
"1-02": {
"path": "//TEXTART[@Text='{searchValue}']/descendant::WINDOWBRUSH/@FaceColor",
"path2": null,
"searchValue": "전통주페어링특강안내",
@@ -44,7 +44,7 @@
"category": "글맵시",
"item":"문구 (전통주페어링특강안내)/② 채우기 : 색상(RGB:28,145,110)"
},
"1-3": {
"1-03": {
"path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Width",
"path2": null,
"searchValue": "전통주페어링특강안내",
@@ -53,7 +53,7 @@
"category": "글맵시",
"item":"문구 (전통주페어링특강안내)/③ 크기 : 너비(80mm)"
},
"1-4": {
"1-04": {
"path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Height",
"path2": null,
"searchValue": "전통주페어링특강안내",
@@ -62,7 +62,7 @@
"category": "글맵시",
"item":"문구 (전통주페어링특강안내)/④ 크기 : 높이(20mm)"
},
"1-5": {
"1-05": {
"path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/POSITION/@TreatAsChar",
"path2": null,
"searchValue": "전통주페어링특강안내",
@@ -71,7 +71,7 @@
"category": "글맵시",
"item":"문구 (전통주페어링특강안내)/⑤ 위치 (글자처럼 취급)"
},
"1-6": {
"1-06": {
"path": "//PARASHAPE[@Id=//TEXTART[@Text='{searchValue}']/ancestor::P/@ParaShape]/@Align",
"path2": null,
"searchValue": "전통주페어링특강안내",
@@ -80,7 +80,7 @@
"category": "글맵시",
"item":"문구 (전통주페어링특강안내)/⑥ 정렬 (가운데 정렬)"
},
"1-7":{
"1-07":{
"path": "",
"path2": null,
"searchValue": "전통주페어링특강안내",
@@ -89,7 +89,7 @@
"category": "글맵시",
"item":"문구 (전통주페어링특강안내)/⑦ 글맵시모양 (육안확인)"
},
"1-8": {
"1-08": {
"path": "boolean(//CHARSHAPE[@Id=//CHAR[contains(text()[1],'{searchValue}')]/parent::TEXT/@CharShape][BOLD])",
"path2": null,
"searchValue": "혼술, 홈술, 집술",
@@ -98,7 +98,7 @@
"category": "글꼴속성",
"item":"문구 (혼술, 홈술, 집술)/진하게"
},
"1-9": {
"1-09": {
"path": "boolean(//CHARSHAPE[@Id=//CHAR[contains(text()[1],'{searchValue}')]/parent::TEXT/@CharShape][UNDERLINE])",
"path2": null,
"searchValue": "혼술, 홈술, 집술",