從 Excel 到 Python
在 2016 年的 Build 大會上,微軟宣佈全球有 12 億人在使用 Excel,而在同一年,全球的人口為 74 億。也就是說,使用 Excel 的人佔全球人口的 16.2%。
2019 年的一份報告( https://slashdata-website-cms.s3.amazonaws.com/sample_reports/ZAamt00SbUZKwB9j.pdf )顯示,Python 擁有 820 萬活躍開發者,佔全球人口的 0.001%。
從這些資料可以看出,增強 Excel 和 Python 之間的互動性對我們是有好處的,這為更多人打開了一扇使用 Python 工具的大門。
Python 在 Excel 前端方面的機會是巨大的。在本文中,我們將分享如何實現一個“典型的”財務 Excel 表格。
先工具,後 Excel
在幾乎所有我能想到的場景中,通常是先寫 Python 程式碼,不過必須要保持資料“輸入”格式的靈活性。
改變輸入資料集格式不應該影響到程式碼
假設我們使用 Pandas 讀取一個或兩個 CSV/Excel 表格,可能會依賴一組給定的列名。
如果有數千行這樣的程式碼,我們就依賴了很多硬編碼的列名,當我們試圖使用 Excel 動態輸入列名時,就會遇到問題。
因此,在最初的原型設計階段,在還沒有使用 Excel 工作表時,可以在程式碼裡將列名和內部標籤名對映起來:
mappings = {'loan identifier': 'loan_id', 'amt': 'amount', ... 'init fees': 'initial_fees'} data.rename(mappings, axis=1, inplace=True)
稍後,這種對映將被 Excel 工作表取代。
Excel 前端
等到 Python 初具模型,就可以開始構建 Excel 前端了。首先,我們要確定哪些變數可以放在 Excel 工作表中。
在開發這類工具時,一般都是要假設輸入資料的格式是會變的。
這點要麼很重要,要麼不那麼重要,具體取決於你所在的工作環境以及你要開發什麼樣的工具。有些工作流程定義得比較好,資料格式不太可能會發生變化。
但是,我總是會傾向於保持謹慎,希望通過 Excel 來增加靈活性,但要注意不要將事情複雜化。
使用 Excel 將 Python 內部列名與外部 CSV/Excel 列名對映起來
使用內部命名系統並允許 Excel 使用者指定列對映,這是保持靈活性的一個很好的例子。現在,Excel 使用者不再依賴於硬編碼的列名,他們可以在不修改 Python 程式碼的情況下調整列對映。
對映
mappings 是整合的核心部分,它的內容來自 Excel 中的一張表(我通常會叫它 Mapping)。
要得到 mappings,我們需要一個函式來讀取 Excel。為此,我們使用了 openpyxl。
我們可以這樣讀取 Excel 中的單元格:
import openpyxl
# 載入工作簿
wb = openpyxl.load_workbook("sheet.xlsx", data_only=True)
# 建立工作簿物件
ws = wb.active
# 獲取單元格 E4 的值
value = ws['E4'].value
我們可以通過這種方式得到 mappings。我們將程式碼稍作調整,新增 Excel 工作簿“tool_setup.xlsx”本地路徑。
我們還要假設 Excel 的當前工作表可能不是我們想要的那個,而且可能會新增、被刪除或被移動,所以我們需要通過遍歷找到目標工作表的索引位置:
# 首先,我們設定 Excel 檔案的路徑
path = r".\documents\tool_setup.xlsx"
# 載入檔案,建立工作簿物件
wb = openpyxl.load_workbook(path, data_only=True)
# 找到目標工作表的索引
idx = [i for i, name in wb.sheetnames if name == 'Mapping'][0]
# 將目標工作表設定為當前工作表
wb.active = idx
ws = wb.active
現在,我們可以填充 mappings 內容了 :
mappings = {}
mappings['Amount'] = ws["E4"].value
mappings['Term'] = ws["E5"].value
保持靈活性
如果工作表裡添加了新行或者把舊行刪除,有可能會得到一個不正確的 mappings。為了避免這種情況,我們需要 search_col 函式,它會遍歷查詢每個單元格,直到找到包含我們想要的值(或超過 limit 限制)的單元格。
# 定義一個函式,用於查詢 openpyxl 工作簿物件中的給定列
def search_col(sheet, column, value, limit=100):
# 從 1 開始,逐行查詢,直到達到 limit 限制
for row in range(1, limit+1):
if sheet[f"column{row}"].value == value:
# 找到想要的單元格,返回單元格的列和行
return (col, row)
search_col 返回我們想要的資料的列和行。
如果沒處理好,哪怕是在工作表裡新增一個註釋也會讓工具不可用。左邊的“Internal”在第 12 行,而右邊是第 14 行。
我們可以像下面這樣找到“Internal”的單元格位置:
search_col(ws, 'B', 'Internal')
[Out]: ('B', 12)
接下來,我們通過迴圈往 mappings 新增其他列對映。在遇到兩個或者更多個空的單元格後,我們就知道對映內容已經全部讀取完畢,就可以結束迴圈了:
empty = 0 # 初始化空單元格數量
while empty < 2:
# 增加行計數
row += 1
# 賦值
internal = ws[f'B{row}'].value
if internal is None:
empty += 1 # 遇到空單元格就增加空單元格計數
else:
# 加入 mappings
mappings[internal] = ws[f'D{row}'].value
empty = 0 # also re-initialize the empty counter
執行上面的程式碼,就可以得到像下面這樣的 mappings:
{
'Loan ID': 'loan identifier',
'Product': 'product type',
...
'Initial Fees': 'init fees'
}
如果要引入其他變數,比如檔案路徑(filepath),我們只需要找到包含“Filepath”的單元格,並把它的值賦給“filepath”:
row, _ = search_col(ws, 'C', 'Filepath')
mappings['filepath'] = ws[f'D{row}].value
整合
最後一步,也是最容易的一步——在 Python 指令碼中使用列名。
我們使用上面得到的 mappings,將輸入列名轉成內部標籤。
data = pd.read_csv(mappings['Filepath'])
在將輸入列名轉成內部標籤之前,我們必須翻轉鍵值對,即把鍵 - 值轉成值 - 鍵。
# 翻轉
inv_mappings = {mappings[key]: key for key in mappings}
對於這個簡單的例子,或許在構建 mappings 時就進行翻轉會更方便些。對於複雜一點的工具,我發現使用內部到外部的對映格式會更好。但不管怎樣,這一切取決於你自己。
最後,將輸入列名轉成內部標籤:
data.rename(inv_mappings, axis=1, inplace=True)
我們可以做得更靈活一些。為了處理不必要的空格或大小寫拼寫錯誤,我們重寫了一小部分程式碼:
data = pd.read_csv(mappings['Filepath'])
# 轉成小寫,剔除不必要的空格
data.rename({col: col.strip().lower() for col in data.columns},
axis=1, inplace=True)
# inv_mappings 也是一樣
# 內部標籤使用蛇形命名方式 (不是必需的)
inv_mappings = {
mappings[key].strip().lower():
key.strip().lower().replace(' ', '_')
for key in mappings
}
# 現在安全了
data.rename(inv_mappings, axis=1, inplace=True)
另外,我們在 Excel 中顯示內部標籤時通常會使用首字母大寫和正常空格,而在內部我個人還是選擇蛇形命名格式。
"Loan ID" -> "loan_id"
"Initial Rate" -> "initial_rate"
結論
我曾見過無數家重度使用 Excel 的公司,這麼做可以節省數百個小時用於檢查單元格、輸入值或等待 Excel 模型處理資料的時間。
儘管自動化和機器學習時代正在迅速地將 Excel 的很多領域自動化,但 Excel 不會很快就消失掉。
目前,世界上發展最快的程式語言(Python)和世界上使用最為廣泛的軟體(Excel)之間的緊密整合可以給很多行業帶來巨大收益。
※更多文章和資料|點選後方文字直達 ↓↓↓
100GPython自學資料包
阿里雲K8s實戰手冊
[阿里雲CDN排坑指南]CDN
ECS運維指南
DevOps實踐手冊
Hadoop大資料實戰手冊
Knative雲原生應用開發指南
OSS 運維實戰手冊
雲原生架構白皮書
Zabbix企業級分散式監控系統原始碼文件
雲原生基礎入門手冊
10G大廠面試題戳領