kil*_*out 101 python scikit-learn
我很难理解class_weight
scikit-learn的Logistic回归中的参数是如何运作的.
情况
我想使用逻辑回归对非常不平衡的数据集进行二进制分类.类别标记为0(负)和1(正),观察数据的比例约为19:1,大多数样本具有负结果.
第一次尝试:手动准备训练数据
我将我拥有的数据拆分为不相交的集合进行培训和测试(约80/20).然后我手动随机抽取训练数据,得到不同比例的训练数据,比例为19:1; 从2:1 - > 16:1.
然后,我在这些不同的训练数据子集上训练逻辑回归,并绘制召回(= TP /(TP + FN))作为不同训练比例的函数.当然,召回是根据观察到的比例为19:1的不相交TEST样本计算的.请注意,虽然我在不同的训练数据上训练了不同的模型,但我在相同(不相交)的测试数据上计算了所有这些模型的回忆.
结果如预期的那样:召回率为2:1的训练比例约为60%,并且在达到16:1时下降得相当快.有几个比例为2:1 - > 6:1,召回率高于5%.
第二次尝试:网格搜索
接下来,我想测试不同的正则化参数,所以我使用了GridSearchCV并制作了一个C
参数的几个值的网格class_weight
.将我的n:m比例的负面:正面训练样本翻译成字典语言,class_weight
我认为我只是指定了几个字典,如下所示:
{ 0:0.67, 1:0.33 } #expected 2:1
{ 0:0.75, 1:0.25 } #expected 3:1
{ 0:0.8, 1:0.2 } #expected 4:1
Run Code Online (Sandbox Code Playgroud)
我也包括None
和auto
.
这次结果完全被摧毁了.对于class_weight
除了的每个值,我的所有召回都很小(<0.05)auto
.所以我只能假设我对如何设置class_weight
字典的理解是错误的.有趣的是,class_weight
网格搜索中'auto' 的值对于所有值都是59%左右C
,我猜它平衡为1:1?
我的问题
1)如何正确使用class_weight
来实现训练数据的不同平衡,从实际给出的数据?具体来说,我传给什么词典class_weight
使用n:m比例的负面:正面训练样本?
2)如果您将各种class_weight
词典传递给GridSearchCV,在交叉验证期间它会根据字典重新平衡训练折叠数据,但是使用真实的给定样本比例来计算测试折叠上的评分函数?这是至关重要的,因为任何度量标准仅对我有用,如果它来自观察到的比例的数据.
3)就比例而言auto
,class_weight
做什么的价值是多少?我阅读了文档,我假设"平衡数据与它们的频率成反比"只是意味着它以1:1的比例.它是否正确?如果没有,有人可以澄清吗?
非常感谢,任何澄清将不胜感激!
And*_*ler 109
首先,单独召回可能不太好.通过将所有内容归类为积极的类,您可以简单地实现100%的召回.我通常建议使用AUC选择参数,然后找到您感兴趣的工作点(比如给定的精度级别)的阈值.
对于如何class_weight
工作的:它惩罚的样本失误class[i]
与class_weight[i]
代替1.这样高类的重量意味着要更多地强调的一类.根据你所说的,似乎0级比1级频率高19倍.所以你应该class_weight
相对于0级增加1级,比如说{0:.1,1:.9}.如果class_weight
不求和为1,则基本上会改变正则化参数.
有关class_weight="auto"
工作原理,您可以查看此讨论.在您可以使用的开发版本中class_weight="balanced"
,这更容易理解:它基本上意味着复制较小的类,直到您拥有与较大的类一样多的样本,但是以隐式方式.
第一个答案有助于理解它是如何工作的。但我想了解我应该如何在实践中使用它。
概括
class_weight="balanced"
在您不想手动优化的情况下工作得很好class_weight="balanced"
您捕获更多真实事件(更高的 TRUE 召回率),您也更有可能获得错误警报(更低的 TRUE 精度)
NB
使用 RF 或 GBM 时,结果可能会有所不同。sklearn 没有 class_weight="balanced"
GBM 但lightgbm有LGBMClassifier(is_unbalance=False)
代码
# scikit-learn==0.21.3
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score, classification_report
import numpy as np
import pandas as pd
# case: moderate imbalance
X, y = datasets.make_classification(n_samples=50*15, n_features=5, n_informative=2, n_redundant=0, random_state=1, weights=[0.8]) #,flip_y=0.1,class_sep=0.5)
np.mean(y) # 0.2
LogisticRegression(C=1e9).fit(X,y).predict(X).mean() # 0.184
(LogisticRegression(C=1e9).fit(X,y).predict_proba(X)[:,1]>0.5).mean() # 0.184 => same as first
LogisticRegression(C=1e9,class_weight={0:0.5,1:0.5}).fit(X,y).predict(X).mean() # 0.184 => same as first
LogisticRegression(C=1e9,class_weight={0:2,1:8}).fit(X,y).predict(X).mean() # 0.296 => seems to make things worse?
LogisticRegression(C=1e9,class_weight="balanced").fit(X,y).predict(X).mean() # 0.292 => seems to make things worse?
roc_auc_score(y,LogisticRegression(C=1e9).fit(X,y).predict(X)) # 0.83
roc_auc_score(y,LogisticRegression(C=1e9,class_weight={0:2,1:8}).fit(X,y).predict(X)) # 0.86 => about the same
roc_auc_score(y,LogisticRegression(C=1e9,class_weight="balanced").fit(X,y).predict(X)) # 0.86 => about the same
# case: strong imbalance
X, y = datasets.make_classification(n_samples=50*15, n_features=5, n_informative=2, n_redundant=0, random_state=1, weights=[0.95])
np.mean(y) # 0.06
LogisticRegression(C=1e9).fit(X,y).predict(X).mean() # 0.02
(LogisticRegression(C=1e9).fit(X,y).predict_proba(X)[:,1]>0.5).mean() # 0.02 => same as first
LogisticRegression(C=1e9,class_weight={0:0.5,1:0.5}).fit(X,y).predict(X).mean() # 0.02 => same as first
LogisticRegression(C=1e9,class_weight={0:1,1:20}).fit(X,y).predict(X).mean() # 0.25 => huh??
LogisticRegression(C=1e9,class_weight="balanced").fit(X,y).predict(X).mean() # 0.22 => huh??
(LogisticRegression(C=1e9,class_weight="balanced").fit(X,y).predict_proba(X)[:,1]>0.5).mean() # same as last
roc_auc_score(y,LogisticRegression(C=1e9).fit(X,y).predict(X)) # 0.64
roc_auc_score(y,LogisticRegression(C=1e9,class_weight={0:1,1:20}).fit(X,y).predict(X)) # 0.84 => much better
roc_auc_score(y,LogisticRegression(C=1e9,class_weight="balanced").fit(X,y).predict(X)) # 0.85 => similar to manual
roc_auc_score(y,(LogisticRegression(C=1e9,class_weight="balanced").fit(X,y).predict_proba(X)[:,1]>0.5).astype(int)) # same as last
print(classification_report(y,LogisticRegression(C=1e9).fit(X,y).predict(X)))
pd.crosstab(y,LogisticRegression(C=1e9).fit(X,y).predict(X),margins=True)
pd.crosstab(y,LogisticRegression(C=1e9).fit(X,y).predict(X),margins=True,normalize='index') # few prediced TRUE with only 28% TRUE recall and 86% TRUE precision so 6%*28%~=2%
print(classification_report(y,LogisticRegression(C=1e9,class_weight="balanced").fit(X,y).predict(X)))
pd.crosstab(y,LogisticRegression(C=1e9,class_weight="balanced").fit(X,y).predict(X),margins=True)
pd.crosstab(y,LogisticRegression(C=1e9,class_weight="balanced").fit(X,y).predict(X),margins=True,normalize='index') # 88% TRUE recall but also lot of false positives with only 23% TRUE precision, making total predicted % TRUE > actual % TRUE
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
65023 次 |
最近记录: |