Sklearn DecisionClassifier提取规则

发布时间 2023-07-17 02:19:56作者: 动量不守恒的浩
children_left    = clf.tree_.children_left            # 左节点编号
children_right   = clf.tree_.children_right            # 右节点编号
feature        = clf.tree_.feature               # 分割的变量
threshold       = clf.tree_.threshold              # 分割阈值
impurity       = clf.tree_.impurity               # 不纯度(gini)
n_node_samples   = clf.tree_.n_node_samples            # 样本个数
value         = clf.tree_.value                 # 样本分布
 
#-------------打印------------------------------
print("children_left:",children_left)        
print("children_right:",children_right)
print("feature:",feature)
print("threshold:",threshold)
print("impurity:",impurity)
print("n_node_samples:",n_node_samples)
print("value:",value)




在第一题第二问中我们希望的到“训练好的模型的规则在测试集上表现最好的几条”。解读为模型为训练集训练的树,而需要重新编写函数评价树的每个结点在测试集上的表现。我认为每条规则的正确率即为该结点下预测正确的所有样本/该结点往下所有样本。且这种解释符合实际生产知道需求。
由于sklearn的DecisionTree并不提供更深层的属性,最终我编写了一套递归代码用于提起最好的几条规则(结点).

"""在实际生产中我们需要知道在测试集上最优的几个特征以指导生产"""
def get_lastnodenum(test_onesample,node_num):
    left_node    = children_left[node_num]            # 左节点编号
    right_node   = children_right[node_num]
    if left_node < 0 or right_node < 0:
        return node_num
    else:  
        if test_onesample[feature[node_num]]<threshold[node_num]:
            return get_lastnodenum(test_onesample,left_node)
        else:
            return get_lastnodenum(test_onesample,right_node)

def last_node_find(test_data):
    N=len(test_data)#测试集样本数
    return [get_lastnodenum(test_data.to_numpy()[i,:],0) for i in range(N)]


def recursion(node_num,lastnode_PreTrue,lastnode_PreCount,lastnode_num):
    #递归遍历节点

    left_node    = children_left[node_num]            # 左节点编号
    right_node   = children_right[node_num]

    if left_node < 0 or right_node < 0:
        try:
            ind=lastnode_num.index(node_num)
            TrueCount_list[node_num]=lastnode_PreTrue[lastnode_num.index(node_num)]
            AllCount_List[node_num]=lastnode_PreCount[lastnode_num.index(node_num)]
        except:
            TrueCount_list[node_num]=0
            AllCount_List[node_num]=0
    else:
        recursion(left_node,lastnode_PreTrue,lastnode_PreCount,lastnode_num)
        recursion(right_node,lastnode_PreTrue,lastnode_PreCount,lastnode_num)
        TrueCount_list[node_num]=TrueCount_list[left_node]+TrueCount_list[right_node]
        AllCount_List[node_num]=AllCount_List[left_node]+AllCount_List[right_node]
    
def Feature_Extra(clf,test_data,test_label):

    PredictCorrect=(clf.predict(test_data)==test_label)
    lastnode_list=last_node_find(test_data)#test_data中所有样本所属的尾节点

    df = pd.DataFrame({'PredictCorrect':PredictCorrect,'lastnode': lastnode_list})
    PreTrue=df.groupby(['lastnode'])['PredictCorrect'].sum()
    PreCount=df.groupby(['lastnode'])['PredictCorrect'].count()
    lastnode_num=PreTrue.index.to_list()
    lastnode_PreTrue=PreTrue.to_list()
    lastnode_PreCount=PreCount.to_list()
    recursion(0,lastnode_PreTrue,lastnode_PreCount,lastnode_num)
    
    Acc_list=[TrueCount_list[i]/AllCount_List[i] if AllCount_List[i]!=0 else 0  for i in range(n)]
    return Acc_list

n=len(children_left)
TrueCount_list=[0]*n
AllCount_List=[0]*n
Acc_list=Feature_Extra(clf,X_test,y_test)

np.array(Acc_list).argsort()