【问题标题】:How to plot a regression line on a timeseries line plot如何在时间序列线图上绘制回归线
【发布时间】:2021-11-09 05:31:05
【问题描述】:

我有一个关于斜率值的问题,我计算如下:

import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt
import datetime as dt
import numpy as np

df = yf.download('aapl', '2015-01-01', '2021-01-01')
df.rename(columns = {'Adj Close' : 'Adj_close'}, inplace= True)

x1 = pd.Timestamp('2019-01-02')
x2 = df.index[-1]
y1 = df[df.index == x1].Adj_close[0]
y2 = df[df.index == x2].Adj_close[0]

slope = (y2 - y1)/ (x2 - x1).days
angle = round(np.rad2deg(np.arctan2(y2 - y1, (x2 - x1).days)), 1)

fig, ax1 = plt.subplots(figsize= (15, 6))
ax1.grid(True, linestyle= ':')
ax1.set_zorder(1)
ax1.set_frame_on(False)
ax1.plot(df.index, df.Adj_close, c= 'k', lw= 0.8)
ax1.plot([x1, x2], [y1, y2], c= 'k')


ax1.set_xlim(df.index[0], df.index[-1])
plt.show()

它返回坡度的角度值为 7.3 度。看图表看起来不正确:

它看起来接近 45 度。这里有什么问题?

这是我需要计算角度的线:

【问题讨论】:

    标签: python pandas matplotlib scikit-learn time-series


    【解决方案1】:
    • OP 中的实现不是确定或绘制线性模型的正确方法。因此,绕过了确定绘制线的角度的问题,并展示了一种更严格的绘制回归线的方法。
    • 可以通过将日期时间日期转换为序数来添加回归线。 可以使用sklearn 计算模型,或使用seaborn.regplot 添加到图中,如下所示。
    • pandas.DataFrame.plot绘制完整数据
    • python 3.8.11pandas 1.3.2matplotlib 3.4.3seaborn 0.11.2sklearn 0.24.2 中测试

    进口和数据

    import yfinance as yf
    import pandas as pd
    import seaborn as sns
    import matplotlib.pyplot as plt
    import numpy as np
    from sklearn.linear_model import LinearRegression
    
    # download the data
    df = yf.download('aapl', '2015-01-01', '2021-01-01')
    
    # convert the datetime index to ordinal values, which can be used to plot a regression line
    df.index = df.index.map(pd.Timestamp.toordinal)
    
    # display(df.iloc[:5, [4]])
            Adj Close
    Date             
    735600  24.782110
    735603  24.083958
    735604  24.086227
    735605  24.423975
    735606  25.362394
    
    # convert the regression line start date to ordinal
    x1 = pd.to_datetime('2019-01-02').toordinal()
    
    # data slice for the regression line
    data=df.loc[x1:].reset_index()
    

    使用 seaborn 绘制回归线

    • 使用seaborn.regplot 无需计算即可将回归线添加到数据的折线图中。
    • 将 x 轴标签转换为日期时间格式
    • 如果您需要调整端点,请使用 xticks 和标签。
    # plot the Adj Close data
    ax1 = df.plot(y='Adj Close', c='k', figsize=(15, 6), grid=True, legend=False,
                  title='Adjusted Close with Regression Line from 2019-01-02')
    
    # add a regression line
    sns.regplot(data=data, x='Date', y='Adj Close', ax=ax1, color='magenta', scatter_kws={'s': 7}, label='Linear Model', scatter=False)
    
    ax1.set_xlim(df.index[0], df.index[-1])
    
    # convert the axis back to datetime
    xticks = ax1.get_xticks()
    labels = [pd.Timestamp.fromordinal(int(label)).date() for label in xticks]
    ax1.set_xticks(xticks)
    ax1.set_xticklabels(labels)
    
    ax1.legend()
    
    plt.show()
    

    计算线性模型

    # create the model
    model = LinearRegression()
    
    # extract x and y from dataframe data
    x = data[['Date']]
    y = data[['Adj Close']]
    
    # fit the mode
    model.fit(x, y)
    
    # print the slope and intercept if desired
    print('intercept:', model.intercept_)
    print('slope:', model.coef_)
    
    intercept: [-90078.45713565]
    slope: [[0.1222514]]
    
    # calculate y1, given x1
    y1 = model.predict(np.array([[x1]]))
    
    print(y1)
    array([[28.27904095]])
    
    # calculate y2, given the last date in data
    x2 = data.Date.iloc[-1]
    y2 = model.predict(np.array([[x2]]))
    
    print(y2)
    array([[117.40030862]])
    
    # this can be added to `ax1` with
    ax1 = df.plot(y='Adj Close', c='k', figsize=(15, 6), grid=True, legend=False,
                  title='Adjusted Close with Regression Line from 2019-01-02')
    ax1.plot([x1, x2], [y1[0][0], y2[0][0]], label='Linear Model', c='magenta')
    ax1.legend()
    

    斜坡角度

    • 这是axes 的方面的工件,它不等于xy。当坡向相等时,看到坡度为 7.0 度。
    x = x2 - x1
    y = y2[0][0] - y1[0][0]
    slope = y / x
    
    print(round(slope, 7) == round(model.coef_[0][0], 7))
    [out]:
    True
    
    angle = round(np.rad2deg(np.arctan2(y, x)), 1)
    print(angle)
    [out]:
    7.0
    
    # given the existing plot
    ax1 = df.plot(y='Adj Close', c='k', figsize=(15, 6), grid=True, legend=False,
                  title='Adjusted Close with Regression Line from 2019-01-02')
    ax1.plot([x1, x2], [y1[0][0], y2[0][0]], label='Linear Model', c='magenta')
    
    # make the aspect equal
    ax1.set_aspect('equal', adjustable='box')
    

    【讨论】:

    • 好的,知道了。就是因为人物的长宽比,感觉应该有更大的角度。
    猜你喜欢
    • 1970-01-01
    • 2020-10-19
    • 2021-04-14
    • 2021-07-18
    • 1970-01-01
    • 2016-05-12
    • 2013-10-13
    • 2017-11-05
    相关资源
    最近更新 更多