scikit学习randomforest中令人困惑的概率

时间:2018-10-21 11:05:00

标签: python scikit-learn random-forest

我正在尝试预测一个整数值的时间序列。我通过滑动窗口来执行此操作,在该窗口中,它学会关联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)的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数组的列表组成,有时包含一个元素,有时包含两个元素?据我对the manual的了解,应该使用维数#个样本*#个类返回一个数组,因此在我的形状为(1,128)的示例中。

有人可以帮助我指出我做错了什么吗?

编辑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

概率数组具有一致的大小,但是其形状是完全怪异的(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?我在手册中找不到关于此的任何提示。

1 个答案:

答案 0 :(得分:3)

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

  • 2-d y被视为标签指示器矩阵,用于scikit-learn中的多标签或多输出多类任务。从您的数据来看,情况似乎并非如此,因此我认为您不希望对y进行一次热编码。

  • 关于问题中目标的第二件事是,您首先需要确定是要分类任务还是回归任务。您说您有一个"time series of integer values"。所以问题是可以将这些整数与另一个数字进行比较吗?

示例1 :考虑到您遇到一个问题,您想将一些数据归类为“日本”,“俄罗斯”,“美国”三个国家。

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

  • 但是在任何其他情况下,例如预测股票价格或预测温度等,这些数字可以并且应该相互比较,因此应该使用回归(预测实际价值目标)。 / p>

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

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

  • 但是在回归模型中,如果一个模型将输出预测为8,则可以说比同一样本将输出预测为1的模型更好。

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

注意:我现在将分类作为您的原始问题进行进一步的研究。

现在进入功能X

如果类别中没有排序,或者您无法正确确定该排序,则使用单热编码。我上面给出的类别之间的数值比较的解释也适用于此。

  • 考虑三个类别的另一个示例:“高”,“中”,“低”。它们在其中具有固有的顺序。如果您将其编码为0(低),1(中)和2(高),则可以对其进行数值比较。因此,您可以决定将它们保留为0,1,2或一键编码。

  • 正如我在评论中说的那样,如果对类别进行战略性编码,则随机森林对于此类情况非常强大,并且不会对性能产生太大影响。例如,如果您编码0(高),1(低),2(中)等,性能可能会下降。

现在再次从第1点开始讨论您的问题和我的问题:可以将这些整数与另一个数字进行比较吗?如果是,则无需对功能进行一次热编码。如果没有,那就这样做。