2025年9月9日 星期二

避免 Series/DataFrame 不匹配錯誤的範例

 
這個程式碼:

  1. 安全地抓取股票資料

  2. 檢查型態,避免 Series/DataFrame 錯誤

  3. 計算移動平均與量能異常

  4. 畫出柱狀圖 + 折線 + 異常點

  5. 適合當作 量能分析模板

 ===========================================================

import yfinance as yf
import matplotlib.pyplot as plt
import pandas as pd

# 1️⃣ 選股票
ticker = "2330.TW"
data = yf.download(ticker, period="3mo", interval="1d", auto_adjust=True)

# 2️⃣ 型態檢查
print("資料型態檢查:")
print(f"data type: {type(data)}")                 # DataFrame
print(f"Volume type: {type(data['Volume'])}")    # Series
print("欄位名稱:", data.columns)
print("Index 型態:", type(data.index))

# 3️⃣ 取成交量,確保是 Series
if isinstance(data['Volume'], pd.Series):
    volume = data['Volume']
else:
    volume = data['Volume'].squeeze()  # 轉成 Series

# 4️⃣ 計算移動平均量能
volume_ma5 = volume.rolling(window=5).mean()
volume_ma20 = volume.rolling(window=20).mean()

# 5️⃣ 計算量能異常
volume_mean = volume.mean()
volume_std = volume.std()
high_volume_flag = volume > (volume_mean + 2*volume_std)

# 6️⃣ 畫圖(安全處理 index)
x_labels = [d.strftime('%Y-%m-%d') for d in data.index]

plt.figure(figsize=(12,6))
plt.bar(x_labels, volume.values, color='skyblue', label='成交量')
plt.plot(x_labels, volume_ma5.values, color='red', label='5日平均量')
plt.plot(x_labels, volume_ma20.values, color='green', label='20日平均量')
plt.scatter(
    [x_labels[i] for i, flag in enumerate(high_volume_flag) if flag],
    [volume.values[i] for i, flag in enumerate(high_volume_flag) if flag],
    color='orange', label='量能異常', zorder=5
)
plt.xticks(rotation=45)
plt.legend()
plt.title(f'{ticker} 成交量與移動平均 (安全模板)')
plt.tight_layout()
plt.show()

 

======================================================

🔹 特點

  1. 型態檢查 → 避免 Series/DataFrame 不匹配錯誤

  2. index 安全處理 → strftime 轉成字串,Matplotlib bar 不出錯

  3. 計算量能指標 → 5 日 / 20 日平均、異常量能點

  4. 一條龍流程 → 從抓資料到畫圖,小實驗可直接使用

 =====================================================

 

程式碼 逐行拆解、解釋用途與作用:


import yfinance as yf import matplotlib.pyplot as plt import pandas as pd
  • 引入套件

    • yfinance:抓取股票資料的 API

    • matplotlib.pyplot:繪圖套件,用來畫折線圖、柱狀圖等

    • pandas:資料處理套件,用來操作 DataFrame、Series


# 1️⃣ 選股票 ticker = "2330.TW" data = yf.download(ticker, period="3mo", interval="1d", auto_adjust=True)
  • ticker:股票代號,這裡是台積電(2330.TW)

  • yf.download(...):

    • period="3mo" → 下載過去 3 個月資料

    • interval="1d" → 每日資料

    • auto_adjust=True → 自動調整股價(考慮除權息),方便分析

  • 回傳結果:data 是一個 DataFrame,包含欄位:Open, High, Low, Close, Adj Close, Volume


# 2️⃣ 型態檢查 print("資料型態檢查:") print(f"data type: {type(data)}") # DataFrame print(f"Volume type: {type(data['Volume'])}") # Series print("欄位名稱:", data.columns) print("Index 型態:", type(data.index))
  • 檢查資料型態,避免之後計算或畫圖時發生 Series/DataFrame 錯誤

  • .columns → 取得欄位名稱

  • .index → 取得索引型態(通常是 DatetimeIndex)


# 3️⃣ 取成交量,確保是 Series if isinstance(data['Volume'], pd.Series): volume = data['Volume'] else: volume = data['Volume'].squeeze() # 轉成 Series
  • data['Volume'] 可能是 Series 或 DataFrame(單欄時偶爾會有差異)

  • isinstance 判斷型態,確保 volume 最終是 Series,方便做 .rolling()、算平均等操作


# 4️⃣ 計算移動平均量能 volume_ma5 = volume.rolling(window=5).mean() volume_ma20 = volume.rolling(window=20).mean()
  • rolling(window=5) → 計算 5 日移動平均

  • .mean() → 計算平均

  • 5 日平均量與 20 日平均量,用來觀察量能趨勢


# 5️⃣ 計算量能異常 volume_mean = volume.mean() volume_std = volume.std() high_volume_flag = volume > (volume_mean + 2*volume_std)
  • volume_mean → 成交量平均值

  • volume_std → 成交量標準差

  • high_volume_flag → 標記「量能異常」的布林值 (True/False)

    • 條件:成交量大於平均 + 2 倍標準差 → 異常放大量


# 6️⃣ 畫圖(安全處理 index) x_labels = [d.strftime('%Y-%m-%d') for d in data.index]
  • 將 DatetimeIndex 轉成 字串日期,方便 matplotlib 畫圖

  • 避免直接用 DatetimeIndex 某些版本 matplotlib 會出現錯誤


plt.figure(figsize=(12,6)) plt.bar(x_labels, volume.values, color='skyblue', label='成交量') plt.plot(x_labels, volume_ma5.values, color='red', label='5日平均量') plt.plot(x_labels, volume_ma20.values, color='green', label='20日平均量')
  • plt.figure(figsize=(12,6)) → 設定圖表大小

  • plt.bar(...) → 畫成交量柱狀圖

  • plt.plot(...) → 畫移動平均折線圖

  • .values → 確保資料是 numpy array,避免 Series 與索引不對應


plt.scatter( [x_labels[i] for i, flag in enumerate(high_volume_flag) if flag], [volume.values[i] for i, flag in enumerate(high_volume_flag) if flag], color='orange', label='量能異常', zorder=5 )
  • plt.scatter → 畫量能異常點

  • [x_labels[i] for i, flag in enumerate(high_volume_flag) if flag]

    • 取布林值為 True 的日期

  • [volume.values[i] for i, flag in enumerate(high_volume_flag) if flag]

    • 取對應成交量

  • zorder=5 → 讓異常點疊在其他圖表之上


plt.xticks(rotation=45) plt.legend() plt.title(f'{ticker} 成交量與移動平均 (安全模板)') plt.tight_layout() plt.show()
  • plt.xticks(rotation=45) → X 軸文字旋轉,避免重疊

  • plt.legend() → 顯示圖例

  • plt.title(...) → 設定標題

  • plt.tight_layout() → 調整邊距,避免標題或 X 軸文字被截掉

  • plt.show() → 顯示圖表




 

沒有留言:

張貼留言