从scikit学习随机森林的混淆概率



我有一个整数值的时间序列,我正在尝试预测。我通过一个滑动窗口来实现这一点,它在那里学习关联99个值来预测下一个值。这些值介于0和128之间。X的表示是一个由99个长的n个滑动窗口组成的立方体,每个整数编码为128个元素长的一个热编码矢量。这个数组的形状是(n,99128)。Y的形状是(n,128)。我认为这是一个多类问题,因为Y只能得到一个结果。

这在Keras/Tensorflow中运行良好,但当我尝试使用scikit learn中的RandomForest时,它抱怨输入向量是3D而不是2D。因此,我将输入立方体X重塑为形状为(n,99*128)的2D矩阵。结果不太好,为了了解发生了什么,我要求提供概率(见下面的代码)。

def rf(X_train, Y_train, X_val, Y_val, samples):
clf = RandomForestClassifier(n_estimators=32, n_jobs=-1)
clf.fit(X_train, Y_train)
score = clf.score(X_val, Y_val)
print('Score of randomforest =', score)
# compute some samples
for i in range(samples):
index = random.randrange(0, len(X_val) - 1)
xx = X_val[index].reshape(1, -1)
probs = clf.predict_proba(xx)
pred = clf.predict(xx)
y_true = np.argmax(Y_val[index])
y_hat = np.argmax(pred)
print(index, '-', y_true, y_hat, xx.shape, len(probs))
print(probs)
print(pred)

我从predict_proba得到的输出是:

[array([[0.841, 0.159]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), 
array([[1.]]), array([[1., 0.]]), array([[1., 0.]]), array([[1., 0.]]),
array([[1., 0.]]), array([[1., 0.]]), array([[0.995, 0.005]]), array([[0.999,
0.001]]), array([[0.994, 0.006]]), array([[1., 0.]]), array([[0.994, 0.006]]),
array([[0.977, 0.023]]), array([[0.999, 0.001]]), array([[0.939, 0.061]]),
array([[0.997, 0.003]]), array([[0.969, 0.031]]), array([[0.997, 0.003]]),
array([[0.984, 0.016]]), array([[0.949, 0.051]]), array([[1., 0.]]),
array([[0.95, 0.05]]), array([[1., 0.]]), array([[0.918, 0.082]]), 
array([[0.887, 0.113]]), array([[1.]]), array([[0.88, 0.12]]), array([[1.]]),
array([[0.884, 0.116]]), array([[0.941, 0.059]]), array([[1.]]), array([[0.941,
0.059]]), array([[1.]]), array([[0.965, 0.035]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]]),
array([[1.]]), array([[1.]]), array([[1.]]), array([[1.]])]

输出向量的长度是128,但为什么它由一个列表组成,包含2D数组,有时包含一个元素,有时包含两个元素?据我从手册中了解,数组应该返回维度#samples**class,所以在我的shape(1128)示例中也是如此。

有人能帮我指出我做错了什么吗?

编辑1

我按照@Vivek Kumar(感谢Vivek)在他的评论中建议的思路做了实验。我输入整数序列(X),并将它们与序列(y)中的下一个整数匹配。这是代码:

def rff(X_train, Y_train, X_val, Y_val, samples, cont=False):
print('Input data:', X_train.shape, Y_train.shape, X_val.shape, Y_val.shape)
clf = RandomForestClassifier(n_estimators=64, n_jobs=-1)
clf.fit(X_train, Y_train)
score = clf.score(X_val, Y_val)
y_true = Y_val
y_prob = clf.predict_proba(X_val)
y_hat = clf.predict(X_val)
print('y_true', y_true.shape, y_true)
print('y_prob', y_prob.shape, y_prob)
print('y_hat', y_hat.shape, y_hat)
#sum_prob = np.sum(y_true == y_prob)
sum_hat = np.sum(y_true == y_hat)
print('Score of randomforest =', score)
print('Score y_hat', sum_hat / len(X_val))
#print('Score y_prob', sum_prob / len(X_val))
# compute some individual samples
for i in range(samples):
index = random.randrange(0, len(X_val) - 1)
y_true_i = Y_val[index]
#y_prob_i = y_prob[index]
y_hat_i = y_hat[index]
print('{:4d} - {:3d}{:3d}'.format(index, y_true_i, y_hat_i))

其输出为:

Input data: (4272, 99) (4272,) (1257, 99) (1257,)
y_true (1257,) [ 0  0  0 ... 69 70 70]
y_prob (1257, 29) [[0.09375  0.       0.       ... 0.078125 0.078125 0.015625]
[0.109375 0.       0.       ... 0.046875 0.0625   0.0625  ]
[0.125    0.       0.       ... 0.015625 0.078125 0.015625]
...
[0.078125 0.       0.       ... 0.       0.       0.      ]
[0.046875 0.       0.       ... 0.       0.       0.      ]
[0.078125 0.       0.       ... 0.       0.       0.      ]]
y_hat (1257,) [81 81 79 ... 67 67 65]
Score of randomforest = 0.20047732696897375
Score y_hat 0.20047732696897375
228 -  76 77
51 -  76  0
563 -  81  0
501 -   0 77
457 -  79 79
285 -  76 77
209 -  81  0
1116 -  79  0
178 -  72 77
1209 -  67 65

probabilities数组有一个一致的大小,但它的形状完全奇怪(12829)。这个29是从哪里来的。。。?然而,报告还有一些改进:准确性大大提高。它过去大约是0.0015,现在大约是0.20。

关于概率数组代表什么,有什么想法吗?

编辑2

我的错误是,通过从128个一热编码值返回到整数,我没有考虑到我只有29个唯一值。predict_proba巧妙地预测了这29个值,因为这些都是它学到的。

剩下的唯一问题是概率可以预测哪些值?让我们假设要预测的类是0101-128,predict_proba返回索引0..28的值。概率到类的映射是什么:0-->0,1-->101,2-->102,29-128?我在手册中找不到任何关于这方面的提示。

首先让我们谈谈您的目标y

  • 2-dy被认为是scikit学习中用于多标签或多输出多类任务的标签指示符矩阵。从你的数据来看,情况似乎并非如此,所以我认为你不会想对y进行一次热编码。

  • 关于问题中的目标的第二件事是,您首先需要决定是想要分类还是回归任务。你说你有"time series of integer values"。所以问题是这些整数可以在数字上相互比较吗?

示例1:考虑到您有一个问题,您想将一些数据分为三个国家:";Japan"俄罗斯"USA";。

  • 现在这些字符串可以被编码为1("日本")、2("俄罗斯")和3("美国"),以便它们可以在机器学习模型中使用。但我们不能比较这些编码,因为2中的数字大于1或小于3。这里的1,2,3只是分类数据的数字表示,实际上对它没有任何数字意义。在这种情况下,分类任务适合将数据分为这三类。

  • 但在任何其他情况下,如预测股价或预测温度等,可以也应该将这些数字相互比较,因此应该使用回归(来预测真正有价值的目标)。

示例2:为了更好地理解,您还可以考虑模型的正确性(损失函数)。让我们假设一个模型预测从1到10的目标,并且特定样本的正确目标是9。

  • 在分类任务中,只有正确的预测才重要。不管模型预测的目标是8还是1。

  • 但在回归模型中,如果一个模型预测输出为8,那么你可以说它比预测同一样本的输出为1的模型要好。

希望你明白我的意思。因此,对于你的问题,即使你有有限数量的整数(128)作为目标,你也需要决定它们在分类或回归中是否有意义。

注意:我目前正在进一步将分类作为您的原始问题。

现在介绍功能X

如果类别中没有排序,或者您无法正确确定该排序,则使用一个热编码。我在上面对类别之间的数字比较所做的解释也适用于此。

  • 考虑三个类别的另一个例子:;高"中等""低";。它们有一个固有的排序。这里,如果你编码为0(低)、1(中)和2(高),那么它们可以进行数字比较。因此,您可以决定将它们保留为0,1,2或一个热编码。

  • 正如我在评论中所说,随机森林对这些东西非常强大,如果类别是战略性编码的,应该不会对性能产生太大影响。例如,如果你编码0(高)、1(低)、2(中等)等,性能可能会下降。

现在再次讨论您的情况和我从第1点提出的问题:这些整数可以在数字上相互比较吗?如果是,则无需对特征进行一次热编码。如果没有,就去做。

最新更新