[PYTHON] [Régression linéaire] À propos du nombre de variables explicatives et du coefficient de détermination (degré de liberté ajusté)

en premier

L'auteur décrit les variables explicatives de la régression linéaire. "Il vaut mieux ne pas utiliser de variables sans rapport avec la variable objective d'apprentissage" (* 1) J'ai l'image. Cependant, tout en étudiant l'analyse de régression linéaire, J'ai appris que le coefficient de détermination a les propriétés suivantes.

"Lorsqu'une variable explicative est ajoutée, il est peu probable que le coefficient de détermination soit plus bas qu'avant l'ajout. (Par conséquent, la comparaison de précision des modèles avec différents nombres de variables explicatives utilise le" coefficient de détermination ajusté en liberté ". ) "(* 2)

Connaissant ses propriétés, l'auteur a voulu vérifier le [Résumé] suivant.

Aperçu

Concernant l'hypothèse de l'auteur (* 1) et la nature du coefficient de détermination (* 2), j'ai essayé de vérifier les deux points suivants (①, ②) (en faisant effectivement un modèle). Cet article décrit la méthode de vérification et les résultats.

① Comparaison des coefficients de décision → Lorsqu'une variable explicative sans rapport avec la variable objectif est ajoutée, son coefficient de détermination ne tombe pas en dessous du coefficient de détermination avant l'addition.

(2) Comparaison des coefficients de décision ajustés en liberté → Dans le cas du coefficient de détermination ajusté en degrés, la valeur n'est-elle pas plus élevée "avant d'ajouter" une variable sans rapport avec la variable objectif?

supposition

[Régression linéaire] Une méthode pour exprimer la variable objective par "connexion de premier ordre (connexion linéaire) des variables explicatives" par rapport aux variables explicatives et aux variables objectives existantes. Puisqu'il est exprimé par une connexion linéaire, le résultat exprimé (valeur estimée) est un graphique droit. Normdist_regression.png

[Facteur de décision] Le modèle de régression linéaire créé est un indice indiquant «la qualité de l'ajustement pour les données» et est exprimé par la formule suivante.  $ R^{2}=1-\dfrac {\sum e^{2}}{\sum \left( y-\overline {y}\right) ^{2}} $

$ {\ sum e ^ {2}}: Variation résiduelle (somme des carrés de la différence entre la variable objective et la valeur estimée) $ $ {\ sum \ left (y- \ override {y} \ right) ^ {2}}: Variation totale (somme des carrés de la différence entre la variable objectif et sa moyenne) $

[Facteur de décision ajusté] Un indice qui ajoute le nombre de variables explicatives (k) au coefficient de détermination. Comme pour le coefficient de décision, il indique «la qualité de l'ajustement pour les données».  $ {\widehat {R}^{2}}=1-\dfrac {n-1}{n-k}\left( 1-R^{2}\right) $

$ {n}: nombre de données $ $ {k}: nombre de variables explicatives $

Détails de vérification

Les deux points de vérification (① et ②) décrits dans le [Résumé] ci-dessus sont vérifiés par les méthodes suivantes.

[Données à préparer] (1) Variable explicative (liée à la variable objective) → Créé en utilisant des nombres aléatoires. La variable objectif est créée par la combinaison linéaire de cette variable. (2) Variable explicative (quelle que soit la variable objective) → Créé en utilisant des nombres aléatoires. (3) Variable objective → Créer par combinaison de premier ordre des variables explicatives dans (1) ci-dessus.

① Comparaison des coefficients de décision → Vérifiez la différence entre les coefficients de détermination du <Modèle 1> et du <Modèle 2> ci-dessous (Modèle 2-Modèle 1). <Modèle 1> (n) Modèle créé avec les variables (1 à n) de la variable ci-dessus (1) <Modèle 2> (n x m) Pour un [modèle 1] ci-dessus Modèle créé avec des «variables explicatives utilisées pour le modèle» et «au-dessus des variables (2) (1 à m)»

(2) Comparaison des coefficients de décision ajustés en liberté → Pour la vérification ci-dessus (1), régler le "coefficient de décision" sur le "coefficient de décision ajusté en degré de liberté" et valider.

Procédure de vérification

(1) Variable explicative (liée à la variable objective)   → col_rel_[n](n=0〜10) (2) Variable explicative (quelle que soit la variable objective)   → col_no_rel_[m](m=0〜10) (3) Variable objective   → target

[2] Création de modèles → Créez le <Modèle 1> et le <Modèle 2> ci-dessus.

<Modèle 1> (n)   → nothing_ [n] _ [m]

[3] Calcul du coefficient de décision et du coefficient de décision ajusté en degré de liberté → Conserver les deux valeurs comme type de dict (comme valeur). Chaque nom de dict est le suivant.

Facteur de décision: dict_R2 Coefficient de décision ajusté en degré de liberté: dict_adjusted_R2

[4] Combinez les résultats agrégés en une seule trame de données [5] Créez des graphiques à deux lignes de pliage → L'axe vertical est le coefficient de détermination (ajusté pour la liberté), L'axe horizontal représente «le nombre des variables ci-dessus (2) utilisées pour l'apprentissage du modèle».

Code de vérification

experiment.jpynb


import random

import numpy as np
import pandas as pd

import matplotlib.pyplot as  plt

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

#[Paramètre]
#Valeur des semences
random.seed(10)

#Nombre de données
data_num = 10 ** 4

#Nombre d'objets(rel:Relatif à la variable objectif, non_rel:Non lié à la variable objective)
group_num = 10

dict_group_num = dict()
dict_group_num["rel"] = group_num #Lié à la variable objectif
dict_group_num["no_rel"] = group_num #Non lié à la variable objective

#[Création de données]
#Variable explicative
col_format = 'col_{group}_{index}'

all_data = pd.DataFrame({
    col_format.format(
        group = key
        , index = i
    ):[random.randint(0 , 1000) for _ in range(10 ** 4)] 
    for key , val in dict_group_num.items()
    for i in range(val)
})

#Variable objectif
w_list = [random.randint(1 , 10) for i in range(dict_group_num["rel"])]
target_series = pd.Series(np.zeros(data_num))
for i in range(dict_group_num["rel"]):
    w = w_list[i]
    col = col_format.format(
        group = "rel"
        , index = i
    )
    
    #Vérification
    print('-' * 50)
    print(target_series.head())
    print("w=" , w)
    print(all_data[col].head())
    print(w * all_data[col].head())    
    
    target_series = target_series + w * all_data[col]

    #Vérification
    display(target_series.head())
    
all_data['target'] = target_series

#[Création de modèle]
#Toutes les combinaisons de variables explicatives
dict_features = {}
key_format = "{type_}_{n}_{m}"

#1.「col_rel_x」(n)
type_ = "nothing"
for n in range(dict_group_num["rel"]):
    cols = [col_format.format(
                group = "rel"
                , index = i
            ) for i in range(n+1)]
    
    key = key_format.format(
        type_ = type_
        , n = n + 1
        , m = 0
    )
    dict_features[key] = cols

#2.「col_rel_x」(n)Et "col_no_rel_x」(m)
type_ = "contain"
for n in range(dict_group_num["rel"]):
    cols_rel = [col_format.format(
                group = "rel"
                , index = i
            ) for i in range(n+1)]
    for m in range(dict_group_num["no_rel"]):
        cols_no_rel = [col_format.format(
                    group = "no_rel"
                    , index = i
                ) for i in range(m+1)]
        cols = cols_rel + cols_no_rel
        key = key_format.format(
            type_ = type_
            , n = n + 1
            , m = m + 1
        )
        dict_features[key] = cols

#Vérification
type_ = "nothing"
print("-" * 50 , type_)
_dict = {key:val for key , val in dict_features.items() if key[:len(type_)] == type_}
print(list(_dict.items())[:5])

type_ = "contain"
print("-" * 50 , type_)
_dict = {key:val for key , val in dict_features.items() if key[:len(type_)] == type_}
print(list(_dict.items())[:5])

#La modélisation
dict_models = {}
for key , feature_cols in dict_features.items():
    #Diviser en variables explicatives et variables objectives
    train_X = all_data[feature_cols] 
    train_y = all_data['target']
    #La modélisation
    model = LinearRegression()
    model.fit(train_X , train_y)
    
    dict_models[key] = model
    
    #Vérification
    print("-" * 50)
    print("key={}".format(key))
    print(model.intercept_)
    print(model.coef_)

#Vérification
list(dict_models.keys())[:5]

#Coefficient de décision, coefficient de décision ajusté en degré de liberté
dict_R2 = {}
dict_adjusted_R2 = {}

for key , feature_cols in dict_models.items():
    #Acquisition de modèle
    model = dict_models[key]
    
    #Extraire toutes les données(numpy)
    feature_cols = dict_features[key]
    X = np.array(all_data[feature_cols])
    y = np.array(all_data["target"])
    
    #Coefficient de décision
    R2 = model.score(X , y)
    dict_R2[key] = R2
    
    #Coefficient de décision ajusté en degré de liberté
    n = data_num
    k = int(key.split("_")[1]) + int(key.split("_")[2])
    adjusted_R2 = 1 - ((n-1)/(n-k)) * (1 - R2)
    dict_adjusted_R2[key] = adjusted_R2

#【résultat de l'inspection】
R2_df = pd.DataFrame({
    "key":list(dict_R2.keys())
    , "R2":list(dict_R2.values())
})
adjusted_R2_df = pd.DataFrame({
    "key":list(dict_adjusted_R2.keys())
    , "adjusted_R2":list(dict_adjusted_R2.values())
})
result_df = pd.merge(R2_df , adjusted_R2_df , on="key" , how='outer')
result_df['rel_num'] = result_df["key"].str.split("_" , expand=True)[1].astype(int)
result_df['no_rel_num'] = result_df["key"].str.split("_" , expand=True)[2].astype(int)

#Vérification
print(len(R2_df))
print(len(adjusted_R2_df))
print(len(result_df))
display(R2_df.head())
display(adjusted_R2_df.head())
display(result_df.head())

#[Création graphique]
#Coefficient de décision
value = "R2"
fig = plt.figure(figsize=(10,10))

for i in range(dict_group_num["rel"]):
    rel_num = i + 1
    df = result_df.query("rel_num == {}".format(rel_num))
    base = df.query("no_rel_num == 0")[value]
    x = df["no_rel_num"]
    y = df[value].apply(lambda x:x - base)
    
    #Vérification
#     print("-" * 50)
#     print("base={}".format(base))
#     print("x={}".format(x))
#     print("y={}".format(y))
    
    plt.plot(x, y, marker = 'o' 
             , label="rel_num={}".format(rel_num))

plt.title("Diff of {}".format(value))
plt.legend(loc="upper left" , bbox_to_anchor=(1, 1))
plt.xlabel("no_rel_num")
plt.ylabel(value)
plt.grid()
plt.show()

#Enregistrer le graphique
fig.savefig("plot_R2.png ")

#Coefficient de décision ajusté en degré de liberté
value = "adjusted_R2"
fig = plt.figure(figsize=(10,10))

for i in range(dict_group_num["rel"]):
    rel_num = i + 1
    df = result_df.query("rel_num == {}".format(rel_num))
    base = df.query("no_rel_num == 0")[value]
    x = df["no_rel_num"]
    y = df[value].apply(lambda x:x - base)
    
    #Vérification
#     print("-" * 50)
#     print("base={}".format(base))
#     print("x={}".format(x))
#     print("y={}".format(y))
    
    plt.plot(x, y, marker = 'o' 
             , label="rel_num={}".format(rel_num))

plt.title("Diff of {}".format(value))
plt.legend(loc="upper left" , bbox_to_anchor=(1, 1))
plt.xlabel("no_rel_num")
plt.ylabel(value)
plt.grid()
plt.show()

#Enregistrer le graphique
fig.savefig("plot_adjusted_R2.png ")

résultat de l'inspection

[Graphique 1] Coefficient de décision Quel que soit le nombre de variables explicatives (rel_num) de «liées à la variable objective», le coefficient de décision augmente de façon monotone à mesure que le nombre de variables explicatives «non liées à la variable objective» à ajouter augmente. En d'autres termes, il a été confirmé que cela était conforme à la théorie. plot_R2.png [Graphique 2] Coefficient de décision ajusté à la liberté À propos du nombre de variables explicatives de «liées à la variable objective» Lorsqu'il y a 1 à 4, il vaut mieux ajouter la variable explicative «non liée à la variable objective». (Un à quatre ne suffit pas pour expliquer, et il semble préférable d'ajouter même un peu d'informations.) Quand il est de 9 à 10, c'est presque la même chose. (Il semble que 9 à 10 suffisent pour expliquer la variable objective.) En revanche, dans le cas de 5 à 8, le coefficient de détermination est plus élevé lorsque la variable explicative «sans rapport avec la variable objective» n'est pas ajoutée. Il a été confirmé que c'était comme prévu par l'auteur. plot_adjusted_R2.png

Résumé

Lors de la comparaison de modèles utilisant des coefficients de décision, il faut faire attention au nombre de variables explicatives utilisées pour la formation. Comme cela peut être confirmé par les résultats de la vérification, dans le coefficient de décision, si les variables explicatives sont "en grand nombre y compris l'autre partie", le coefficient de décision sera élevé (même si des variables non utilisables sont ajoutées). Ou égal. Par conséquent, afin d'effectuer une comparaison plus appropriée dans ce cas, il semble préférable d'utiliser le "coefficient de détermination ajusté en fonction du degré de liberté".

Recommended Posts

[Régression linéaire] À propos du nombre de variables explicatives et du coefficient de détermination (degré de liberté ajusté)
À propos de l'équation normale de la régression linéaire
Revoir le concept et la terminologie de la régression
Méthode d'évaluation du problème de régression d'apprentissage automatique (erreur quadratique moyenne et coefficient de décision)
À propos du comportement de copy, deepcopy et numpy.copy
"Régression linéaire" et "Version probabiliste de la régression linéaire" en Python "Régression linéaire de Bayes"
relation entre la série de nombres de Fibonacci et le nombre d'or
Implémentation python de la classe de régression linéaire bayésienne
Pensez à la nouvelle génération de Rack et WSGI
Notes personnelles sur l'intégration de vscode et anaconda