Seaborn:标注线性回归方程

Seaborn: annotate the linear regression equation

我尝试为波士顿数据集拟合 OLS。我的图表如下所示。

如何在直线上方或图中某处标注线性回归方程?如何打印 Python?

中的方程式

我对这个领域还很陌生。目前正在探索 python。如果有人可以帮助我,那将加快我的学习曲线。

非常感谢!

我也试过了。

我的问题是 - 如何以方程格式在图中注释以上内容?

您可以使用线性拟合系数制作图例,如下例所示:

import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats

tips = sns.load_dataset("tips")

# get coeffs of linear fit
slope, intercept, r_value, p_value, std_err = stats.linregress(tips['total_bill'],tips['tip'])

# use line_kws to set line label for legend
ax = sns.regplot(x="total_bill", y="tip", data=tips, color='b', 
 line_kws={'label':"y={0:.1f}x+{1:.1f}".format(slope,intercept)})

# plot legend
ax.legend()

plt.show()

如果你使用更复杂的拟合函数,你可以使用乳胶通知:https://matplotlib.org/users/usetex.html

要在使用 seaborn lmplot 的情况下注释多个线性回归线,您可以执行以下操作。

 import pandas as pd 
 import seaborn as sns
 import matplotlib.pyplot as plt 

df = pd.read_excel('data.xlsx')
# assume some random columns called EAV and PAV in your DataFrame 
# assume a third variable used for grouping called "Mammal" which will be used for color coding
p = sns.lmplot(x=EAV, y=PAV,
        data=df, hue='Mammal', 
        line_kws={'label':"Linear Reg"}, legend=True)

ax = p.axes[0, 0]
ax.legend()
leg = ax.get_legend()
L_labels = leg.get_texts()
# assuming you computed r_squared which is the coefficient of determination somewhere else
slope, intercept, r_value, p_value, std_err = stats.linregress(df['EAV'],df['PAV'])
label_line_1 = r'$y={0:.1f}x+{1:.1f}'.format(slope,intercept)
label_line_2 = r'$R^2:{0:.2f}$'.format(0.21) # as an exampple or whatever you want[!
L_labels[0].set_text(label_line_1)
L_labels[1].set_text(label_line_2)

结果:

更简单的语法..相同的结果。

    import seaborn as sns
    import matplotlib.pyplot as plt
    from scipy import stats
        
    slope, intercept, r_value, pv, se = stats.linregress(df['alcohol'],df['magnesium'])
        
    sns.regplot(x="alcohol", y="magnesium", data=df, 
      ci=None, label="y={0:.1f}x+{1:.1f}".format(slope, intercept)).legend(loc="best")

我扩展了@RMS 的解决方案以适用于 multi-panel lmplot 示例(使用来自 sleep-deprivation study (Belenky et. al., J Sleep Res 2003 的数据)在 pydataset 中可用)。这允许一个人拥有 axis-specific legends/labels 而不必使用 regplotplt.subplots.

Edit:添加了第二种方法,使用 FacetGrid() 中的 map_dataframe() 方法,如 the answer by Marcos here.

中所建议
import numpy as np
import scipy as sp
import pandas as pd
import seaborn as sns
import pydataset as pds
import matplotlib.pyplot as plt

# use seaborn theme
sns.set_theme(color_codes=True)

# Load data from sleep deprivation study (Belenky et al, J Sleep Res 2003)
#  ['Reaction', 'Days', 'Subject'] = [reaction time (ms), deprivation time, Subj. No.]
df = pds.data("sleepstudy")
# convert integer label to string
df['Subject'] = df['Subject'].apply(str)

# perform linear regressions outside of seaborn to get parameters
subjects = np.unique(df['Subject'].to_numpy())
fit_str = []
for s in subjects:
    ddf = df[df['Subject'] == s]
    m, b, r_value, p_value, std_err = \
        sp.stats.linregress(ddf['Days'],ddf['Reaction'])
    fs = f"y = {m:.2f} x + {b:.1f}"
    fit_str.append(fs)

method_one = False
method_two = True
if method_one:
    # Access legend on each axis to write equation
    #
    # Create 18 panel lmplot with seaborn
    g = sns.lmplot(x="Days", y="Reaction", col="Subject",
                   col_wrap=6, height=2.5, data=df,
                   line_kws={'label':"Linear Reg"}, legend=True)
    # write string with fit result into legend string of each axis
    axes = g.axes # 18 element list of axes objects
    i=0
    for ax in axes:
        ax.legend()  # create legend on axis
        leg = ax.get_legend()
        leg_labels = leg.get_texts()
        leg_labels[0].set_text(fit_str[i])
        i += 1
elif method_two:
    # use the .map_dataframe () method from FacetGrid() to annotate plot
    #   (answer by @Marcos)
    #
    # Create 18 panel lmplot with seaborn
    g = sns.lmplot(x="Days", y="Reaction", col="Subject",
                   col_wrap=6, height=2.5, data=df)
    def annotate(data, **kws):
        m, b, r_value, p_value, std_err = \
            sp.stats.linregress(data['Days'],data['Reaction'])
        ax = plt.gca()
        ax.text(0.5, 0.9, f"y = {m:.2f} x + {b:.1f}",
                horizontalalignment='center',
                verticalalignment='center',
                transform=ax.transAxes)
    g.map_dataframe(annotate)

# write figure to pdf
plt.savefig("sleepstudy_data_w-fits.pdf")

输出(方法 1)

输出(方法 2)

更新 2022-05-11:与绘图技术无关,事实证明,这种对数据的解释(以及提供的数据,例如 original R repository) is incorrect. See the reported issue here. 应在第 2-9 天进行拟合,对应于 0 到 7 天的睡眠剥夺(每晚睡眠 3 小时)。前三个数据点对应于训练和基线天数(每晚睡眠 8 小时)。