¶Ô±ÈÐÂÎļþ |
| | |
| | | import sys |
| | | import pandas as pd |
| | | import numpy as np |
| | | import matplotlib.pyplot as plt |
| | | from sklearn.preprocessing import MinMaxScaler |
| | | from sklearn.metrics import mean_absolute_error, mean_squared_error |
| | | |
| | | # Check numpy version |
| | | if np.__version__ < '1.23.5': |
| | | print(f"Warning: Current numpy version {np.__version__} may cause compatibility issues.") |
| | | print("Please upgrade numpy to version 1.23.5 or higher.") |
| | | |
| | | try: |
| | | import tensorflow as tf |
| | | print(f"TensorFlow version: {tf.__version__}") |
| | | except ImportError as e: |
| | | print("Error importing TensorFlow:", e) |
| | | sys.exit(1) |
| | | |
| | | # Check TensorFlow version |
| | | if tf.__version__ < '2.10.0': |
| | | print(f"Warning: Current TensorFlow version {tf.__version__} may cause compatibility issues.") |
| | | print("Please upgrade TensorFlow to version 2.10.0 or higher.") |
| | | |
| | | from tensorflow.keras.models import Model |
| | | from tensorflow.keras.layers import Input, Conv1D, LSTM, Dense, Layer |
| | | from tensorflow.keras.callbacks import EarlyStopping |
| | | |
| | | # ================================ |
| | | # 1. æ°æ®é¢å¤ç模å |
| | | # ================================ |
| | | class DataPreprocessor: |
| | | def __init__(self, file_path, target_col='Value'): |
| | | # ä½¿ç¨æ£ç¡®çç¼ç ååå |
| | | self.df = pd.read_csv(file_path, encoding='utf-8-sig', parse_dates=['DateTime'], index_col='DateTime') |
| | | self.target_col = target_col |
| | | self.scaler = MinMaxScaler(feature_range=(0, 1)) |
| | | |
| | | def preprocess(self, resample_freq='h'): # 使ç¨å°åç'h'代æ¿å¤§åç'H' |
| | | """æ°æ®ééæ ·ä¸å½ä¸å""" |
| | | # åªéæ©Valueåè¿è¡å¤ç |
| | | value_series = self.df[self.target_col] |
| | | |
| | | # å¤çéçé´ééæ · |
| | | df_resampled = value_series.resample(resample_freq).mean() |
| | | df_filled = df_resampled.fillna(method='ffill').fillna(method='bfill') # ååå¡«å
|
| | | |
| | | # å½ä¸åå¤ç |
| | | self.scaled_data = self.scaler.fit_transform(df_filled.values.reshape(-1, 1)) |
| | | self.dates = df_filled.index |
| | | return self.scaled_data, self.dates |
| | | |
| | | def create_sequences(self, data, look_back=72, pred_steps=120): |
| | | """å建çç£å¦ä¹ åºå""" |
| | | X, Y = [], [] |
| | | for i in range(len(data) - look_back - pred_steps): |
| | | X.append(data[i:(i + look_back)]) |
| | | Y.append(data[(i + look_back):(i + look_back + pred_steps)]) |
| | | return np.array(X), np.array(Y) |
| | | |
| | | # ================================ |
| | | # 2. 模åæå»ºæ¨¡å |
| | | # ================================ |
| | | class TemporalAttention(Layer): |
| | | """æ¶é´æ³¨æåæºå¶å±""" |
| | | def __init__(self, units): |
| | | super(TemporalAttention, self).__init__() |
| | | self.W1 = Dense(units) |
| | | self.W2 = Dense(units) |
| | | self.V = Dense(1) |
| | | |
| | | def call(self, encoder_output, lstm_output): |
| | | lstm_output = tf.expand_dims(lstm_output, 1) |
| | | score = self.V(tf.nn.tanh( |
| | | self.W1(encoder_output) + self.W2(lstm_output))) |
| | | attention_weights = tf.nn.softmax(score, axis=1) |
| | | context_vector = attention_weights * encoder_output |
| | | context_vector = tf.reduce_sum(context_vector, axis=1) |
| | | return context_vector, attention_weights |
| | | |
| | | class SalinityPredictor: |
| | | def __init__(self, look_back=72, pred_steps=120): |
| | | self.look_back = look_back # åå²çªå£ï¼å°æ¶ï¼ |
| | | self.pred_steps = pred_steps # 颿µæ¥é¿ï¼5天=120å°æ¶ï¼ |
| | | |
| | | def build_model(self): |
| | | """æå»ºCNN-LSTM-Attentionæ··åæ¨¡å""" |
| | | inputs = Input(shape=(self.look_back, 1)) |
| | | |
| | | # CNNç¹å¾æå |
| | | cnn = Conv1D(64, 3, activation='relu', padding='same')(inputs) |
| | | cnn = Conv1D(32, 3, activation='relu', padding='same')(cnn) |
| | | |
| | | # LSTMæ¶åºå»ºæ¨¡ |
| | | lstm_out = LSTM(128, return_sequences=True)(cnn) |
| | | lstm_out = LSTM(64, return_sequences=False)(lstm_out) |
| | | |
| | | # 注æåæºå¶ |
| | | context_vector, _ = TemporalAttention(64)(cnn, lstm_out) |
| | | |
| | | # è¾åºå± |
| | | outputs = Dense(self.pred_steps)(context_vector) |
| | | |
| | | self.model = Model(inputs=inputs, outputs=outputs) |
| | | self.model.compile(optimizer='adam', loss='mse') |
| | | return self.model |
| | | |
| | | def dynamic_split(self, data, dates, cutoff_date): |
| | | """卿ååè®ç»é""" |
| | | cutoff_idx = np.where(dates <= cutoff_date)[0][-self.look_back] |
| | | train_data = data[:cutoff_idx] |
| | | return train_data |
| | | |
| | | def train(self, X_train, y_train, epochs=200, batch_size=32): |
| | | """模åè®ç»""" |
| | | early_stop = EarlyStopping(monitor='val_loss', patience=20) |
| | | history = self.model.fit( |
| | | X_train, y_train, |
| | | epochs=epochs, |
| | | batch_size=batch_size, |
| | | validation_split=0.2, |
| | | callbacks=[early_stop], |
| | | verbose=1 |
| | | ) |
| | | return history |
| | | |
| | | def predict(self, last_sequence): |
| | | """éå½å¤æ¥é¢æµ""" |
| | | predictions = [] |
| | | current_seq = last_sequence.copy() |
| | | |
| | | for _ in range(self.pred_steps): |
| | | pred = self.model.predict(current_seq[np.newaxis, :, :], verbose=0) |
| | | predictions.append(pred[0][0]) # åªå第ä¸ä¸ªé¢æµå¼ |
| | | current_seq = np.roll(current_seq, -1, axis=0) |
| | | current_seq[-1] = pred[0][0] # 使ç¨åä¸ªé¢æµå¼æ´æ°åºå |
| | | |
| | | return np.array(predictions) |
| | | |
| | | # ================================ |
| | | # 3. 宿´æµç¨æ§è¡ |
| | | # ================================ |
| | | if __name__ == "__main__": |
| | | # åæ°é
ç½® |
| | | DATA_PATH = 'D:\opencv\.venv\ä¸åæ°´.csv' |
| | | CUTOFF_DATE = '2024-12-20 00:00' # ç¨æ·æå®å岿¶é´ç¹ |
| | | LOOK_BACK = 72 # 3天å岿°æ® |
| | | PRED_STEPS = 120 # 颿µ5天 |
| | | |
| | | # æ°æ®é¢å¤ç |
| | | preprocessor = DataPreprocessor(DATA_PATH) |
| | | scaled_data, dates = preprocessor.preprocess() |
| | | X, Y = preprocessor.create_sequences(scaled_data, LOOK_BACK, PRED_STEPS) |
| | | |
| | | # 模åæå»º |
| | | predictor = SalinityPredictor(LOOK_BACK, PRED_STEPS) |
| | | model = predictor.build_model() |
| | | model.summary() |
| | | |
| | | # 卿è®ç» |
| | | train_data = predictor.dynamic_split(scaled_data, dates, pd.to_datetime(CUTOFF_DATE)) |
| | | X_train, y_train = preprocessor.create_sequences(train_data, LOOK_BACK, PRED_STEPS) |
| | | history = predictor.train(X_train, y_train) |
| | | |
| | | # 颿µéªè¯ |
| | | cutoff_idx = np.where(dates <= pd.to_datetime(CUTOFF_DATE))[0][-1] |
| | | last_seq = scaled_data[cutoff_idx-LOOK_BACK:cutoff_idx] # 使ç¨åå²ç¹åçæ°æ®ä½ä¸ºè¾å
¥ |
| | | scaled_pred = predictor.predict(last_seq) |
| | | predictions = preprocessor.scaler.inverse_transform(scaled_pred.reshape(-1, 1)) |
| | | |
| | | # ç»æå¯è§å |
| | | true_dates = pd.date_range(start=pd.to_datetime(CUTOFF_DATE), periods=PRED_STEPS, freq='h') |
| | | plt.figure(figsize=(15, 6)) |
| | | |
| | | # ç»å¶åå²ç¹åçå岿°æ® |
| | | plt.plot(dates[cutoff_idx-PRED_STEPS:cutoff_idx], |
| | | preprocessor.scaler.inverse_transform(scaled_data[cutoff_idx-PRED_STEPS:cutoff_idx]), |
| | | 'b-', label='å岿°æ®ï¼åå²ç¹åï¼') |
| | | |
| | | # ç»å¶åå²ç¹åçå®é
æ°æ® |
| | | plt.plot(dates[cutoff_idx:cutoff_idx+PRED_STEPS], |
| | | preprocessor.scaler.inverse_transform(scaled_data[cutoff_idx:cutoff_idx+PRED_STEPS]), |
| | | 'g-', label='å®é
æ°æ®ï¼åå²ç¹åï¼') |
| | | |
| | | # ç»å¶é¢æµæ°æ® |
| | | plt.plot(true_dates, predictions, 'r--', label='颿µæ°æ®') |
| | | |
| | | # æ·»å åå²çº¿ |
| | | plt.axvline(x=pd.to_datetime(CUTOFF_DATE), color='k', linestyle='--', label='å岿¶é´ç¹') |
| | | |
| | | plt.title(f'çåº¦é¢æµå¯¹æ¯ï¼{CUTOFF_DATE}å5天ï¼') |
| | | plt.xlabel('æ¶é´') |
| | | plt.ylabel('ç度å¼') |
| | | plt.legend() |
| | | plt.grid(True) |
| | | plt.xticks(rotation=45) |
| | | plt.tight_layout() |
| | | plt.show() |
| | | |
| | | # æ§è½ææ |
| | | true_values = preprocessor.scaler.inverse_transform(scaled_data[cutoff_idx:cutoff_idx+PRED_STEPS]) |
| | | mae = mean_absolute_error(true_values, predictions) |
| | | rmse = np.sqrt(mean_squared_error(true_values, predictions)) |
| | | print(f'éªè¯ææ => MAE: {mae:.3f}, RMSE: {rmse:.3f}') |
| | | |
| | | # ================================ |
| | | # 4. 模åä¿åä¸å è½½ï¼å¯éï¼ |
| | | # ================================ |
| | | # model.save('salinity_predictor.h5') |
| | | # loaded_model = tf.keras.models.load_model('salinity_predictor.h5', custom_objects={'TemporalAttention': TemporalAttention}) |