如何为时间序列局部极值点绘制最佳拟合线或拟合多数点的线条
Hey there! Let's figure out how to add those fitted lines with uncertainty bands for your local minima and maxima in the time series plot. You're already halfway there with finding the extreme points—let's build on that code.
First, a quick note: Time series dates can't be directly used in statistical fitting functions (they need numerical values), so we'll convert datetime indices to matplotlib's numeric date format first. Then we'll compute the fit lines and their confidence intervals, just like the tutorial you mentioned.
Here's the updated code with explanations:
First, make sure you add the missing import for datetime at the top:
import datetime as dt from scipy import stats
Then, right after your existing code that finds the minima/maxima and plots the initial scatter points, add this:
# ---------------------- # Process Local Minima # ---------------------- # Extract valid minima points (drop NaNs) min_points = index_df.dropna(subset=['min'])[['min']].reset_index() # Convert dates to numerical values for fitting min_x_num = plt.date2num(min_points['Date']) min_y = min_points['min'] # Perform linear regression fit min_slope, min_intercept, _, _, min_std_err = stats.linregress(min_x_num, min_y) min_fit_line = min_slope * min_x_num + min_intercept # Calculate 95% confidence interval for the fit n_min = len(min_x_num) dof_min = n_min - 2 # degrees of freedom for linear fit t_critical = stats.t.ppf(0.975, dof_min) # 95% confidence level min_residuals = min_y - min_fit_line min_mse = np.mean(min_residuals ** 2) min_ci = t_critical * np.sqrt(min_mse * (1/n_min + (min_x_num - np.mean(min_x_num))**2 / np.sum((min_x_num - np.mean(min_x_num))**2))) # Convert numerical dates back to datetime for plotting min_x_dates = plt.num2date(min_x_num) # ---------------------- # Process Local Maxima # ---------------------- # Same steps for maxima max_points = index_df.dropna(subset=['max'])[['max']].reset_index() max_x_num = plt.date2num(max_points['Date']) max_y = max_points['max'] max_slope, max_intercept, _, _, max_std_err = stats.linregress(max_x_num, max_y) max_fit_line = max_slope * max_x_num + max_intercept n_max = len(max_x_num) dof_max = n_max - 2 max_residuals = max_y - max_fit_line max_mse = np.mean(max_residuals ** 2) max_ci = t_critical * np.sqrt(max_mse * (1/n_max + (max_x_num - np.mean(max_x_num))**2 / np.sum((max_x_num - np.mean(max_x_num))**2))) max_x_dates = plt.num2date(max_x_num) # ---------------------- # Final Plotting # ---------------------- plt.figure(figsize=(12, 6)) # Plot original price data plt.plot(index_df['Adj Close'].index, index_df['Adj Close'], label='S&P 500 Adj Close', alpha=0.5) # Plot extreme points plt.scatter(min_x_dates, min_y, c='r', label='Local Minima') plt.scatter(max_x_dates, max_y, c='g', label='Local Maxima') # Plot fit lines and confidence bands plt.plot(min_x_dates, min_fit_line, 'r--', label='Minima Fit Line') plt.fill_between(min_x_dates, min_fit_line - min_ci, min_fit_line + min_ci, color='r', alpha=0.2) plt.plot(max_x_dates, max_fit_line, 'g--', label='Maxima Fit Line') plt.fill_between(max_x_dates, max_fit_line - max_ci, max_fit_line + max_ci, color='g', alpha=0.2) # Format plot plt.title('S&P 500 with Local Extremes & Fitted Lines (95% Confidence)') plt.xlabel('Date') plt.ylabel('Adjusted Close Price') plt.legend() plt.xticks(rotation=45) plt.tight_layout() plt.show()
Key details to note:
- Date conversion: We use
plt.date2num()to turn datetime objects into numbers that fitting functions can work with, then convert back withplt.num2date()for plotting. - Confidence intervals: The shaded areas represent the 95% confidence range for the fit—this means we're 95% confident the true trend line lies within that band.
- Non-linear fits (optional): If you want a curved fit instead of linear, replace the
stats.linregresspart withnp.polyfit(e.g.,np.polyfit(min_x_num, min_y, 3)for a 3rd-degree polynomial). You can calculate confidence bands for polynomials using residual standard deviation as a simpler estimate if needed.
内容的提问来源于stack exchange,提问作者Yi Wen Edwin Ang

