【发布时间】:2019-03-25 15:50:11
【问题描述】:
我有一个整数值的时间序列,我试图预测。我通过一个滑动窗口来做到这一点,它学习关联 99 个值来预测下一个值。这些值介于 0 和 128 之间。X 的表示是一个由 n 个 99 长的滑动窗口组成的立方体,每个整数都被编码为一个 128 个元素长的热编码向量。这个数组的形状是 (n, 99, 128)。 Y的形状是(n, 128)。我将其视为一个多类问题,因为 Y 可以精确地得出一个结果。
这适用于 Keras/Tensorflow,但是当我尝试使用 scikit-learn 中的 RandomForest 时,它抱怨输入向量是 3D 而不是 2D。因此,我将输入立方体 X 重新整形为形状为 (n, 99 * 128) 的二维矩阵。结果不是很好,为了了解发生了什么,我请求了概率(参见下面的代码)。
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 没错,但为什么它由一个列表组成,包含二维数组,有时包含一个元素,有时包含两个元素?据我了解the manual 应该返回一个数组,其维度为# samples * # classes,因此在我的形状示例中为 (1,128)。
谁能帮我指出我做错了什么?
编辑 1
我按照@Vivek Kumar(感谢 Vivek)在他的 cmets 中建议的方式进行了实验。我输入整数序列 (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
概率数组的大小一致,但它的形状完全奇怪 (128, 29)。这个 29 是从哪里来的……?然而,报告有一些改进:准确性大大提高。以前是 0.0015 左右,现在是 0.20 左右。
关于概率数组代表什么的任何想法?
编辑 2
我的错误是,从 128 个单热编码值返回到整数时,我没有考虑到我只有 29 个唯一值。 predict_proba 巧妙地预测了这 29 个值,因为这些是它学到的。
剩下的唯一问题是概率预测哪些值?让我们假设要预测的类是 0、101-128,predict_proba 返回索引 0..28 的值。概率到类的映射是什么:0-->0, 1-->101, 2-->102, ... , 29-128?我在手册中找不到任何关于此的提示。
【问题讨论】:
-
您还需要停止对
y值的一次性编码。在您当前的输入中,y 的形状为 (n, 128),它是 2-d 触发分类器的多输出模式,而不是多类。对于多类,只需保持数字不变(从 0 到 128 的值),使 y 的形状为(n,)。 -
另外,在 X 中,如果值(介于 0 到 128 之间)表示它们之间的任何排序,则无需对它们进行任何 one-hot 编码。您可以按原样放置它们。你的 X 可以是形状 (n, 99)。树分类器在处理这个问题上做得很好。看看这些 cmets 是否有意义,否则我会发布一个详细解释这一点的答案。
-
@Vivek Kumar:看我的编辑。由于您的 cmets,我有相当多的改进,但概率的形状完全奇怪。我很想看看你的解释,因为我的印象是分类器的输入应该是一个热编码的。我还认为数据应该是某种标准化的,而我的数据不再是这样了。
-
我在下面添加了关于我的 cmets 的说明。看看这是否有意义。如果还需要更多支持,我也可以描述代码。
-
看clf.classes_属性
标签: python scikit-learn random-forest