Python実装決定ツリー(シリーズ記事7)--連続型変数属性値分割修正

20430 ワード

1問題


私の例では、連続変数の属性値の2点選択は、まずパーセントカット(100部に切る)を行い、その後、これらのカットポイントのgini指数を循環的にテストすることによって行われる.1つの変数は約100回のテストを実行し、通常のpythonコードの実行は単一プロセスであるため、待機をブロックし、多くの時間と計算力を浪費します.

2考え方


すべてのカットポイントテストをマトリクス計算に変更すると、最適化された計算のたびに、元の5%未満の時間が推定されます.
実装には約3つのステップがあります.
  • 1変数の分割点ベクトル
  • を得る.
  • 2は2つの区間ベクトルを構築する、ベクトル減算により1(選択)と0(選択なし)の選択ベクトル
  • を構築する.
  • 3行列選択ベクトル(行列)とターゲットのgini最小値
  • を計算する.

    3コード修正

  • 3.1元の関数コード
  • def cbcut(data=None, pstart=0.1, pend=0.9):
            data = data.copy()
            #  10~90 
            #  linspace (0.1, 0.11,... 0.9)
            bins = int((pend - pstart) * 100 + 1)
            qlist = np.linspace(pstart, pend, bins)
    
            #  , (unique )
            qtiles = data.quantile(qlist).unique()
            res_list = []
            for q in qtiles:
                data1 = data.apply(lambda x: 1 if x < q else 0)
                res_list.append(data1)
            res_dict = {
         }
            res_dict['data_list'] = res_list
            res_dict['qtiles'] = qtiles
            return res_dict
    
    
  • 3.2改良コード
  • def cal_min_gini_mat(mat=None, y=0):
        #  
        totals = len(y)
        # left
        left_total = (1 - mat).sum(axis=0)
    
        left_weight = left_total / totals
        left_p1 = (1-mat)@y / left_total
        left_p0 = 1 - left_p1
    
        l_gini = left_weight * (1 - left_p1 ** 2 - left_p0 ** 2)
    
        # right
        right_total = mat.sum(axis=0)
    
        right_weight = right_total / totals
        right_p1 = mat @y / right_total
        right_p0 = 1 - right_p1
    
        r_gini = right_weight * (1 - right_p1 ** 2 - right_p0 ** 2)
    
        _gini = l_gini + r_gini
        return min(_gini), _gini.argmin()
    
    def Ctype_Search(x = None, y = None,pstart = 0.1,pend = 0.9):
        bins = int((pend - pstart) * 100 + 1)
        qlist = np.linspace(pstart, pend, bins)
        qtiles = x.quantile(qlist).unique()
        #  C 
        #  qtiles 
        qtiles1 = np.expand_dims(qtiles, -1)
        mat = (x.values < qtiles1) * 1
    
        # X = mat.T  # (99020, 26)
        min_gini , min_pos = cal_min_gini_mat(mat=mat.T, y = y)
        return min_gini, qtiles[min_pos]
        
    

    4例


    データのダウンロード
    #  
    In [156]: res_df.head()                                                         
    Out[156]: 
          x  y
    157500.0  0
    67500.0  0
    90000.0  0
    405000.0  1
    90000.0  0
    。。。
    
    
    # >>>>>>>>>>>>>>>>>>>>>> before
    import time 
    st = time.time()
    iTree.find_min_gini(x=x, y=y, vartype='C', varname='AMT_INCOME_TOTAL')
    print('It takes %.3f seconds' % time.time() - st)
    
    In [13]: import time  
        ...: st = time.time() 
        ...: iTree.find_min_gini(x=x, y=y, vartype='C', varname='AMT_INCOME_TOTAL') 
        ...: print('It takes %.3f seconds' % (time.time() - st))                    
    It takes 1.665 seconds
    
    In [158]: tree_res['AMT_INCOME_TOTAL'].keys()                                   
    Out[158]: dict_keys(['gini', 'condition_left', 'condition_right'])
    
    In [159]: tree_res['AMT_INCOME_TOTAL']['gini']                                  
    Out[159]: 0.150674339064104
    
    In [160]: tree_res['AMT_INCOME_TOTAL']['condition_left']                        
    Out[160]: '<247500.0'
    
    In [161]: tree_res['AMT_INCOME_TOTAL']['condition_right']                       
    Out[161]: '>=247500.0'
    
    # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> after
    In [162]: import time  
         ...: st = time.time() 
         ...: tree_res = Ctype_Search(x,y) 
         ...: print('It takes %.3f seconds' % (time.time() - st))                   
    It takes 0.032 seconds
    
    In [163]: tree_res                                                              
    Out[163]: (0.150674339064104, 247500.0)
    
    

    50倍近くなったのに木があるの?