You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按行处理Pandas DataFrame实现ID3算法新根属性的分支拆分

ID3算法实现分支拆分需求

我在实现ID3算法,遇到新根属性分支处理的问题,当前运行打印输出如下:

gain: 1.263221025628615 for Material
processing attribute Volume
processing branch 1 for Volume
processing branch 6 for Volume
processing branch 4 for Volume
processing branch 2 for Volume
processing branch 5 for Volume
processing branch 3 for Volume
gain: 0.6036978279454468 for Volume
attribute Venue has the max gain of 0.6036978279454468
removing Venue
new root Venue has branches [2 1]

现有实现代码

from numpy.core.defchararray import count
import pandas as pd
import numpy as np
from math import ceil, floor, log2
from sklearn.decomposition import PCA
from numpy import linalg as LA
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB

def calculate_metrics(tp, tn, fn, p, n, fp):
    # calculate the accuracy, error rate, sensitivity, specificity, and precision for the selected classifier in reference to the corresponding test set.
    accuracy = tp + tn /(p+n)
    error_rate = fp + fn /(p + n)
    sensitivity = tp/ p
    precision = tp/ (tp+fp)
    specificity = tn/n

    display_metrics(accuracy, error_rate, sensitivity, precision, specificity)

def display_metrics(accuracy, error_rate, sensitivity, precision, specificity):
    print(f'Accuracy: {accuracy}, Error_rate:{error_rate}, Sensitivity:{sensitivity}, Precision:{precision}, specificity:{specificity}')

def mc(columnName,training_set):
    column = training_set[columnName]
    probs = column.value_counts(normalize=True)
    messageConveyed = -1*np.sum(np.log2(probs)*probs)
    # print(f'mc {messageConveyed}')
    return messageConveyed

def isUnique(s):
    a = s.to_numpy() # s.values (pandas<0.24)
    return (a[0] == a).all()

def ID3(threshold,g):
    # use the training set to predict the test set.
    # use the Assignment 2--Training set to extract rules and test the quality of the extracted rules against the Assignment 2-- Test set for ID3.
    test_set = pd.read_csv("Assignment 2--Test set for ID3.csv")
    training_set = pd.read_csv("Assignment 2--Training set for ID3.csv")

    print('***********************************')
    print('TRAINING SET')
    print(training_set)
    print('***********************************')


    print('***********************************')
    print('TEST SET')
    print(test_set)
    print('***********************************')

    print(f'test_set: {test_set}')
    print(f'training_set: {training_set}')

    # Step 1- Calculate MC (Message Conveyed) for the given data set in reference to the class attribute
    print(f'Step 1- Calculate MC (Message Conveyed) for the given data set in reference to the class attribute')
    # MC = -p1*log2(p1) - p2*log2(p2)
    # For n classes MC = -p1log2(p1) - p2*log2(p2)-...-pn*log2(pn)

    # For each column calculate the gain.
    numberOfColumns = 0
    mcDictionary = {}
    print('***********************************')
    print('For each column calculate the gain.')
    for (columnName, columnData) in training_set.iteritems():
        messageConveyed = mc(columnName,training_set)
        mcDictionary.update({columnName:round(messageConveyed)})
        numberOfColumns+=1
    print('***********************************')
    print(f'numberOfColumns {numberOfColumns}')
    print(f'mcDictionary {mcDictionary}')


    # The column with the highest gain is the root.
    print(f'The column with the highest gain is the root.')
    values = mcDictionary.values()
    max_value = max(values)
    print(f'The max value is {max_value}')
    # print(f'The max value, {max_value}, is associated with column {columnWithMaximumInformationGain}')
    val_list = list(values)
    columnWithMaximumInformationGain = list(mcDictionary.keys())[list(mcDictionary.values()).index(max_value)]
    print(f'The max value, {max_value}, is associated with column {columnWithMaximumInformationGain}')

    # select the max value from the gain array
    # this is the new root
    root =  columnWithMaximumInformationGain
    print(f'root is {root}')
    print("******************************************")
    print("**************   ROOT   ******************")
    print(f"TF is {root}**********************")
    print("******************************************")
    print(f'isUnique = {isUnique(training_set[root])}')
    if(isUnique(training_set[root])):
        return   
    
    # Step 2 - Repeat for every attribute
    print(f'Step 2 - Repeat for every attribute')
    # Loop 1
    attribute = ""
    maximum       = 0 
    for (F, columnData) in training_set.iteritems():
        print(f'processing attribute {F}')
        # Loop 2
        Total = 0
        uniques = training_set[F].unique()
        for k in uniques:
            print(f'processing branch {k} for {F}')
            # Calculate MC for column
            messageConveyed = mc(F,training_set)

            # Calculate the weight for F
            F_D    = training_set[F].count()
            TF_D   = training_set[root].count()

            weight = F_D/TF_D
            total = weight*messageConveyed
        gain = mcDictionary[root] - total
        if(gain > maximum):
            attribute = F
            maximum   = gain 
        print(f"gain: {gain} for {F}")
    
    print(f'attribute {attribute} has the max gain of {gain}')
    print(f'removing {attribute}')
    root = attribute
    print(f'new root {root} has branches {training_set[root].unique()}')
    del training_set[attribute]

    # Step 3 - Examine dataset of each leaf
    print(f'')


def BayesClassifier(training_set,test_set):
    # use the assignment 2-- training set for Bayes as the training set to classify the records of the assignment 2 test set for bayes
    X = test_set.values
    Y = training_set.values
    clf = GaussianNB()
    clf.fit(X, Y)




# prompt user to select either ID3 or Bayes classifier.
selection = "ID3" #= input("Please enter your selection for either ID3 or Bayes classification: ")
threshold = 0.9   #= input("Please enter a threshold: ")
g         = 0.05   #= input("Please enter a value for g: ")

if(selection == "ID3"):
    ID3(threshold,g)

if(selection == "Bayes"):
    BayesClassifier()

所用训练集

Venue,color,Model,Category,Location,weight,Veriety,Material,Volume
2,6,4,4,4,2,2,1,1
1,2,4,4,4,1,6,2,6
1,5,4,4,4,1,2,1,6
2,4,4,4,4,2,6,1,4
1,4,4,4,4,1,2,2,2
2,4,3,3,3,2,1,1,1
1,5,2,1,4,1,6,2,6
1,2,3,3,3,1,2,1,6
2,6,4,4,4,2,3,1,1
1,4,4,4,4,1,2,1,6
1,5,4,4,4,1,2,1,4
实现方案

固定拆分Venue为1和2的两个子集

直接用pandas布尔索引过滤即可:

# 提取Venue值为1的所有行
df_venue_1 = training_set[training_set['Venue'] == 1].reset_index(drop=True)
# 提取Venue值为2的所有行
df_venue_2 = training_set[training_set['Venue'] == 2].reset_index(drop=True)

reset_index(drop=True)用于重置子数据集的行索引,避免后续处理出现索引混乱,不需要可以删除。

通用分支拆分方法(适合ID3递归场景)

如果需要兼容任意根属性、任意数量的分支值,用遍历唯一值的方式存为字典更灵活:

branch_datasets = {}
# 遍历当前根属性的所有唯一分支值
for val in training_set[root].unique():
    # 过滤出对应分支的子集,存入字典
    branch_datasets[val] = training_set[training_set[root] == val].reset_index(drop=True)

调用时直接取branch_datasets[1]、branch_datasets[2]即可得到对应分支的数据集。

内容的提问来源于stack exchange,提问作者Evan Gertis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 21:45:03