代码之家  ›  专栏  ›  技术社区  ›  Arnold

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

  •  1
  • Arnold  · 技术社区  · 6 年前

    我有一个整数值的时间序列,我正试图预测它。我通过一个滑动窗口来实现这一点,它将学习关联99个值来预测下一个值。值介于0和128之间。x的表示是一个n个滑动窗口的立方体,长99,每个整数编码为一个128个元素的热编码向量。这个数组的形状是(n,99128)。Y的形状是(N,128)。我认为这是一个多层次的问题,因为Y可以精确地得到一个结果。

    这对Keras/TensorFlow很好,但是当我尝试使用SciKit的RandomForest时,我发现它抱怨输入向量是3D而不是二维的,所以我将输入立方体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*类一起返回,所以在我的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数组的大小是一致的,但是它的形状是完全奇怪的(128,29)。这29个是从哪里来的…?然而,还有一些改进需要报告:准确性已经大大提高了。以前是0.0015左右,现在是0.20左右。

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

    编辑2

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

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

    1 回复  |  直到 6 年前
        1
  •  3
  •   Vivek Kumar    6 年前

    首先让我们谈谈你的目标 y .

    • 二维 Y 被认为是一个标签指标矩阵,用于SciKit学习中的多标签或多输出多类任务。从你的数据来看,情况似乎不是这样的,所以我不认为你会想要一个热编码 Y .

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

    实施例1 :考虑到您有一个问题,您希望将一些数据分为“日本”、“俄罗斯”、“美国”三个国家。

    • 现在,这些字符串可以编码为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点开始讨论您的案例和我的问题: 这些整数能用数字比较吗 ?如果是,则无需对功能进行热编码。如果没有,就去做。