首页 文章

为什么我的Python RandomForestRegressor不能准确预测训练集数据?

提问于
浏览
3

我是一个相当复杂的数据集上的'm taking my baby steps with machine learning and would like to use scikit-learn' s RandomForestRegressor() . 首先要了解它,我正在尝试通过以下基本示例:

import sklearn.ensemble as se
import numpy as np
forest = se.RandomForestRegressor(n_estimators=1000)
traindata = np.arange(1000).reshape(200,5)
forest = forest.fit(traindata[0::,1::],traindata[0::,0])

此时,我认为我创建了一个200行矩阵,每行格式 [ x, x+1, x+2, x+3, x+4 ] 有5个值,其中 x 是5的倍数(例如 [0,1,2,3,4][5,6,7,8,9] 等) .

我已经告诉我的森林适合 [ x+1, x+2, x+3, x+4 ] 来预测 x . 以下是我预测的情况:

forest.predict([1,2,3,4])
>> array([2.785])

这对我来说真的不直观 . 考虑到 [1,2,3,4] 的特征值是 x = 0 的训练数据,我的森林难道不能比2.785更接近预测吗?

我更进一步看到功能重要性如下:

forest.feature_importances_
>> array([0.26349716, 0.23664264, 0.23360533, 0.26625487])

对我来说,这并不意味着我所看到的方式存在重大偏差 . 我在这里想念的是什么?

4 回答

  • 0

    为什么不准确预测?

    Short version: 由于智能Breiman提出的方法的性质 .

    Longer version:

    随机森林是非常有趣的学习者 .

    但是,你需要一点耐心才能让它们得到调整 .

    forest.setp_param( oob_score    = True,   # set True to be able to read
                       #                      #     oob-samples score
                       random_state = 2015    # set so as to keep retesting
                       #                      #     possible / meaniningfull on
                       #                      #     an otherwise randomised
                       #                      #     learner construction
                       )
    

    原则上,任何使用 .fit() 方法的尝试都会在场景背后做很多工作来构建一组随机的决策树,使其成为一个RandomForest,适用于您的数据集 .

    .fit() 的“ quality ”表示在 .oob_score_ 中,其中显示了在给定 RandomForest 的训练结束后,已经使用的 oob -samples(Breiman方法的真正部分)中的(in)-accurate . 这有助于您估算“ well " or how " poor ”对您的训练 RandomForest 在可用数据集上的执行情况 .

    然而,更重要的是(或者应该), how well the learner generalises - 即,一旦看到一个看不见的例子,它的预测能力如何能够满足现实 .

    这个可以通过训练有素的 RandomForest -instance的 .score() 方法进行测试 .

    RandomForest是一个“多数投票” - 预测者,感觉到,尝试显示随机树的军队的内部状态:

    def printLDF( aPopulationSET ):
        LDF_example, LDF_counts = np.unique( aPopulationSET, return_counts = True )
        GDF_sum_scaler          = float( LDF_counts.sum() )
        for i in xrange( LDF_example.shape[0] ):
            print "{0: > 6d}: {1: > 6d} x {2: > 15.2f}            {3: > 15.4f} % {4: > 15.1f} %".format( i, LDF_counts[i], LDF_example[i], 100 * LDF_counts[i] / GDF_sum_scaler, 100 * LDF_counts[:i].sum() / GDF_sum_scaler )
        return
    
    >>> printLDF( forest.estimators_[:].predict( anExample ) )
    

    这将显示单个树的预测投射到整个基于森林的预测的多数投票微积分 .

    这意味着,除了其他内容之外, RandomForest 主要不会预测培训中存在的"visited"值范围的值"outside"(不能通过设计"extrapolate") .

    如何让它变得更好?

    嗯,特色工程是关键 . 如果你知道一个RandomForest对你的案例是一个可行的学习者而你觉得它是 observed predictive powers are poor ,那么首先应该归咎于特征选择 .

    检查森林

    检查学习者的内部状态 - 检查森林中的树木做了什么:

    您可以通过以下方式更深入地了解模型:

    def prediction_up_dn_intervals( aPredictorMODEL,                        # >>> http://blog.datadive.net/prediction-intervals-for-random-forests/
                                    X_,                                     # aStateVECTOR: X_sampled
                                    aPredictorOutputIDX =  0,               # (4,2,2) -> singleQUAD ( LONG.TP/SL, SHORT.TP/SL ) <-- idxMAP( 'LONG', 'TP', 1 )
                                    aRequiredPercentile = 95
                                    ):                                      
        err_dn      = []
        err_up      = []
        #-----------------------------------------------------------------------------------------------
        if len( X_.shape ) == 1:                                            # for a single X_example run
            preds   = []
            for pred in aPredictorMODEL.estimators_:
                preds.append( pred.predict( X_ )[0,aPredictorOutputIDX] )   # de-array-ification
    
            err_dn.append( np.percentile( preds,       ( 100 - aRequiredPercentile ) / 2. ) )
            err_up.append( np.percentile( preds, 100 - ( 100 - aRequiredPercentile ) / 2. ) )
        else:
            #------------------------------------------------------------------------------------------
            for x in xrange( len( X_ ) ):                                   # for a multi X_example run
                preds   = []
                for pred in aPredictorMODEL.estimators_:
                    preds.append( pred.predict( X_[x] )[0,aPredictorOutputIDX] ) # de-array-ification
    
                err_dn.append( np.percentile( preds,       ( 100 - aRequiredPercentile ) / 2. ) )
                err_up.append( np.percentile( preds, 100 - ( 100 - aRequiredPercentile ) / 2. ) )
        #-----------------------------------------------------------------------------------------------
        return err_up, err_dn
    
    #numba.jit( 'f8(<<OBJECT>>,f8[:,:],f8[:,:],i8,f8)' )                    # <<OBJECT>> prevents JIT
    def getPredictionsOnINTERVAL(   aPredictorENGINE,                       # a MULTI-OBJECTIVE PREDICTOR -> a singleQUAD or a full 4-QUAD (16,0) <-(4,2,2)
                                    X_,
                                    y_GndTRUTH,                             # (4,2,2) -> (16,0) a MULTI-OBJECTIVE PREDICTOR
                                    aPredictionIDX  =  0,                   # (4,2,2) -> singleQUAD ( LONG.TP/SL, SHORT.TP/SL ) <-- idxMAP( 'LONG', 'TP', 1 )
                                    percentile      = 75
                                    ):
        """
        |>>> getPredictionsOnINTERVAL( loc_PREDICTOR, X_sampled, y_sampled, idxMAP( "LONG", "TP", 1 ), 75 )     1.0                         +0:01:29.375000
        |>>> getPredictionsOnINTERVAL( loc_PREDICTOR, X_sampled, y_sampled, idxMAP( "LONG", "TP", 1 ), 55 )     0.9992532724237898          +0:03:59.922000
        |>>> getPredictionsOnINTERVAL( loc_PREDICTOR, X_sampled, y_sampled, idxMAP( "LONG", "TP", 1 ), 50 )     0.997100939998243           +0:09:16.328000
        |>>> getPredictionsOnINTERVAL( loc_PREDICTOR, X_sampled, y_sampled, idxMAP( "LONG", "TP", 1 ),  5 )     0.31375735746288325         +0:01:16.422000
        """
        correct_on_interval = 0                                                 # correct        = 0. ____________________- faster to keep asINTEGER ... +=1 and only finally make DIV on FLOAT(s) in RET
        #ruth               = y_                                                # Y[idx[trainsize:]]
        err_up, err_dn      = prediction_up_dn_intervals(   aPredictorENGINE,   # ( rf,
                                                            X_,                 #   X[idx[trainsize:]],
                                                            aPredictionIDX,     #   idxMAP( "LONG", "TP", 1 ),
                                                            percentile          #   percentile = 90
                                                            )                   #   )
    
        #-------------------------------------------------------------------# for a single X_ run
        if ( len( X_.shape ) == 1 ):
            if ( err_dn[0] <= y_GndTRUTH[aPredictionIDX] <= err_up[0] ):
                return 1.
            else:
                return 0.
        #-------------------------------------------------------------------# for a multi X_ run
        for i, val in enumerate( y_GndTRUTH[:,aPredictionIDX] ):            # enumerate( truth )
            if err_dn[i] <= val <= err_up[i]:
                correct_on_interval += 1
        #-------------------------------------------------------------------
        return correct_on_interval / float( y_GndTRUTH.shape[0] )           # print correct / len( truth )
    
    def mapPredictionsOnINTERVAL(   aPredictorENGINE,                       #
                                    X_,
                                    y_GndTRUTH,
                                    aPredictionIDX      =  0,
                                    aPercentilleSTEP    =  5
                                    ):
        for aPercentille in xrange( aPercentilleSTEP, 100, aPercentilleSTEP ):
            Quotient = getPredictionsOnINTERVAL( aPredictorENGINE, X_, y_GndTRUTH, aPredictionIDX, aPercentille )
            print "{0: > 3d}-percentil   {1: > 6.3f} %".format( aPercentille, 100 * Quotient )
            """
              5%  0.313757
             10%  0.420847
             15%  0.510191
             20%  0.628481
             25%  0.719758
             30%  0.839058
             35%  0.909646
             40%  0.963454
             45%  0.986603
             50%  0.997101
             55%  0.999253
             60%  0.999912
             65%  1.000000 >>> RET/JIT
             70%  1.000000 xxxxxxxxxxxxxx 
             75%  1.000000 xxxxxxxxxxxxxx       ???? .fit( X_, y_[:,8:12] ) # .fit() on HORIZON-T0+3???? ... y_GndTRUTH.shape[1] v/s .predict().shape[1]
            """
            if ( Quotient == 1 ):
                 return
    
  • -1

    当我尝试你的代码时,我得到 AttributeError: 'module' object has no attribute 'arrange' 所以这里是你的例子的可复制版本(一般来说,我建议明确创建单独的X和Y以避免犯一个愚蠢的错误,我在看到你的问题时首先想到的) . 如下所示,随机森林分类器在训练集中的示例上表现完美 . 随机森林回归量不会产生完美的预测 . 我不知道为什么会这样,但这是一个开始的地方 .

    import numpy as np
    
    import sklearn.ensemble as se
    import numpy as np
    
    x = 0
    X_train = []
    Y_train = []
    while x < 1000:
        Y_train.append(x)
        X_train.append([x + 1, x + 2, + x + 3, x + 4])
        x += 5
    
    
    forestregression = se.RandomForestRegressor(n_estimators=1000)
    forestregression.fit(X_train, Y_train)
    
    print(forestregression.predict(X_train))
    
    [   3.005    4.96     9.015   13.875   18.9     23.985   29.18    34.24
       39.035   43.765   49.135   54.06    59.15    63.99    68.85    74.205
       79.12    84.01    88.9     93.92    98.995  104.13   108.825  114.14
      119.1    123.84   128.895  134.15   138.905  144.075  148.91   153.895
      159.165  163.83   169.065  174.195  179.03   183.975  188.915  194.06
      198.9    204.105  208.975  214.11   218.79   224.135  228.985  234.205
      239.13   244.025  249.04   254.065  258.975  264.14   269.03   274.105
      278.985  284.     288.935  294.055  299.04   304.025  308.895  313.92
      318.82   324.1    328.92   334.18   338.985  344.07   348.905  353.94
      359.115  364.11   369.     374.11   379.07   383.995  388.975  394.005
      399.035  403.91   408.99   414.125  419.165  424.17   428.86   434.14
      438.945  444.155  449.12   453.97   459.075  464.075  469.025  474.105
      478.895  483.98   489.085  494.105  498.985  504.045  508.99   514.02
      519.02   524.115  529.115  533.985  538.95   544.085  548.915  553.94
      558.935  564.035  568.925  574.12   578.925  583.995  589.21   593.99
      599.17   603.925  608.93   613.98   619.105  623.975  629.11   634.08
      638.99   644.06   648.85   654.05   659.175  664.155  669.03   673.85
      679.01   684.005  689.015  694.02   699.225  704.135  708.965  713.86
      718.88   723.84   728.99   733.835  738.985  744.205  748.99   753.74
      759.1    764.125  768.935  774.195  778.925  783.835  789.25   793.8
      798.925  804.03   809.06   813.98   819.135  823.9    828.9    834.04
      839.035  844.18   848.955  854.1    858.98   864.095  868.995  874.02
      879.165  883.795  888.905  894.245  898.965  903.8    908.98   913.945
      918.92   924.26   929.05   933.915  938.815  944.04   949.175  953.815
      959.025  963.925  968.99   974.07   979.1    984.095  988.715  992.18 ]
    
    forestclassifier = se.RandomForestClassifier(n_estimators=1000)
    forestclassifier.fit(X_train, Y_train)
    
    print(forestclassifier.predict(X_train))
    
    [  0   5  10  15  20  25  30  35  40  45  50  55  60  65  70  75  80  85
      90  95 100 105 110 115 120 125 130 135 140 145 150 155 160 165 170 175
     180 185 190 195 200 205 210 215 220 225 230 235 240 245 250 255 260 265
     270 275 280 285 290 295 300 305 310 315 320 325 330 335 340 345 350 355
     360 365 370 375 380 385 390 395 400 405 410 415 420 425 430 435 440 445
     450 455 460 465 470 475 480 485 490 495 500 505 510 515 520 525 530 535
     540 545 550 555 560 565 570 575 580 585 590 595 600 605 610 615 620 625
     630 635 640 645 650 655 660 665 670 675 680 685 690 695 700 705 710 715
     720 725 730 735 740 745 750 755 760 765 770 775 780 785 790 795 800 805
     810 815 820 825 830 835 840 845 850 855 860 865 870 875 880 885 890 895
     900 905 910 915 920 925 930 935 940 945 950 955 960 965 970 975 980 985
     990 995]
    
  • 0

    如果您的预测性能仍然很差,您可以将训练集设置为具有相同数量的0级和1级数据,以使数据中的信号更具意义 . 有关详细说明,请参阅this link .

  • 1

    有几件事你做错了/次优:

    • 你只有200行/观察,但你尝试训练N = 1000棵树 . 这是没有意义的 . 你应该没有 . 树木<<没有 . 观察结果 . N = 3-40棵树的任何地方 .

    • You are trying to learn a line: your data is perfectly linear (whereas RF's are intended for a normally-distributed response variable). 对于线性数据,使用更合适的分类器(如线性回归)会优于RF并提供完美的结果(事实上,您的所有四个特征都是线性相关的,您可以丢弃任意三列,回归仍然可以得到完美的结果)

    • 然后,您正在尝试 predict at one of the endpoints ,这是一个已知会产生偏见的问题,原因如下 . 考虑到RF是1000棵树的集合,其行是随机选择的;有些树木可能会预测到最低 endpoints (如果它处于正态分布的尾部,这不会是一个问题) . 输出预测将是整体中每棵树的个体预测的平均值:

    for i in range(1000): forest.estimators_[i].predict([1,2,3,4])

    或: np.hstack([ forest.estimators_[i].predict([1,2,3,4]) for i in range(1000) ])

    然后你会看到许多0和5,大约10,但甚至大约15s,20s和25s . 因此,您的最终预测将是一些> 0且可能<5 .

相关问题