問題代碼:數據集劃分方式不適合時間序列,會導致評估結果不可靠。
- 代碼在整體流程上是合理的,但針對時間序列數據,存在一個關鍵問題:使用train_test_split進行隨機劃分是不合適的。
- 時間序列的特殊性
-
風速數據屬于時間序列數據,其核心特點是數據具有時間依賴性(即未來的數據與歷史數據存在時間上的先后關聯)。而train_test_split的默認行為是隨機劃分數據(即使設置了random_state,本質還是隨機抽樣),這會導致:
- 測試集中可能包含 “時間上早于訓練集” 的數據
- 模型在訓練時可能 “見過” 未來的數據,造成數據泄露
- 最終的評估結果(如 RMSE、R2)不能真實反映模型對 “未來數據” 的預測能力(這是時間序列預測的核心目標)
-
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler# 1. 加載數據
data1 = pd.read_csv(r'data.csv')# 2. 確保 date_time 列是 datetime 類型
data1['date_time'] = pd.to_datetime(data1['date_time'], format='%Y/%m/%d %H:%M')# 3. 定義時間范圍并篩選數據
start_time = '2023-07-01 00:00:00'
end_time = '2024-06-30 18:00:00'
data1 = data1[(data1['date_time'] >= start_time) & (data1['date_time'] <= end_time)]# 4. 提取特征和目標列
X = data1[['ecmwf_wind']] # 特征列
y = data1['wind_obs'] # 目標列# 5. 數據集劃分(訓練集和測試集)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)# 6. 數據歸一化(最大最小歸一化)
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)# 7. 訓練簡單線性回歸模型
model = LinearRegression()
model.fit(X_train_scaled, y_train)# 8. 預測
y_pred = model.predict(X_test_scaled)# 9. 計算評價指標
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
mae = mean_absolute_error(y_test, y_pred)
mbe = np.mean(y_test - y_pred) # 平均偏差誤差
r2 = r2_score(y_test, y_pred)# 10. 輸出評價指標
print(f"RMSE: {rmse:.4f}")
print(f"MAE: {mae:.4f}")
print(f"MBE: {mbe:.4f}")
print(f"R2: {r2:.4f}")# 11. 數據可視化
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.5, label='Predicted vs Observed')
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], color='red', linestyle='--', label='Ideal Line')
plt.xlabel('Observed Wind Speed')
plt.ylabel('Predicted Wind Speed')
plt.title('Observed vs Predicted Wind Speed')
plt.legend()
plt.grid(True)
plt.show()
改進建議(針對時間序列劃分)
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler# 1. 加載數據
data1 = pd.read_csv(r'data.csv')# 2. 確保 date_time 列是 datetime 類型
data1['date_time'] = pd.to_datetime(data1['date_time'], format='%Y/%m/%d %H:%M')# 3. 定義時間范圍并篩選數據
start_time = '2023-07-01 00:00:00'
end_time = '2024-06-30 18:00:00'
data1 = data1[(data1['date_time'] >= start_time) & (data1['date_time'] <= end_time)]# 4. 按時間排序(時間序列分析的重要步驟)
data1 = data1.sort_values('date_time').reset_index(drop=True)# 5. 提取特征和目標列
X = data1[['ecmwf_wind']] # 特征列
y = data1['wind_obs'] # 目標列# 6. 時間序列數據集劃分(按時間順序,前75%訓練,后25%測試)
split_ratio = 0.75
split_idx = int(len(data1) * split_ratio)X_train, X_test = X.iloc[:split_idx], X.iloc[split_idx:]
y_train, y_test = y.iloc[:split_idx], y.iloc[split_idx:]# 7. 數據歸一化(最大最小歸一化)
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)# 8. 訓練簡單線性回歸模型
model = LinearRegression()
model.fit(X_train_scaled, y_train)# 9. 預測
y_pred = model.predict(X_test_scaled)# 10. 計算評價指標
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
mae = mean_absolute_error(y_test, y_pred)
mbe = np.mean(y_test - y_pred) # 平均偏差誤差
r2 = r2_score(y_test, y_pred)# 11. 輸出評價指標
print(f"RMSE: {rmse:.4f}")
print(f"MAE: {mae:.4f}")
print(f"MBE: {mbe:.4f}")
print(f"R2: {r2:.4f}")# 12. 預測值與觀測值對比可視化(帶時間維度)
plt.figure(figsize=(12, 6))
plt.plot(data1['date_time'].iloc[split_idx:], y_test, label='觀測風速', alpha=0.7)
plt.plot(data1['date_time'].iloc[split_idx:], y_pred, label='預測風速', linestyle='--')
plt.xlabel('時間')
plt.ylabel('風速')
plt.title('測試集風速預測對比')
plt.legend()
plt.grid(True)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()# 13. 散點圖可視化(預測值 vs 觀測值)
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.5, label='預測值 vs 觀測值')
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], color='red', linestyle='--', label='理想線')
plt.xlabel('觀測風速')
plt.ylabel('預測風速')
plt.title('觀測值與預測值對比')
plt.legend()
plt.grid(True)
plt.show()
繪圖展示中文顯示不了,設置matplotlib設置中文字體。
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScalerimport matplotlib as mpl# 設置中文字體 - 根據您的系統選擇
plt.rcParams['font.sans-serif'] = ['SimHei'] # 黑體,Windows
# plt.rcParams['font.sans-serif'] = ['Heiti TC'] # 黑體-繁,Mac
# plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei'] # 文泉驛正黑,Linux# 解決負號顯示問題
plt.rcParams['axes.unicode_minus'] = False# 或者使用全局設置
mpl.rc('font', family='SimHei') # Windows
# mpl.rc('font', family='Arial Unicode MS') # Mac# 1. 加載數據
data1 = pd.read_csv(r'data.csv')# 2. 確保 date_time 列是 datetime 類型
data1['date_time'] = pd.to_datetime(data1['date_time'], format='%Y/%m/%d %H:%M')# 3. 定義時間范圍并篩選數據
start_time = '2023-07-01 00:00:00'
end_time = '2024-06-30 18:00:00'
data1 = data1[(data1['date_time'] >= start_time) & (data1['date_time'] <= end_time)]# 4. 按時間排序(時間序列分析的重要步驟)
data1 = data1.sort_values('date_time').reset_index(drop=True)# 5. 提取特征和目標列
X = data1[['ecmwf_wind']] # 特征列
y = data1['wind_obs'] # 目標列# 6. 時間序列數據集劃分(按時間順序,前75%訓練,后25%測試)
split_ratio = 0.75
split_idx = int(len(data1) * split_ratio)X_train, X_test = X.iloc[:split_idx], X.iloc[split_idx:]
y_train, y_test = y.iloc[:split_idx], y.iloc[split_idx:]# 7. 數據歸一化(最大最小歸一化)
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)# 8. 訓練簡單線性回歸模型
model = LinearRegression()
model.fit(X_train_scaled, y_train)# 9. 預測
y_pred = model.predict(X_test_scaled)# 10. 計算評價指標
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
mae = mean_absolute_error(y_test, y_pred)
mbe = np.mean(y_test - y_pred) # 平均偏差誤差
r2 = r2_score(y_test, y_pred)# 11. 輸出評價指標
print(f"RMSE: {rmse:.4f}")
print(f"MAE: {mae:.4f}")
print(f"MBE: {mbe:.4f}")
print(f"R2: {r2:.4f}")# 12. 預測值與觀測值對比可視化(帶時間維度)
plt.figure(figsize=(12, 6))
plt.plot(data1['date_time'].iloc[split_idx:], y_test, label='觀測風速', alpha=0.7)
plt.plot(data1['date_time'].iloc[split_idx:], y_pred, label='預測風速', linestyle='--')
plt.xlabel('時間')
plt.ylabel('風速')
plt.title('測試集風速預測對比')
plt.legend()
plt.grid(True)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()# 13. 散點圖可視化(預測值 vs 觀測值)
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.5, label='預測值 vs 觀測值')
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], color='red', linestyle='--', label='理想線')
plt.xlabel('觀測風速')
plt.ylabel('預測風速')
plt.title('觀測值與預測值對比')
plt.legend()
plt.grid(True)
plt.show()