Помогите посчитать значение q2 для Leave-One-Out перекрестной проверки линейной регрессии?

Имеется вот такой код:

import pandas as pd 
import numpy as np
import seaborn as sns
%matplotlib inline
import matplotlib.pyplot as plt
Porphs_data = pd.read_excel('I:\\Porphyrins\\26_4-Descs_varI_22-3-20.xlsx', index_col=0)
y = Porphs_data.LogFi
X = Porphs_data.drop(['LogFi'], axis=1)
# Select upper triangle of correlation matrix
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))
# Find index of feature columns with correlation greater than 0.95
to_drop = [column for column in upper.columns if any(upper[column] > 0.95)]
# Drop features 
X = X.drop(Porphs_data[to_drop], axis=1)
X_train = X.drop(["(p-Br)4-TPP", "5,10-NO2-etioporphyrin I", "Deuteroporphyrin-IX-DME", 
                  "N-CH3-Octaethylporphyrin", "Porphine"], axis=0)
y_train = y.drop(["(p-Br)4-TPP", "5,10-NO2-etioporphyrin I", "Deuteroporphyrin-IX-DME", 
                  "N-CH3-Octaethylporphyrin", "Porphine"], axis=0)
X_test = X.loc[["(p-Br)4-TPP", "5,15-NO2-etioporphyrin I", "Deuteroporphyrin-IX-DME", 
                  "N-CH3-Octaethylporphyrin", "Porphine"]]
y_test = y.loc[["(p-Br)4-TPP", "5,10-NO2-etioporphyrin I", "Deuteroporphyrin-IX-DME", 
                  "N-CH3-Octaethylporphyrin", "Porphine"]]
from sklearn import linear_model
lm = linear_model.LinearRegression()
lm.fit(X_train, y_train)

Получаем коэффициент детерминации:

from sklearn.metrics import r2_score
y_pred = lm.predict(X_train)
r2_score(y_train, y_pred)

Пытаюсь получить значение q2 для leave-one-out перекрестной проверки:

from sklearn.model_selection import LeaveOneOut
from sklearn.linear_model import LinearRegression
loo_lm = LinearRegression(lm, LeaveOneOut())
loo_lm.fit(X_train, y_train)
loo_lm.score(X_train, y_train)                         

Но получаю такое же значение как и для коэффициента детерминации для тренировочной выборки.

Другой способ посчитать q2:

from sklearn.model_selection import cross_val_score
cvs=cross_val_score(lm, X_train, y_train, cv=21)
cvs
mean_cross_val_score = cvs.mean()
mean_cross_val_score

выдает ошибку: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples.

Пожалуйста, помогите посчитать q2 для leave-one-out перекрестной проверки!

PS Примеры X и y. Вот X:

    Eig02_EA(dm)    MATS1e  HOMO-LUMO_Gap   SpMax4_Bh(p)    SAdon
compound                    
(m-Cl)4-TPP 0.00    -0.040  2.74    3.86    33.6
(o-Cl)4-TPP 0.00    -0.040  2.80    3.86    33.6
(o-F)4-TPP  0.00    -0.026  2.75    3.84    33.6
(p-Cl)4-TPP 0.00    -0.040  2.69    3.86    33.6

Вот y:

compound
(m-Cl)4-TPP                                  1.908485
(o-Cl)4-TPP                                  1.924279
(o-F)4-TPP                                   1.851258
(p-Cl)4-TPP                                  1.851258

Ответы (3 шт):

Автор решения: Andrey Buglak

Воспользовавшись советами MaxU и CrazyElf, собрал вот такой код:

from sklearn.model_selection import LeaveOneOut
score_list = []
loo = LeaveOneOut()
skipped = 0
for train_index, test_index in loo.split(X):
    X_train, X_test = X.iloc[train_index], X.iloc[test_index]
    y_train, y_test = y.values[train_index], y.values[test_index]
    lm.fit(X_train, y_train)
    y_lm = lm.predict(X_test)
      skipped += 1
      continue
    score = score(np.array(y_test)[y_lm], np.array(y_lm)[y_lm])
    score_list.append(score)
print(np.mean(score_list))

Однако выдает ошибку

    skipped += 1
    ^
IndentationError: unexpected indent"```

→ Ссылка
Автор решения: CrazyElf

Попробуйте сделать примерно так:

from sklearn.model_selection import LeaveOneOut
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score

lr = LinearRegression()
loo = LeaveOneOut()
cvs=cross_val_score(lr, X_train, y_train, cv=loo)
print(cvs)
print(cvs.mean())

А что касается ошибки

UndefinedMetricWarning: R^2 score is not well-defined with less than two samples.

Вы понимаете, как работает LeaveOneOut в качестве кросс-валидации? Он по очереди откладывает из выборки один сэмпл, тренирует модель на остальной части выборки и потом считает score на этом отложенном сэмпле. При этом метрика sklearn.metrics.r2_score, которая видимо используется в данном случае для вычисления score, считает, что по одному сэмплу её нельзя вычислять. Так что вам надо определиться - либо метод кросс-валидации неправильный, либо метод вычисления score. Они между собой несовместимы.

→ Ссылка
Автор решения: Andrey Buglak

В итоге на researchgate мне посоветовали вот такой код:

from sklearn import linear_model
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import r2_score as r2
# Assuming you have X_train and y_train in a correct form
lm = linear_model.LinearRegression()
y_pred = cross_val_predict(lm, X_train, y_train, cv=len(X_train))
r2_score = r2(y_pred,y_train)
r2_score

Не знаю, правильно ли это. Но вроде работает.

→ Ссылка