Я пытаюсь воспроизвести следующие результаты R в Python. В этом конкретном случае прогнозирующий навык R ниже, чем навык Python, но в моем опыте это обычно не так (отсюда и причина желать воспроизвести результаты в Python), поэтому, пожалуйста, игнорируйте эту деталь здесь.
Цель состоит в том, чтобы предсказать вид цветка («версиколор» 0 или «вирджиника» 1). У нас есть 100 маркированных образцов, каждый из которых состоит из 4 цветочных характеристик: длина чашелистика, ширина чашелистика, длина лепестка, ширина лепестка. Я разделил данные на обучающие (60% данных) и тестовые наборы (40% данных). 10-кратная перекрестная проверка применяется к обучающему набору для поиска оптимальной лямбды (оптимизированный параметр - «C» в scikit-learn).
Я использую glmnet в R с альфа-значением, установленным на 1 (для штрафа LASSO), а для python, scikit-learn Функция LogisticRegressionCV с решателем "liblinear" (единственный решатель, который может использоваться с штрафом L1). Метрики оценки, используемые в перекрестной проверке, одинаковы для обоих языков. Однако результаты модели как-то различны (перехваты и коэффициенты, найденные для каждого признака, сильно различаются).
Код R
library(glmnet)
library(datasets)
data(iris)
y <- as.numeric(iris[,5])
X <- iris[y!=1, 1:4]
y <- y[y!=1]-2
n_sample = NROW(X)
w = .6
X_train = X[0:(w * n_sample),] # (60, 4)
y_train = y[0:(w * n_sample)] # (60,)
X_test = X[((w * n_sample)+1):n_sample,] # (40, 4)
y_test = y[((w * n_sample)+1):n_sample] # (40,)
# set alpha=1 for LASSO and alpha=0 for ridge regression
# use class for logistic regression
set.seed(0)
model_lambda <- cv.glmnet(as.matrix(X_train), as.factor(y_train),
nfolds = 10, alpha=1, family="binomial", type.measure="class")
best_s <- model_lambda$lambda.1se
pred <- as.numeric(predict(model_lambda, newx=as.matrix(X_test), type="class" , s=best_s))
# best lambda
print(best_s)
# 0.04136537
# fraction correct
print(sum(y_test==pred)/NROW(pred))
# 0.75
# model coefficients
print(coef(model_lambda, s=best_s))
#(Intercept) -14.680479
#Sepal.Length 0
#Sepal.Width 0
#Petal.Length 1.181747
#Petal.Width 4.592025
Код Python
from sklearn import datasets
from sklearn.linear_model import LogisticRegressionCV
from sklearn.preprocessing import StandardScaler
import numpy as np
iris = datasets.load_iris()
X = iris.data
y = iris.target
X = X[y != 0] # four features. Disregard one of the 3 species.
y = y[y != 0]-1 # two species: 'versicolor' (0), 'virginica' (1). Disregard one of the 3 species.
n_sample = len(X)
w = .6
X_train = X[:int(w * n_sample)] # (60, 4)
y_train = y[:int(w * n_sample)] # (60,)
X_test = X[int(w * n_sample):] # (40, 4)
y_test = y[int(w * n_sample):] # (40,)
X_train_fit = StandardScaler().fit(X_train)
X_train_transformed = X_train_fit.transform(X_train)
clf = LogisticRegressionCV(n_jobs=2, penalty='l1', solver='liblinear', cv=10, scoring = ‘accuracy’, random_state=0)
clf.fit(X_train_transformed, y_train)
print clf.score(X_train_fit.transform(X_test), y_test) # score is 0.775
print clf.intercept_ #-1.83569557
print clf.coef_ # [ 0, 0, 0.65930981, 1.17808155] (sepal length, sepal width, petal length, petal width)
print clf.C_ # optimal lambda: 0.35938137
2 ответа
Проблема, с которой вы столкнулись, заключается в упорядочении наборов данных (обратите внимание, я не проверял код R, но я уверен, что это проблема). Если я запускаю ваш код, а затем запустить этот
print np.bincount(y_train) # [50 10]
print np.bincount(y_test) # [ 0 40]
Вы можете видеть, что тренировочный набор не является репрезентативным для тестового набора. Однако, если я внесу пару изменений в ваш код Python, то получу точность теста 0.9
.
from sklearn import datasets
from sklearn import preprocessing
from sklearn import model_selection
from sklearn.linear_model import LogisticRegressionCV
from sklearn.preprocessing import StandardScaler
import numpy as np
iris = datasets.load_iris()
X = iris.data
y = iris.target
X = X[y != 0] # four features. Disregard one of the 3 species.
y = y[y != 0]-1 # two species: 'versicolor' (0), 'virginica' (1). Disregard one of the 3 species.
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y,
test_size=0.4,
random_state=42,
stratify=y)
X_train_fit = StandardScaler().fit(X_train)
X_train_transformed = X_train_fit.transform(X_train)
clf = LogisticRegressionCV(n_jobs=2, penalty='l1', solver='liblinear', cv=10, scoring = 'accuracy', random_state=0)
clf.fit(X_train_transformed, y_train)
print clf.score(X_train_fit.transform(X_test), y_test) # score is 0.9
print clf.intercept_ #0.
print clf.coef_ # [ 0., 0. ,0., 0.30066888] (sepal length, sepal width, petal length, petal width)
print clf.C_ # [ 0.04641589]
Я должен обижаться с парой вещей здесь.
Во-первых, «для python - функция LogisticRegressionCV scikit-learn с решателем« liblinear »(единственный решатель, который может использоваться с штрафом L1)». Это явно ложно, если только вы не хотели это квалифицировать более определенным образом. Просто посмотрите на описания sklearn.linear_model
классы, и вы увидите несколько, которые конкретно упоминают L1. Я уверен, что другие позволят вам также реализовать это, но мне не очень хочется их считать.
Во-вторых, ваш метод разделения данных далеко не идеален. Посмотрите на ваши входные и выходные данные после разделения, и вы обнаружите, что в вашем разделении все тестовые образцы имеют целевые значения 1, в то время как цель 1 составляет только 1/6 вашей обучающей выборки. Этот дисбаланс, который не отражает распределение целей, приведет к тому, что ваша модель будет плохо подходить. Например, просто с помощью sklearn.model_selection.train_test_split
сразу после установки классификатора LogisticRegressionCV
точно так же, как вы это сделали, вы получите .92
Теперь все это говорит о том, что есть пакет glmnet для python, и вы можете повторить свои результаты с помощью этого пакет . Существует блог авторов этого проекта, в котором обсуждаются некоторые ограничения при попытке воссоздать результаты glmnet с помощью sklearn. В частности :
«В Scikit-Learn есть несколько решателей, похожих на glmnet, ElasticNetCV и LogisticRegressionCV, но у них есть некоторые ограничения. Первый работает только для линейной регрессии, а второй не обрабатывает штраф эластичной сети». - Билл Латтнер GLMNET для PYTHON
Похожие вопросы
Новые вопросы
python
Python - это многопарадигмальный, динамически типизированный, многоцелевой язык программирования. Он разработан для быстрого изучения, понимания и использования, а также для обеспечения чистого и единообразного синтаксиса. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Тем не менее, для вопросов о Python, связанных с версией, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas и NumPy) включите его в теги.