如何按行处理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
相关产品推荐
相关产品推荐

