LogisticRegression scikit学习协变量(列)顺序对训练很重要
Posted
技术标签:
【中文标题】LogisticRegression scikit学习协变量(列)顺序对训练很重要【英文标题】:LogisticRegression scikit learn covariate (column) order matters on training 【发布时间】:2018-06-01 06:00:09 【问题描述】:由于某种原因,协变量的顺序似乎与 scikit-learn 中的 LogisticRegression
分类器有关,这对我来说似乎很奇怪。我有 9 个协变量和一个二进制输出,当我更改列的顺序并调用 fit()
然后调用 predict_proba()
时,输出是不同的。下面的玩具示例
logit_model = LogisticRegression(C=1e9, tol=1e-15)
以下
logit_model.fit(df['column_2','column_1'],df['target'])
logit_model.predict_proba(df['column_2','column_1'])
array([[ 0.27387109, 0.72612891] ..])
给出不同的结果:
logit_model.fit(df['column_1','column_2'],df['target'])
logit_model.predict_proba(df['column_1','column_2'])
array([[ 0.26117794, 0.73882206], ..])
这对我来说似乎令人惊讶,但也许这只是我对算法的内部结构和拟合方法缺乏了解。
我错过了什么?
编辑:这是完整的代码和数据
数据:https://s3-us-west-2.amazonaws.com/gjt-personal/test_model.csv
import pandas as pd
from sklearn.linear_model import LogisticRegression
df = pd.read_csv('test_model.csv',index_col=False)
columns1 =['col_1','col_2','col_3','col_4','col_5','col_6','col_7','col_8','col_9']
columns2 =['col_2','col_1','col_3','col_4','col_5','col_6','col_7','col_8','col_9']
logit_model = LogisticRegression(C=1e9, tol=1e-15)
logit_model.fit(df[columns1],df['target'])
logit_model.predict_proba(df[columns1])
logit_model.fit(df[columns2],df['target'])
logit_model.predict_proba(df[columns2])
原来它与 tol=1e-15
有关,因为这会产生不同的结果。
LogisticRegression(C=1e9, tol=1e-15)
但这给出了相同的结果。
LogisticRegression(C=1e9)
【问题讨论】:
【参考方案1】:这是在两个代码示例中测量相同的东西。
当我们将 DataFrame
提供给 sklearn 中的分类器时,它会在数据帧的每一行上进行训练(每一行对应一个观察值)
所以行的顺序无关紧要,因为您得到的输出是特定行对应于每个可能的类的概率。
例如:
array([[ 0.26117794, 0.73882206], ..])
的输出意味着我们提供给分类器的行有约 26% 的机会属于第 0 类,有约 74% 的机会属于第 1 类。这个测量并没有说明什么各个列。只是整个行。
让我知道这是否有帮助,如果我能澄清我的答案。
【讨论】:
所以我的问题不是关于输出的解释或者不同行的不同,而是当fit
上的列顺序不同时同一行的不同/跨度>
根据代码,输出完全相同。您能否提供一个示例,说明同一行数据的输出不同?
输出完全相同是什么意思?这不一样。你的意思是应该完全一样吗?
天哪,我完全错过了。我觉得自己很愚蠢。
实际的答案是逻辑回归使用梯度下降来达到其最终形式,这意味着涉及一些随机性。无论行的顺序如何,重新拟合模型都会改变预测。您可以通过在 train_test_split() 中设置随机种子来测试这一点【参考方案2】:
感谢您添加示例数据。
更深入地查看您的数据显然不是标准化的。如果您将StandardScaler
应用于数据集并再次尝试拟合,您会发现预测差异消失了。
虽然这个结果至少是一致的,但它引发LineSearchWarning
和ConvergenceWarning
仍然令人不安。对此,我想说您在1e-15
的容忍度确实非常低。考虑到您应用的非常高的正则化惩罚率(1e9
),将tol
降低到默认的1e-4
将不会产生任何影响。这使得模型能够正确收敛并仍然产生相同的结果(运行时间更快)。
我的整个过程如下所示:
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
ss = StandardScaler()
cols1 = np.arange(9)
cols2 = np.array([1,0,2,3,4,5,6,7,8])
X = ss.fit_transform(df.drop('target', axis=1))
lr = LogisticRegression(solver='newton-cg', tol=1e-4, C=1e9)
lr.fit(X[:, cols1], df['target'])
preds_1 = lr.predict_proba(X[:, cols1])
lr.fit(X[:, cols2], df['target'])
preds_2 = lr.predict_proba(X[:, cols2])
preds_1
array([[ 0.00000000e+00, 1.00000000e+00],
[ 0.00000000e+00, 1.00000000e+00],
[ 0.00000000e+00, 1.00000000e+00],
...,
[ 1.00000000e+00, 9.09277801e-31],
[ 1.00000000e+00, 3.52079327e-35],
[ 1.00000000e+00, 5.99607407e-30]])
preds_2
array([[ 0.00000000e+00, 1.00000000e+00],
[ 0.00000000e+00, 1.00000000e+00],
[ 0.00000000e+00, 1.00000000e+00],
...,
[ 1.00000000e+00, 9.09277801e-31],
[ 1.00000000e+00, 3.52079327e-35],
[ 1.00000000e+00, 5.99607407e-30]])
断言preds_1 == preds_2
将失败,但每个值的差异在 1e-40 + 的数量级上,我想说这远远超出了任何合理的重要性水平。
【讨论】:
Grr 是的,这就是我的想法,但在文档中它说:“在求解器 == ‘sag’ 或 ‘liblinear’ 时使用。”这就是为什么我使用newton-cg
scikit-learn.org/stable/modules/generated/…
嗯,如果我用logit_model = LogisticRegression(random_state=0)
重新运行,输出是相等的,但是如果我运行,LogisticRegression(fit_intercept=True, C=1e9,tol=1e-15, solver='newton-cg',random_state=0)
仍然不同,即使运行LogisticRegression()
也是一样的
那么在这种情况下,您不再使用 newton-cg 了,这是有道理的
所以它与tol
属性有关。 LogisticRegression(fit_intercept=True, C=1e9,tol=1e-15)
不同但LogisticRegression(fit_intercept=True, C=1e9)
相同,知道为什么会这样吗?
ah "注意:底层 C 实现在拟合模型时使用随机数生成器来选择特征。因此,对于相同的输入数据,结果略有不同的情况并不少见。如果发生这种情况,尝试使用较小的 tol 参数。”以上是关于LogisticRegression scikit学习协变量(列)顺序对训练很重要的主要内容,如果未能解决你的问题,请参考以下文章
scikit-learn 中 LogisticRegression 上的 GridSearchCV
LogisticRegression scikit学习协变量(列)顺序对训练很重要
如何评估 scikit learn LogisticRegression 的成本函数?
在 scikit-learn 库中使用 sgd 求解器的 SGDClassifier 与 LogisticRegression