XLSX 생성, 편집 및 분석
| 작업 | 접근 방식 |
|---|---|
| 공식/서식 포함 생성 또는 편집 | openpyxl — 아래 주의사항 참고 |
| 대량 데이터 입출력 | pandas (read_excel, to_excel) |
| 시트 빠른 확인 | markitdown file.xlsx — 시트당 ## SheetName; .xlsm도 읽음. 셀 좌표는 없으므로 이를 기준으로 편집 계획 수립 금지 |
| 모델 읽기 (공식 및 값) | 두 번의 load_workbook 패스 — 아래 주의사항 참고 |
openpyxl,pandas,markitdown은 사전 설치되어 있습니다 — 먼저pip install을 실행하지 말고 스크립트를 작성하여 직접 임포트하세요. 임포트가 실패하거나(또는markitdown명령이 누락된 경우)에만 누락된 패키지를pip install하세요.
아래 스크립트 경로는 이 스킬의 디렉토리를 기준으로 합니다.
모든 출력에 대한 요구사항
- 사용자가 달리 명시하지 않는 한 전체에 전문적인 글꼴(Arial, Times New Roman)을 사용합니다.
- 에러 없는 공식.
recalc.py가errors_found를 보고하는 동안에는 절대 배포하지 마세요. 에러가 사용자 이전에 존재했다고 생각되면 증명하세요:data_only=True로 원본을 로드하여 해당 셀을 확인하세요. 사용자가 도입한 에러는 상속받은 에러와 동일하게 보입니다. - 공식을 사용하고, 하드코딩된 결과는 절대 사용하지 마세요. Python으로 계산된 총합 대신
sheet['B10'] = '=SUM(B2:B9)'를 작성하세요. 시트는 입력이 변경될 때 다시 계산되어야 합니다. - 사용자의 사양을 문자 그대로 따르세요. 정확한 탭 이름, 정확한 열 헤더, 사용자가 지정한 공식을 준수하세요. 다른 것을 계산하는 재설계는 아무리 우아해도 실패입니다.
- 모든 가정과 하드코딩된 숫자를 독자가 볼 수 있는 곳에 문서화하세요 — 셀 주석 또는 표 끝의 인접한 셀. 출처가 존재하는 경우 실제 출처를 인용하세요(
출처: 회사 10-K, FY2024, 45페이지, 수익 주석, [SEC EDGAR URL]); 숫자가 사용자로부터 온 경우 명확히 명시하세요. - 사용자가 채울 목적으로 생성한 통합 문서에는 편집할 셀을 명시하는 짧은 범례와 예상 형식을 보여주는 하나의 예시 행(실제 값 포함)이 필요합니다. 편집을 요청받은 파일에는 이러한 행을 절대 추가하지 마세요.
- 기존 파일 편집: 해당 파일의 규칙을 정확히 따르세요. 여기의 모든 지침보다 우선합니다. 먼저 지정된 입력 셀을 찾으세요 — 고유한 글꼴 색상, 채우기 또는 음영으로 표시되어 있음 — 그곳에만 작성하고 기존 공식은 그대로 두세요.
재계산 (파일에 공식이 포함된 경우 필수)
openpyxl은 공식을 캐시된 값 없이 문자열로 작성합니다. 재계산하기 전까지 모든 공식 셀은 캐시된 값을 읽는 모든 것(pandas, load_workbook(data_only=True), 대부분의 미리보기 도구)에 대해 None으로 읽힙니다.
python scripts/recalc.py output.xlsx [timeout_seconds] # 기본 30
LibreOffice가 모든 공식을 계산하고, 파일은 제자리에서 덮어쓰기되며, JSON이 반환됩니다: status (success | errors_found), total_formulas, total_errors, 그리고 에러 유형별로 최대 100개 셀을 명명하는 error_summary (locations_truncated는 생략된 개수를 나타냄 — 목록 길이가 아닌 total_errors를 신뢰하세요). 명명된 항목을 수정하고 다시 실행하세요. status 대신 error 키가 있는 JSON은 재계산되지 않았음을 의미하며, 이 경우에만 0이 아닌 종료 코드가 발생합니다 — errors_found는 0으로 종료되므로, 깨끗한 종료를 깨끗한 통합 문서로 간주하지 마세요.
재계산 성공은 공식이 평가된다는 것만 증명하며, 올바르다는 것을 증명하지 않습니다. 하나 차이 나는 범위나 잘못된 행 참조는 잘못된 숫자가 포함된 깨끗하고 에러 없는 파일을 만듭니다. 먼저 2~3개의 공식을 작성하여 예상하는 값을 가져오는지 확인한 후, 그리드를 구축하세요.
다른 파일에 연결된 통합 문서를 openpyxl로 다시 저장한 후 재계산하면 해당 연결이 손실됩니다. 이러한 공식은 ='[1]Returns Analysis'!$B$2로 읽힙니다 — [1]은 통합 문서의 외부 참조 목록 인덱스로, 시트가 아닌 디스크 상의 별도 파일을 나타냅니다. 해당 파일이 여기에 있는 경우는 드물므로, 셀의 캐시된 값만이 데이터를 유지합니다. openpyxl은 저장 시 해당 값을 제거합니다. 그러면 LibreOffice가 실제로 참조를 확인해야 하고, 실패하여 #NAME?을 쓰고 모든 링크를 삭제합니다. recalc.py는 이 상태에서 실행을 거부합니다 — 저장하기 전에 원본에서 해당 셀의 값을 복사하세요 (--force는 재정의하며 손실을 감수합니다).
검증을 통과하는 공식 선택
LibreOffice는 Excel보다 적은 수의 함수를 구현하며, 평가할 수 없는 함수는 전달하는 파일에 리터럴 #NAME?으로 각인됩니다.
- Excel-2007 시대 함수 —
SUMIFS,INDEX,MATCH,IFERROR,SUMPRODUCT— 접두사가 필요 없으므로 선호하세요. - 2007 이후 여섯 가지 함수는
_xlfn.접두사가 있어야만 작동합니다. openpyxl이 공식을 XML에 그대로 쓰고 Excel은 접두사가 붙은 2007 이후 이름을 저장하기 때문입니다(UI는 접두사를 숨깁니다):_xlfn.TEXTJOIN,_xlfn.CONCAT,_xlfn.IFS,_xlfn.SWITCH,_xlfn.MAXIFS,_xlfn.MINIFS. 접두사 없이 쓰면 각각#NAME?이 발생합니다. XLOOKUP,XMATCH,SORT,FILTER,UNIQUE,SEQUENCE는 절대 사용하지 마세요. 런타임의 LibreOffice는 어떤 접두사로도 이를 평가할 수 없습니다. 최신 빌드는 평가할 수 있지만, 이들은 스필링 배열 함수이며 openpyxl로 작성된 파일에는 스필 메타데이터가 없으므로 범위의 왼쪽 위 셀만 값을 얻습니다 — 그리고recalc.py는 잘린 결과에 대해total_errors: 0을 보고합니다. 조회에는INDEX/MATCH를 사용하고, 셀을 쓰기 전에 Python에서 정렬, 필터링, 중복 제거를 수행하세요.- LibreOffice가 구문 분석할 수 없는 공식은 소문자로 다시 기록됩니다 —
#NAME?옆의 빠른 단서입니다.
openpyxl 주의사항
- 모델을 읽으려면 두 번 로드해야 합니다.
data_only=True는 공식이 사라진 캐시된 값을 제공합니다. 기본값은 값이 없는 공식 문자열을 제공합니다. 한 번의 패스로 두 가지를 모두 얻을 수 없습니다. - 저장 시
data_only=True는 파괴적입니다. 해당 통합 문서에는 더 이상 공식이 없으므로 저장 시 모든 공식이 리터럴로 대체되어 영구적으로 유지됩니다. - openpyxl이 방금 쓴 파일에 대해
data_only=True를 사용하면 모든 곳에서None이 반환됩니다 — 먼저recalc.py를 실행하세요. (결과가""인 공식도None으로 읽힙니다.) - 병합된 셀: 왼쪽 위 앵커에만 쓰세요. 범위의 다른 모든 셀은
.value가 읽기 전용인MergedCell입니다. .xlsm파일은load_workbook에keep_vba=True를 전달하지 않으면 매크로가 손실됩니다.- 공백이 포함된 시트 이름은 시트 간 참조에서 따옴표로 묶어야 합니다:
='Assumptions Inputs'!$B$5. 따옴표 없이 사용하면#VALUE!로 평가됩니다.
재무 모델
사용자가 달리 명시하거나 기존 파일이 이미 다른 방식으로 처리하지 않는 한 적용됩니다.
색상: 하드코딩된 입력 및 시나리오 레버는 파란색 텍스트(0,0,255) · 공식은 검은색 · 다른 시트로의 링크는 녹색(0,128,0) · 다른 파일로의 링크는 빨간색(255,0,0) · 주요 가정 및 사용자가 채워야 할 셀은 노란색 채우기(255,255,0).
숫자: 통화 $#,##0, 헤더에 단위 명시(Revenue ($mm)) · 0은 -로 표시, 백분율 포함($#,##0;($#,##0);-) · 음수는 괄호로 표시 · 백분율 0.0%, 분수로 저장 (0.15는 15.0%로 표시; 15를 저장하면 1500.0%로 표시) · 평가 배수 0.0x · 연도는 텍스트로 ("2024", 2,024 절대 사용 금지).
구조: 모든 가정은 자체 레이블이 지정된 셀에 있고, 이를 사용하는 공식에서 참조 (=B5*(1+$B$6), =B5*1.05 절대 사용 금지) · 모든 예측 기간에 걸쳐 공식이 일관되어야 함(행 중간에 단독으로 편집된 셀이 가장 흔한 무음 에러이므로) · 0으로 나눌 수 있는 분모를 보호하세요.
종속성
openpyxl, pandas, markitdown (pip, 사전 설치됨 — 임포트 실패 또는 명령 누락 시에만 설치) · LibreOffice (soffice, 샌드박스 환경에 맞게 scripts/office/soffice.py를 통해 자동 구성됨)