基於Python程式碼的相關性熱力圖,VIF共線性診斷圖及殘差四圖的使用及解釋

一眉师傅發表於2024-03-23

注:熱力圖共線性診斷圖易看易解釋,這裡不再闡述

殘差四圖(Residuals vs Fitted Plot,Normal Q-Q Plot,Scale-Location Plot,Cook's Distance Plot)

各種現象的相關解釋如下:

  1. Residuals vs Fitted Plot(殘差與擬合值散點圖):
    這個圖用於幫助檢驗迴歸模型的線性關係假設。在這個圖中,我們會將模型的殘差(觀測值與預測值之間的差異)與模型的擬合值(預測值)進行比較,理想情況下,殘差應該隨著擬合值的增加而隨機分佈在0附近,沒有明顯的模式或趨勢。如果殘差呈現出某種趨勢,可能意味著模型的線性關係假設不成立。

  2. Normal Q-Q Plot(正態機率圖):
    這個圖用於檢驗模型殘差是否符合正態分佈。在這個圖中,殘差的排序值會和一個理論的正態分佈進行比較,理想情況下,殘差點應該落在一條直線上,如果殘差點偏離直線,可能表示殘差不符合正態分佈。

  3. Scale-Location Plot(標準化殘差與擬合值的散點圖):
    這個圖也稱為“Spread-Location”圖,用於檢驗模型的同方差性假設。在這個圖中,我們會將標準化殘差的絕對值開方(以消除負值)與擬合值進行比較,理想情況下,點應該在一條水平線上分佈,如果點呈現出聚集或特定的模式,可能意味著同方差性不成立。

  4. Cook’s Distance Plot(庫克距離圖):
    這個圖用於識別在迴歸模型中對結果產生顯著影響的個別觀測值。Cook’s Distance是一種衡量資料點影響的統計量,這個圖可以顯示每個資料點的Cook’s Distance值,通常我們會關注那些Cook’s Distance遠高於平均水平的資料點,它們可能是影響模型準確性的異常值或離群點。

綜合使用這四種圖可以幫助分析師評估線性迴歸模型的準確性、假設是否成立以及是否存在異常值,從而提高建模的質量和可靠性。

1>封裝好的程式碼如下:

基於Python程式碼的相關性熱力圖,VIF共線性診斷圖及殘差四圖的使用及解釋
import matplotlib.pyplot as plt
import seaborn as sns
import statsmodels.formula.api as smf
import pandas as pd
from statsmodels.formula.api import ols
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

def Corr_heatmap(data):
    # import matplotlib.pyplot as plt
    # import seaborn as sns
    #相關性分析
    print(data.corr())
    #畫出熱力圖
    plt.figure(figsize=(7,5),dpi=128)
    sns.heatmap(data.corr().round(2), cmap='coolwarm', annot=True, annot_kws={"size": 10})
    plt.savefig('相關係數熱力圖.jpg')
    plt.show()

def VIF_calculate(data, y_name):
    # import statsmodels.formula.api as smf
    # import pandas as pd
    x_cols = data.columns.to_list()
    x_cols.remove(y_name)

    def vif(df_exog, exog_name):
        exog_use = list(df_exog.columns)
        exog_use.remove(exog_name)
        model = smf.ols(f"{exog_name}~{'+'.join(list(exog_use))}", data=df_exog).fit()
        return 1. / (1. - model.rsquared)

    df_vif = pd.DataFrame()
    for x in x_cols:
        df_vif.loc['VIF', x] = vif(data[x_cols], x)

    df_vif.loc['tolerance'] = 1 / df_vif.loc['VIF']
    df_vif = df_vif.T.sort_values('VIF', ascending=False)
    df_vif.loc['mean_vif'] = df_vif.mean()
    # from statsmodels.formula.api import ols
    def vif(data, col_i):
        """
        df: 整份資料
        col_i:被檢測的列名
        """
        cols = list(data.columns)
        cols.remove(col_i)
        cols_noti = cols
        formula = col_i + '~' + '+'.join(cols_noti)
        r2 = ols(formula, data).fit().rsquared
        # 其實就是多元線性迴歸建模步驟,只是取出了引數 R 平方而已
        test = 1. / (1. - r2)
        return test

    print('vif檢驗結果')
    print('  變數            vif檢驗值')
    vif_value = []
    for i in data:
        print(i.center(7) + '    ', str(vif(data=data, col_i=i)))
        vif_value.append(vif(data=data, col_i=i))
    plt.bar([x for x in data], vif_value, color='teal')
    plt.axhline(10, color='red', lw=2, label="參考線")
    plt.title("VIF檢驗結果")
    plt.xlabel("變數")
    plt.ylabel("VIF_value")
    plt.show()
    return print(df_vif)

def Residuals_plot(predicts,residuals):
    import numpy as np
    import matplotlib.pyplot as plt
    import statsmodels.api as sm
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False

    plt.subplots(2, 2, figsize=(8, 8), dpi=128)
    plt.subplot(221)
    plt.scatter(predicts, residuals)
    plt.xlabel('Fitted Value')
    plt.ylabel('Residual')
    plt.title('(a)Residuals vs Fitted Plot', fontsize=15)
    plt.axhline(0, ls='--')

    ax2 = plt.subplot(222)
    pplot = sm.ProbPlot(residuals, fit=True)
    pplot.qqplot(line='r', ax=ax2, xlabel='Theoretical Quantiles', ylabel='Sample Quantiles')
    ax2.set_title('(b)Normal Q-Q Plot', fontsize=15)

    #建立一個序列來表示觀測序號:
    obs = np.arange(1, len(residuals) + 1)
    #繪製scale-location圖
    ax3 = plt.subplot(223)
    ax3.scatter(np.sqrt(obs), np.abs(residuals))
    ax3.set_xlabel("√Observation Number")
    ax3.set_ylabel("|Residuals|")
    ax3.set_title("(c)Scale-Location Plot")

    #計算庫克距離並繪製庫克距離圖:
    model = sm.OLS(residuals, sm.add_constant(obs)).fit()  # 應用OLS迴歸模型
    influence = model.get_influence()
    cooks_dist = influence.cooks_distance[0]

    ax4=plt.subplot(224)
    ax4.scatter(obs, cooks_dist)
    ax4.axhline(y=4*cooks_dist.mean(), linestyle='dashed')
    ax4.set_xlabel("Observation")
    ax4.set_ylabel("Cook's Distance")
    ax4.set_title("(d)Cook's Distance Plot")
    plt.tight_layout()
    plt.show()
Multivariable_statistics.py

2>對上述程式碼進行簡單呼叫:

import Multivariable_statistics as Ms
import numpy as np
import pandas as pd
p=np.linspace(20,60,100)   #預測值
r=np.random.uniform(-1,1,100)   #殘差值
print(r)
Ms.Residuals_plot(residuals=r,predicts=p)   #殘差四圖


#對於其他兩個圖的使用教程,以p,r資料為例
#得到一組100*2的資料
df=pd.DataFrame(p,columns=['p'])
df['r']=r
df['y']=np.linspace(50,80,100)   #預測值
print(df)

Ms.Corr_heatmap(df)    #皮爾遜相關係數的熱力圖
Ms.VIF_calculate(df,'y')        #VIF檢驗值以及圖

3>結果圖如下:

相關文章