前情提要:
視覺化 Walmart 財報- 01 (安裝環境、檔案基本介紹)
本筆記要開始進入拆解程式碼跟邏輯的階段,為了方便講解,我用 Colab 作筆記 (其實是有點懶得安裝套件)。我的學習方式中英文網頁搜尋 + 搭配ChatGPT 問「為什麼」,目的是我可以「白話文解釋程式碼」
📌 為什麼要轉成 Pandas DataFrame?
我猜因為財報的數據量大所以 duckdb.ipynb
和 Pandas SQL sent.ipynb
也用 Pandas 來處理財報數據!
DataFreame 是2維的資料結構,更一步的介紹請看:
FY25Q4_Link = 'https://app.quotemedia.com/data/downloadFiling?...' #Excel 檔的網址,點擊可下載
import urllib
dls = FY25Q4_Link
urllib.request.urlretrieve(dls, "data.xlsx") #從網址下載 Excel 檔案,並儲存為 data.xlsx。
要先 import urllib
函式庫,這個函式庫用來發送 HTTP 請求,像是urllib.request
→ 發送 HTTP 請求(下載網頁或檔案)再.urlretrieve
表示下載檔案。補充,urllin.request.urlopen
是打開網頁
from openpyxl import load_workbook
wb = load_workbook(filename='data.xlsx', read_only=True)
為甚麼要用 OpenPyXL ?不用 Pandas?這兩種方式最大的差別是
OpenPyXL 像人工操作 Excel 可以做到
✅ 讀取、修改 Excel(如寫入新數據)
✅ 讀 Excel 的部分區域(特定儲存格),設定讀取範圍
✅ 讀 Excel 的格式(顏色、合併儲存格、公式)
但 pandas.read.excel() 只能「讀取整張表」,剛好這個表格每個 sheet 只有特定範圍,所以用 OpenPyXL 比較快。
✅ 只想讀 Excel,轉成 Pandas DataFrame 分析 → pandas.read_excel("data.xlsx")
✅ 不需要修改 Excel,單純做數據分析 → pandas
會更方便
3. 解析「營運總部地址」財報頁面
ws = wb['address of principal execu-4'] #讀分頁worksheet=ws
data_rows = [] # 建立一個空的列大表,之後再轉dataFrame 後續
for row in ws['A4':'H45']:
data_cols = [] #把資料存到新的colomn
for cell in row: # 遍歷該行的每個儲存格(cell)
data_cols.append(cell.value) #把儲存格的值加到column list裡
data_rows.append(data_cols)# 再把每個column list 放到data_row 大表
df_earnings = pd.DataFrame(data_rows)#轉dataframe
address of principal execu-4
(財報的 "Principal Executive Office" 分頁)。小問題,為什麼不要直接寫?還要先把資料存成一行一行,再存入大表呢?雖然少一行程式碼,但是不容易理解,而且當要整理資料(例如去掉0,這樣程式碼就不好維護)
data_rows.append([cell.value for cell in row]) # 直接存入 data_rows
為了解先解析cell.value到row裡面,加入 print
來觀察。
嘗試每個指令print 出,感覺一下
df_earnings
) 方便分析。ws_breakdown = wb['segment information']
data_rows = []
for row in ws_breakdown['A4':'H45']:
data_cols = []
for cell in row:
data_cols.append(cell.value)
data_rows.append(data_cols)
df_breakdown = pd.DataFrame(data_rows)
🔹 這裡的作用:
df_breakdown
)。df
是Pandas 中「DataFrame」的縮寫,表示一個 表格狀的數據結構,類似於:Total Revenue
)lookupn = 6 # 第 6 欄的數值
df_Total_Revenue = df_earnings.loc[df_earnings.iloc[:, 0] == 'Total revenues'].iloc[:, lookupn].item()/1000
df_earnings.iloc[:, 0]
.iloc 是 pandas 裡的篩選功能取出[row,column]先以第 0 Column 。:
是全部列df_earnings.loc[df_earnings.iloc[:, 0] == 'Total revenues']
→ 只保留這一row數據 (往前)看.iloc[:, lookupn].item()/1000
最後看後面,因為前面有設定lookupn是第6 column 再.item()
把 Series 轉換成數字除以 1000,之後用百萬美元(million USD),這行程式碼的目的是把它轉換成 十億美元(billion USD)概念是這樣擷取
df_Revenue_b1 = df_earnings.loc[df_earnings.iloc[:, 0] == 'Membership and other income'].iloc[:, lookupn].item()/1000
df_Revenue_b2 = df_breakdown.loc[df_breakdown.iloc[:, 0] == 'Net sales'].iloc[0, lookupn_mix]/1000
df_Revenue_b3 = df_breakdown.loc[df_breakdown.iloc[:, 0] == 'Net sales'].iloc[1, lookupn_mix]/1000
df_Revenue_b4 = df_breakdown.loc[df_breakdown.iloc[:, 0] == 'Net sales'].iloc[2, lookupn_mix]/1000
df_Revenue_b5 = 0
df_Revenue_b6 = 0
df_Revenue_b1
:會員收入 (Membership and other income
)df_Revenue_b2
:第一個業務部門 (Net sales
,可能是 Walmart U.S.)df_Revenue_b3
:第二個業務部門 (Net sales
,可能是 Walmart International)df_Revenue_b4
:第三個業務部門 (Net sales
,可能是 Sam's Club)Cost of Sales
)df_Total_COGS = df_earnings.loc[df_earnings.iloc[:, 0] == 'Cost of sales'].iloc[:, lookupn].item()/1000
df_GP = df_Total_Revenue - df_Total_COGS
df_Total_COGS
:成本 (Cost of sales
)df_GP
:毛利 (Gross Profit
) = 總營收 - 成本Operating Expenses
)df_RD = 0
df_SGA = df_earnings.loc[df_earnings.iloc[:, 0].str.contains('selling, general and administrative', case=False, regex=True) & True].iloc[:, lookupn].item()/1000
df_Total_Operating_Expenses = df_RD + df_SGA
df_SGA
:銷售、管理、行政費用 (Selling, General & Administrative Expenses
)df_Total_Operating_Expenses
:總營業費用 = 研發 (R&D
) + SGAOperating Profit
)df_OP = df_GP - df_Total_Operating_Expenses
Operating Profit
) = 毛利 (df_GP
) - 營業費用 (df_Total_Operating_Expenses
)Pretax Profit
)df_Pretax_Profit = df_earnings.loc[df_earnings.iloc[:, 0].str.contains('Income before income taxes', case=False, regex=True) & True].iloc[:, lookupn].item()/1000
df_NOEI = df_OP - df_Pretax_Profit
df_Pretax_Profit
:稅前淨利 (Income before income taxes
)df_NOEI
:非營業收入 (Non-Operating Income
),推測是 df_OP - df_Pretax_Profit
Net Profit
)df_Tax_Expense = df_earnings.loc[df_earnings.iloc[:, 0].str.contains('Provision for income taxes', case=False, regex=True) & True].iloc[:, lookupn].item()/1000
df_AfterTax_Revenue = 0
df_Net_Profit = df_Pretax_Profit - df_Tax_Expense + df_AfterTax_Revenue
df_Tax_Expense
:所得稅 (Provision for income taxes
).str.contains
找出包含「Provision for income taxes」的row。case=False
大小寫不拘,regex=True
是允許表達式(允許空格、模糊查詢),前面 case=False 大小寫不拘 使用 regex=True 讓 case=False 可以使用。✅ 忽略大小寫(case=False
) ✅ 允許正則表達式匹配(regex=True
)
df_Net_Profit
:淨利 (Net Profit
) = 稅前利潤 - 所得稅EPS
)df_EPS_Basic = df_earnings.loc[df_earnings.iloc[:, 0] == 'Basic'].iloc[:, lookupn].head(1).item()
df_EPS_Diluted = df_earnings.loc[df_earnings.iloc[:, 0] == 'Diluted'].iloc[:, lookupn].head(1).item()
df_EPS_Basic
:基本每股盈餘 (Basic EPS
)df_EPS_Diluted
:稀釋後每股盈餘 (Diluted EPS
)✅ 這段程式碼的功能:
data.xlsx
)✅ 最後產生的變數:
df_Total_Revenue
(總營收)df_GP
(毛利)df_OP
(營業利潤)df_Net_Profit
(淨利)df_EPS_Basic
(基本每股盈餘)在我們把這些變數找到後,變成Pandas 格式,整理財務數據,並準備資料來畫 Sankey Diagram,下一篇會再繼續拆解。