台股開放資料的民國年、字串數值要怎麼清洗?
三件事要處理:日期是民國年(1150811 是 2026-08-11,11507 是 2026-07),所有數值都以字串回傳要自己轉型,欄名兩套並存(有的端點英文、有的中文)。另外常見的「把逗號全部拿掉」不要照做——實測數值欄位裡沒有千分位逗號,有逗號的是備註那類自由文字,整批清理會把它改壞。
民國年有兩種長度,別用同一個函式硬轉
日期欄位是民國年字串:出表日期像 1150811(7 碼,年月日),資料年月像 11507(5 碼,只有年月)。兩者前面的年份都要加 1911,但後面的切法不同,寫成同一個轉換函式很容易在月份上出錯。
def roc_date(value: str) -> str:
"""民國年日期 1150811 → 2026-08-11。"""
return f"{int(value[:-4]) + 1911}-{value[-4:-2]}-{value[-2:]}"
def roc_month(value: str) -> str:
"""民國年月 11507 → 2026-07。"""
return f"{int(value[:-2]) + 1911}-{value[-2:]}"
print(roc_date("1150811")) # 2026-08-11
print(roc_month("11507")) # 2026-07所有數值都是字串,而且不能無腦轉
開高低收、成交量、成交金額全部以字串回傳。直接 float() 多數時候可行,但遇到空字串或占位符號就會炸——所以轉型要有預設值,並且讓失敗變成 None 而不是 0。0 在價格與成交量裡是有意義的數字,用它當轉換失敗的替身,之後你就分不出來了。
def to_number(value):
"""轉不動就回 None,不要回 0——0 是有意義的值。"""
if value is None:
return None
text = str(value).strip()
if text in ("", "-", "--"):
return None
try:
return float(text)
except ValueError:
return None
print(to_number("13.88"), to_number("20635383"), to_number("--"), to_number(""))「把逗號全部拿掉」是錯的反射動作
很多清洗範例第一步就是全欄位 replace(",", "")。實測這兩支端點的數值欄位裡沒有千分位逗號;有逗號的是「備註」這種自由文字,例如「累計1-7月營收較去年同期增加22,793仟元」。整批去逗號不會讓數字更乾淨,只會把備註改掉。要去逗號就只對你確定是數值的那幾個欄位做。
NUMERIC_FIELDS = {"營業收入-當月營收", "營業收入-上月營收", "營業收入-去年當月營收"} def clean_row(row: dict) -> dict: out = {} for key, value in row.items(): if key in NUMERIC_FIELDS: # 只對確定是數值的欄位處理 out[key] = to_number(str(value).replace(",", "")) else: out[key] = value # 備註之類的自由文字原樣保留 return out欄名有兩套,跨端點要自己對照
同樣是官方開放資料,全市場日行情用英文欄名(Date、Code、ClosingPrice),上市公司月營收用中文欄名(出表日期、公司代號、營業收入-當月營收)。要把不同端點併成一張表,就需要一份自己的欄名對照,而且新增端點時要記得維護它。
FIELD_MAP = { # 日行情(英文欄名) "Code": "symbol", "Date": "date", "ClosingPrice": "close", "TradeVolume": "volume", # 月營收(中文欄名) "公司代號": "symbol", "資料年月": "revenue_month", "營業收入-當月營收": "revenue",} def normalise(row: dict) -> dict: return {FIELD_MAP.get(k, k): v for k, v in row.items()}或者,跳過這一段
如果這些轉換不是你想花時間的地方,我們這邊回的就是已經處理過的形態:日期是 ISO 字串、數值是數字型別、上市與上櫃併在同一套欄名下。資料來源仍是官方,差別只在誰做這段清洗。
import requests
r = requests.get(
"https://api.twmarketdata.com/v2/datasets/twse-daily-price",
headers={"X-API-Key": "sk_live_你的金鑰"},
params={"symbol": "2330", "limit": 3},
timeout=20,
)
for row in r.json()["rows"]:
# date 已是 ISO 字串,close 已是數字,不需要再轉
print(row["date"], row["close"], row["volume_shares"], type(row["close"]).__name__)我們沒有的東西,先說清楚
- 自己抓官方資料完全可行,而且免費——這頁的前四段就是為了讓那條路走得順。
- 沒有即時報價,官方那幾支開放端點同樣是盤後快照。
- 我們不會替你保留原始的民國年與字串型別。要原樣的欄位就直接打官方端點。
常見問題
11150811 跟 11507 為什麼長度不一樣?
一個是年月日、一個只有年月。1150811 是民國 115 年 8 月 11 日(2026-08-11),11507 是民國 115 年 7 月(2026-07)。轉換時要分開處理,不要共用同一個切字串的函式。
2轉型失敗時填 0 有什麼問題?
0 在成交量、買賣超、報酬率裡都是合法且有意義的值。用它當「轉換失敗」的替身,之後你分不出這天是真的沒有成交,還是你的程式沒轉成功。回 None,讓缺就是缺。
3所以到底要不要處理千分位逗號?
只在你確定是數值的欄位上處理。實測這兩支端點的數值欄位沒有逗號,有逗號的是備註那類自由文字;全欄位整批去逗號會把文字改壞。
4上市跟上櫃的欄名一樣嗎?
不一樣,而且同一個機構的不同端點也可能不一樣——日行情是英文欄名,月營收是中文欄名。要合併就得自己維護一份對照表。
想自己查這些資料?免費註冊。