为啥在 python 中获取 sklearn 中的***谓词的结果不同?

Posted

技术标签:

【中文标题】为啥在 python 中获取 sklearn 中的***谓词的结果不同?【英文标题】:Why is the results different in getting the top predications in sklearn in python?为什么在 python 中获取 sklearn 中的***谓词的结果不同? 【发布时间】:2019-12-30 10:07:41 【问题描述】:

我有一个包含 1000 个数据点的数据集。每个数据点都分配有标签10,如下所示。

我的数据集:

node, feature1, feature2, ........, Label
x1,   0.8, 0.9, ........, 1
x2,   0.2, 0.6, ........, 1
...
x999, 0.1, 0.1, ........, 0
x1000,0.8, 0.9, ........, 1

我想执行二进制分类,并根据 1 类的预测概率对我的数据点进行排名。为此,我目前在 sklearn 中使用 predict_proba 函数。所以我的输出应该如下所示。

我的预期输出:

node prediction_probability_of_class_1
x8,  1.0
x5,  1.0
x990,0.95
x78, 0.92
x85, 0.91
x6,  0.90
and so on ........

我一直在尝试这样做,使用以下两种方法。但是,我得到的结果彼此不匹配。所以,我认为我的一种方法(或两种方法)都不正确。

由于我的数据集属于我的公司并包含敏感数据,因此我将展示我使用 iris dataset 具有 150 个数据点的两种方法。

from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target

我的方法一:

#random forest classifier
clf=RandomForestClassifier(n_estimators=10, random_state = 42, class_weight="balanced")
#perform 10 fold cross validation
k_fold = StratifiedKFold(n_splits=10, shuffle=True, random_state=0)
#get predict_proba for each instance
proba = cross_val_predict(clf, X, y, cv=k_fold, method='predict_proba')
#get the probability of class 1
print(proba[:,1])
#get the datapoint index of each probaility
print(np.argsort(proba[:,1]))

所以我的结果如下所示。

#probaility of each data point for class 1
[0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.1 0.  0.  0.
 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.
 0.2 0.  0.  0.  0.  0.1 0.  0.  0.  0.  0.  0.  0.  0.  0.9 1.  0.7 1.
 1.  1.  1.  0.7 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  0.9 0.9 0.1 1.
 0.6 1.  1.  1.  0.9 0.  1.  1.  1.  1.  1.  0.4 0.9 0.9 1.  1.  1.  0.9
 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.  0.  0.  0.  0.  0.  0.  0.9 0.
 0.1 0.  0.  0.  0.  0.  0.  0.  0.1 0.  0.  0.8 0.  0.1 0.  0.1 0.  0.1
 0.3 0.2 0.  0.6 0.  0.  0.  0.6 0.4 0.  0.  0.  0.8 0.  0.  0.  0.  0.
 0.  0.  0.  0.  0.  0. ]

#corresponding index of the above data points
[  0 113 112 111 110 109 107 105 104 114 103 101 100  77 148  49  48  47
  46 102 115 117 118 147 146 145 144 143 142 141 140 139 137 136 135 132
 131 130 128 124 122 120  45  44 149  42  15  26  16  17  18  19  20  21
  22  43  23  24  35  34  33  32  31  30  29  28  27  37  13  25   9  10
   7   6   5   4   3   8  11   2   1  38  39  40  12 108 116  41 121  70
  14 123 125  36 127 126 134  83  72 133 129  52  57 119 138  89  76  50
  84 106  85  69  68  97  98  66  65  64  63  62  61  67  60  58  56  55
  54  53  51  59  71  73  75  96  95  94  93  92  91  90  88  87  86  82
  81  80  79  78  99  74]

我的方法2:

由于我上面使用的cross_val_predict没有fit方法,所以无法访问clf.classes_等数据。因此,我使用下面的代码。

cv_1 = cross_val_score(clf, X, y, cv=k_fold)
clf.fit(X, y)
probabilities = pd.DataFrame(clf.predict_proba(X), columns=clf.classes_)
probabilities['Y'] = y
probabilities.columns.name = 'Classes'
print(probabilities.sort_values(1))

我的结果如下。

Classes    0    1    2  Y
0        1.0  0.0  0.0  0
115      0.0  0.0  1.0  2
114      0.0  0.0  1.0  2
113      0.0  0.0  1.0  2
112      0.0  0.0  1.0  2
111      0.0  0.0  1.0  2
110      0.0  0.0  1.0  2
109      0.0  0.0  1.0  2
108      0.0  0.0  1.0  2
107      0.0  0.0  1.0  2
105      0.0  0.0  1.0  2
104      0.0  0.0  1.0  2
103      0.0  0.0  1.0  2
102      0.0  0.0  1.0  2
101      0.0  0.0  1.0  2
100      0.0  0.0  1.0  2
148      0.0  0.0  1.0  2
49       1.0  0.0  0.0  0
48       1.0  0.0  0.0  0
47       1.0  0.0  0.0  0
116      0.0  0.0  1.0  2
46       1.0  0.0  0.0  0
117      0.0  0.0  1.0  2
120      0.0  0.0  1.0  2
147      0.0  0.0  1.0  2
146      0.0  0.0  1.0  2
145      0.0  0.0  1.0  2
144      0.0  0.0  1.0  2
143      0.0  0.0  1.0  2
142      0.0  0.0  1.0  2
..       ...  ...  ... ..
63       0.0  1.0  0.0  1
59       0.0  1.0  0.0  1
58       0.0  1.0  0.0  1
55       0.0  1.0  0.0  1
54       0.0  1.0  0.0  1
53       0.0  1.0  0.0  1
51       0.0  1.0  0.0  1
50       0.0  1.0  0.0  1
61       0.0  1.0  0.0  1
99       0.0  1.0  0.0  1
76       0.0  1.0  0.0  1
79       0.0  1.0  0.0  1
96       0.0  1.0  0.0  1
95       0.0  1.0  0.0  1
94       0.0  1.0  0.0  1
93       0.0  1.0  0.0  1
92       0.0  1.0  0.0  1
91       0.0  1.0  0.0  1
90       0.0  1.0  0.0  1
78       0.0  1.0  0.0  1
89       0.0  1.0  0.0  1
87       0.0  1.0  0.0  1
86       0.0  1.0  0.0  1
85       0.0  1.0  0.0  1
84       0.0  1.0  0.0  1
82       0.0  1.0  0.0  1
81       0.0  1.0  0.0  1
80       0.0  1.0  0.0  1
88       0.0  1.0  0.0  1
74       0.0  1.0  0.0  1

如您所见,两种方法中每个数据点的class 1 的概率值并不相等。考虑数据点88,在方法1中是0,在方法2中是1

因此,我想知道在 python 中执行此操作的正确方法是什么。注意:我想执行10-fold cross validation 来获取我的概率值。

如果需要,我很乐意提供更多详细信息。

【问题讨论】:

对于您显示的结果,您使用的是您提供的打印代码吗? @Alexis 是的,我使用的是相同的代码 :) 那么 argsort 正在重新排序上面的值。 88 不是 0,而是 1,正如预期的那样。 np.argsort(np.array([3, 1, 2])) => array([1, 2, 0]) 因此,他们对此并没有错。尝试计算两个概率之间的差异并检查是否有任何差异。 @Alexis 感谢您的评论。那么,我正在打印的索引是否已排序?如何在不排序的情况下获得它们对应的索引?所以,我可以再次手动检查结果。期待您的来信:) 我会用解决方案来回答它。让我进行一些测试以获得可比较的东西并构建一个可重复的示例。尽快回复您。 【参考方案1】:

我已在您的代码中添加了一小部分代码。擦除最后一个打印,可以添加如下代码,看看两个预测的区别:

probabilities['other methode'] = proba[:,1]
probabilities['diff'] = probabilities[1]-probabilities['other method']
probabilities[probabilities['diff'] != 0]

结果如下:

Classes 0    1        2     Y   other method diff
20   1.0    0.0     0.0     0   0.1         -0.1
36   1.0    0.0     0.0     0   0.1         -0.1
41   1.0    0.0     0.0     0   0.1         -0.1
50   0.0    1.0     0.0     1   0.9         0.1
52   0.0    0.9     0.1     1   1.0         -0.1
56   0.0    0.9     0.1     1   1.0         -0.1
57   0.0    0.9     0.1     1   1.0         -0.1
59   0.0    1.0     0.0     1   0.9         0.1
60   0.0    0.9     0.1     1   1.0         -0.1
68   0.0    0.9     0.1     1   1.0         -0.1
... ... ... ... ... ... ...
123  0.0    0.2     0.8     2   0.4         -0.2
127  0.0    0.2     0.8     2   0.1         0.1
129  0.0    0.1     0.9     2   0.6         -0.5
133  0.0    0.1     0.9     2   0.9         -0.8
134  0.0    0.2     0.8     2   0.6         -0.4
137  0.0    0.0     1.0     2   0.1         -0.1
138  0.0    0.3     0.7     2   0.6         -0.3
141  0.0    0.0     1.0     2   0.1         -0.1
142  0.0    0.0     1.0     2   0.1         -0.1
146  0.0    0.0     1.0     2   0.1         -0.1

您会发现这两者之间确实存在 29 个元素的差异。 那你为什么要问?好吧,这是因为您没有以相同的方式训练算法:

clf.fit(X, y)
clf.predict_proba(X)

cross_val_predict(clf, X, y, cv=k_fold, method='predict_proba')

不一样。一种是使用交叉验证方法来确保稳健性,而另一种是只训练一次。

结果会有所不同,但在大多数情况下相差甚远。例如,如果我们删除所有 diff

编辑

回答评论是的,简历是一个更好的主意。 在您更新之后,我认为最好的方法是使用您一开始就已经拥有的数据框,然后对其进行排序:

df = pd.DataFrame(index=['x1','x2',...,'x1000'],columns=['prediction_class_1']).fillna(0)
df['prediction_class_1'] = clf.predict(X) #clf trained and X the features values
print(df.sort_values('prediction_class_1'))

X = train[['feature1','feature2', ........,'featuren']].values

【讨论】:

非常感谢您的出色回答。这真的很有帮助。所以,根据你的回答,我觉得使用方法 1 更好,因为它更健壮。请让我知道我是否正确?一个简单的问题,你能帮我用方法 1 获得我的预期输出(如我的问题所示)吗?我想我缺少使用 argsort 的输出顺序。再次非常感谢你:) 我不确定您想要什么作为预期输出。你想要的输出的形式到底是什么? proba[:1] 为您提供第 1 类的列 我的预期输出是按类别 1 的预测概率降序排列的数据点。所以,它看起来如下。 node prediction_probability_of_class_1 x8, 1.0 x5, 1.0 x990,0.95 x78, 0.92 x85, 0.91 x6, 0.90 and so on ........ 。我也更新了这个问题。谢谢你:)

以上是关于为啥在 python 中获取 sklearn 中的***谓词的结果不同?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 python 中的 sklearn 中获取 GridSearchCV 中的选定功能

为啥我在 python 的 sklearn 中使用管道和没有管道得到不同的值

python - 如何从python中sklearn中的cross_val_predict获取排序的概率和名称

为什么我在python中的sklearn中使用管道获取不同的值而没有管道

为啥我在 Sklearn 管道中的 OneHotEncoding 后得到的列比预期的多?

为啥我自己的逻辑回归实现与 sklearn 不同?