iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0
Python

時空序列分析-關鍵籌碼分析系列 第 17

ConvLSTM模型訓練時空資料? 工兵隊Debug中

  • 分享至 

  • xImage
  •  

延續昨天,我們拿到了各個券商分點5/13~5/16 對所羅門進行買賣的籌碼資訊
既然資料收集的部分解決了,下一步來做資料前處理,接著用模型來訓練。

原本DAY10 爬蟲拿資料? 來學習怎麼畫股價K線圖! Step(2/2): 自己爬股價 這篇是以台積電舉例,
現在再用一次這段程式碼,抓所羅門2359今年5月的股價

按照DAY9決定欄位! 天下沒有白吃的午餐,股價、籌碼資料的其他來源? 決定的欄位,

把這幾天的股價資料的這些欄位資料和籌碼資料

開盤價, 收盤價, 最高價, 最低價, 成交量
104 106 99.9 104.5 15868.696 (2024/5/13)
104 114.5 101 114.5 38083.434 (2024/5/14)
120 125.5 120 125.5 23445.998 (2024/5/15)
130 134.5 118 120 95284.736 (2024/5/16)
121 132 119 132 59619.378 (2024/5/17)

昨天 拿到的籌碼資料,
先以日期排序(由小到大)整個資料表,接著把日期放到最前面的欄位,把總數刪去。
現在大概變這樣

日期 券商代碼 買進(張) 賣出(張) 買賣超(張)
2024/05/13 1020 99 81 18
2024/05/13 1021 14 93 -79
2024/05/13 1022 5 23 -18
. . .

開始工人智慧! ctrl+c,ctrl+v,把股價按照日期填在後面。

日期	券商代碼	買進(張)	賣出(張)	買賣超(張)	開盤價	最高價	最低價	收盤價	成交量
2024/05/13	1020	99	81	18	104	106	99.9	104.5	15868.696
2024/05/13	1021	14	93	-79	104	106	99.9	104.5	15868.696
2024/05/13	1022	5	23	-18	104	106	99.9	104.5	15868.696
2024/05/13	1023	45	19	26	104	106	99.9	104.5	15868.696
2024/05/13	1024	8	5	3	104	106	99.9	104.5	15868.696
. . .

大概變成這樣,取名Merged_to_train.xlsx好了。

接著,還有和地理資訊合併!

DAY13 拿到的券商地點,存成了PLUS_lat_lng_address.xlsx
含金量滿滿的文章? Step(1/4):關鍵分點籌碼爬蟲,之前拿到的券商地點,要怎麼處理?

又動手把 經、緯度 再去轉換了 橫坐標、縱坐標

#讀取
PLUS_lat_lng = pd.read_excel('PLUS_lat_lng_address.xlsx')
#PLUS_lat_lng.head()

# 把欄位重新命名成 lat, lng
PLUS_lat_lng = PLUS_lat_lng.rename(columns={
        '緯度': 'lat',
        '經度': 'lng'
    })

PLUS_lat_lng.head()

券商代碼 券商名稱 開業日 地址 lat lng
0 1020 合庫 2011-12-02 台北市大安區忠孝東路四段285號 25.041682 121.554221
1 1021 合庫- 台中 2011-12-02 台中市西區民權路91號 24.138065 120.679533
2 1022 合庫-台南 2011-12-02 台南市北區成功路48號 22.998140 120.207742
3 1023 合庫-高雄 2011-12-02 高雄市大勇路97號 22.624785 120.284190
4 1024 合庫-嘉義 2011-12-02 嘉義市國華街279號 23.480549 120.448310

轉換成TWD97座標制

# 轉換
result = PLUS_lat_lng.apply(lambda row: wgs84_to_twd97(row['lat'], row['lng']), axis=1)
PLUS_lat_lng['橫坐標'], PLUS_lat_lng['縱坐標'] = zip(*result)
print(PLUS_lat_lng.head())

# 將新的資料存 Excel
PLUS_lat_lng.to_excel('PLUS_lat_lng_橫縱.xlsx', index=False)

把地理位置的資訊接上去

import pandas as pd

# 讀取兩個CSV文件
df1 = pd.read_excel('E:/時空資料分析/關鍵分點籌碼分析_實測/PLUS_lat_lng_橫縱.xlsx')
df2 = pd.read_excel('E:/時空資料分析/關鍵分點籌碼分析_實測/Merged_to_train.xlsx')

# 將"代號"列設為索引
df2 = df2.set_index('券商代碼')

# 使用資料表df1的"代碼"列作為索引,並將df1的特定列合併到df2
df2 = df2.join(df1.set_index('券商代碼')[['橫坐標', '縱坐標']], how='left')

## 不能這樣合併後直接用哦,因為裡面有重複資料 !!!!

# 將結果寫入新的CSV文件
df2.to_excel('Merged_to_train_ALL.xlsx', index=True)

日期 買進(張) 賣出(張) 買賣超(張) 開盤價 最高價 最低價 收盤價 成交量 橫坐標 縱坐標
券商代碼
1020 2024/05/13 99 81 18 104 106.0 99.9 104.5 15868.696 305924 2770508
1021 2024/05/13 14 93 -79 104 106.0 99.9 104.5 15868.696 217429 2670350
1022 2024/05/13 5 23 -18 104 106.0 99.9 104.5 15868.696 168780 2544296
1023 2024/05/13 45 19 26 104 106.0 99.9 104.5 15868.696 176418 2502912
1024 2024/05/13 8 5 3 104 106.0 99.9 104.5 15868.696 193646 2597605
... ... ... ... ... ... ... ... ... ... ... ...
9A9W 2024/05/16 451 389 62 130 134.5 118.0 120.0 95284.736 213376 2672724
9A9x 2024/05/16 124 139 -15 130 134.5 118.0 120.0 95284.736 281093 2764818
9A9X 2024/05/16 124 139 -15 130 134.5 118.0 120.0 95284.736 248958 2743608
9A9Y 2024/05/16 105 97 8 130 134.5 118.0 120.0 95284.736 297253 2767298
9A9Z 2024/05/16 11 3 8 130 134.5 118.0 120.0 95284.736 305450 2772146
3183 rows × 11 columns

有點強迫症,然後再手動把 橫坐標、縱坐標 移動到中間,調整成 DAY9預想合併的欄位一樣。

用ConvLSTM模型來分析

一、在使用 ConvLSTM 模型之前,需要準備和處理以下這些欄位:資料前處理

日期->(日期時間類型)
券商代號->(用於區分不同的券商分點)
買進(張)、賣出(張)、買賣超(張)->(交易行為、籌碼資訊)
橫坐標、縱坐標->(券商分點地理位置)
開盤價、最高價、最低價、收盤價、成交量(股價資訊、交易量)

import numpy as np
import pandas as pd

df = pd.read_excel('E:/時空資料分析/關鍵分點籌碼分析_實測/Merged_to_train_ALL.xlsx')
df.info() # 看一下資料型態


# 缺失值處理
df = df.fillna(method='ffill')

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3183 entries, 0 to 3182
Data columns (total 12 columns):

Column Non-Null Count Dtype


0 日期 3183 non-null object
1 券商代碼 3183 non-null object
2 買進(張) 3183 non-null object
3 賣出(張) 3183 non-null object
4 買賣超(張) 3183 non-null object
5 橫坐標 3183 non-null int64
6 縱坐標 3183 non-null int64
7 開盤價 3183 non-null int64
8 最高價 3183 non-null float64
9 最低價 3183 non-null float64
10 收盤價 3183 non-null float64
11 成交量 3183 non-null float64
dtypes: float64(4), int64(3), object(5)

from sklearn.preprocessing import MinMaxScaler

# 對數值資料做標準化
scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(df[['買進(張)', '賣出(張)', '買賣超(張)', '開盤價', '最高價', '最低價', '收盤價', '成交量']])

引入ConvLSTM的模型要用到的工具

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import ConvLSTM2D, Dense, Flatten
from tensorflow.keras.optimizers import Adam

# 創建時間序列資料
def create_sequences(data, time_steps=1):
    X, y = [], []
    for i in range(len(data)-time_steps):
        X.append(data[i:(i+time_steps)])
        y.append(data[i+time_steps, -1]) 
    return np.array(X), np.array(y)
    
time_steps = 10
X, y = create_sequences(scaled_data, time_steps)

把資料重新塑形

# 重塑以適應 ConvLSTM 輸入
X = X.reshape((X.shape[0], time_steps, 1, X.shape[2], 1))
# 建立 ConvLSTM 模型
model = Sequential([
    ConvLSTM2D(filters=64, kernel_size=(1, 2), input_shape=(time_steps, 1, X.shape[3], 1), return_sequences=True),
    ConvLSTM2D(filters=32, kernel_size=(1, 2), return_sequences=False),
    Flatten(),
    Dense(50, activation='relu'),
    Dense(1)
])

model.compile(optimizer=Adam(learning_rate=0.001), loss='mse')
model.summary()

# 訓練模型
history = model.fit(X, y, epochs=50, batch_size=32, validation_split=0.1)

# 預測
predictions = model.predict(X)

---> X = X.reshape((X.shape[0], time_steps, 1, X.shape[2], 1))
IndexError: tuple index out of range

結果遇到了錯誤,看起來原因是資料維度的地方發生了問題

不太確定要怎麼改,跟chatGPT討論一下:

在重塑數據時,X.shape 沒有你期望的四個維度導致的。

  1. 首先,檢查 create_sequences 函數的輸出,確保 X 和 y 的形狀正確。
print(X.shape)  # 應該是 (樣本數, time_steps, 特徵數)
print(y.shape)  # 應該是 (樣本數,)

2.根據 X 的形狀進行重塑。如果 X 的形狀是 (樣本數, time_steps, 特徵數),那麼你需要將其重塑為 (樣本數, time_steps, 1, 特徵數, 1)。

# 創建時間序列數據
def create_sequences(data, time_steps=1):
    X, y = [], []
    for i in range(len(data)-time_steps):
        X.append(data[i:(i+time_steps)])
        y.append(data[i+time_steps, -1]) 
    return np.array(X), np.array(y)

time_steps = 10
X, y = create_sequences(scaled_data, time_steps)

# 檢查一下 X 的形狀
print("Original X shape:", X.shape)

# 重塑資料適應 ConvLSTM 輸入
X = X.reshape((X.shape[0], time_steps, 1, X.shape[2], 1))

# 再檢查 X 的形狀
print("Reshaped X shape:", X.shape)

看了chatGPT給的修改過的程式碼,真的很想吐槽,大哥您根本就沒改@@''
你就只是在中間加入Print阿。

按照修改改了一下,結果跑出了一個新的錯誤??? (剛才怎麼沒有跑出來)
錯誤太長,只放錯誤的原因和錯誤位置就好。

---> scaled_data = scaler.fit_transform(df[['買進(張)', '賣出(張)', '買賣超(張)', '開盤價', '最高價', '最低價', '收盤價', '成交量']])
ValueError: could not convert string to float: '2,795'"

沒辦法把字串轉換成浮點數,因為資料裡面有物件(object)的型態,

dtypes: float64(4), int64(3), object(5)
0 日期 3183 non-null object
1 券商代碼 3183 non-null object
2 買進(張) 3183 non-null object
3 賣出(張) 3183 non-null object
4 買賣超(張) 3183 non-null object

主要原因是股價資料爬下來存進excel時,

張數破千張的買賣張,中間會計格式的逗點,讓資料型態呈現為非數值

日期 券商代碼 買進(張) 賣出(張) 買賣超(張) 橫坐標 縱坐標 開盤價 最高價 最低價 收盤價 成交量
ex. 2024/05/16 8560 1,222 1,154 68 301804 2771069 130 134.5 118 120 95284.736

先在標準化之前進行處理

# 移除數值欄位中的非數值字符,再轉換為float格式
cols_to_convert = ['買進(張)', '賣出(張)', '買賣超(張)', '開盤價', '最高價', '最低價', '收盤價', '成交量']
for col in cols_to_convert:
    df[col] = df[col].astype(str).str.replace(',', '').astype(float)

每日記錄:
先改到這邊,感覺自己對ConvLSTM非常不熟,只有上課和看文章學到的概念,不太懂怎麼應用 0..0
明天找程式強者我朋友討論一下。

參考文章&資料來源

  1. 座標轉換-廢棄物棄置案件管理系統
  2. 台灣常用坐標系系統
  3. TWD97 to Longitude/latitude
  4. 【Python时序预测系列】基于ConvLSTM实现单变量时间序列预测
  5. How to apply the ConvLSTM layers-StackOverflow
  6. IndexError: tuple index out of range (LSTM)

上一篇
含金量滿滿的文章? Step(4/4):關鍵分點的籌碼資訊,你也可以自己拿!
下一篇
配合ConvLSTM模型,資料應該是什麼形狀?
系列文
時空序列分析-關鍵籌碼分析31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言