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載入原始檔案,並檢查該儲存格。你所引入的錯誤與繼承而來的錯誤看起來完全相同。 - 使用公式,絕不硬編碼結果。 請寫
sheet['B10'] = '=SUM(B2:B9)',而非 Python 計算的總和。工作表必須在輸入值變更時重新計算。 - 嚴格遵循使用者的規格。 確切的分頁名稱、精準的欄位標題,以及他們拼寫出來的公式。一個計算其他東西的重新設計,即使再優雅,也是失敗的。
- 在讀者可見之處記錄每個假設與硬編碼數字 — 儲存格註解,或表格末尾的相鄰儲存格。若存在真實來源,請引用(
來源:公司 10-K,FY2024,第 45 頁,收入附註,[SEC EDGAR 網址]);若數字來自使用者,請直接說明。 - 你為讓他人填寫而建立的活頁簿需要一個簡短圖例,標明哪些儲存格需要編輯,以及一個範例列,使用真實值展示預期格式。對於被要求編輯的檔案,切勿加入此類範例列。
- 編輯現有檔案:嚴格比對其慣例。 它們會覆蓋此處的所有指南。首先找出其指定的輸入儲存格(通常有獨特的字型顏色、填滿或陰影標記),僅在該處寫入,並保持所有既有公式不變。
重新計算(每當檔案包含公式時強制執行)
openpyxl 將公式寫為字串,且不包含快取值。在重新計算之前,每個公式儲存格對於任何讀取快取值的東西(pandas、load_workbook(data_only=True) 及大多數預覽工具)都會傳回 None。
python scripts/recalc.py output.xlsx [超時秒數] # 預設 30
LibreOffice 會計算每個公式,檔案會原地重新寫入,並輸出 JSON:包含 status(success | errors_found)、total_formulas、total_errors,以及一個 error_summary,其中最多列出每個錯誤類型的前 100 個儲存格(locations_truncated 表示被省略的數量 — 請相信 total_errors,而非列表的長度)。修正它命名的錯誤後再次執行。當 JSON 包含 error 鍵而非 status 時,表示未重新計算任何內容,且只有此情況會以非零狀態碼退出 — 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。) - 合併儲存格:僅寫入左上角的錨點。 範圍內的其他每個儲存格都是一個
MergedCell,其.value是唯讀的。 - 除非在
load_workbook中傳遞keep_vba=True,否則.xlsm會失去其巨集。 - 包含空格的工作表名稱在跨工作表參考中必須加上引號:
='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.15 顯示為 15.0%;儲存 15 會顯示 1500.0%) · 估值倍數 0.0x · 年份以文字形式儲存("2024",絕不使用 2,024)。
結構: 每個假設放在各自的標籤儲存格中,並由使用它的公式引用(=B5*(1+$B$6),絕不使用 =B5*1.05) · 公式在所有預測期間內保持一致,因為行中間單獨編輯的儲存格是最常見的隱性錯誤 · 對可能為零的分母進行防護。
相依套件
openpyxl、pandas、markitdown(pip,已預先安裝 — 僅在匯入失敗或缺少指令時才安裝) · LibreOffice(soffice,已自動配置為透過 scripts/office/soffice.py 在沙箱環境中運作)