building up codes

This commit is contained in:
mhjensen
2019-10-29 20:40:30 +01:00
parent 766a920a69
commit b39cfc27e9
44 changed files with 2978 additions and 2182 deletions
+180
View File
@@ -399,6 +399,186 @@ s = -\sum_{k=1}^K p_{mk}\log{p_{mk}}.
!et
!split
===== The CART (Classification and Regression Tree) algorithm =====
The above functions (gini, entropy and misclassification error) are important components of the so-called CART algorithm. We will discuss this algorithm first before we move on to the information gain algorithm ID3.
!bc pycod
from random import seed
from random import randrange
from csv import reader
# Load a CSV file
def load_csv(filename):
file = open(filename, "rb")
lines = reader(file)
dataset = list(lines)
return dataset
# Convert string column to float
def str_column_to_float(dataset, column):
for row in dataset:
row[column] = float(row[column].strip())
# Split a dataset into k folds
def cross_validation_split(dataset, n_folds):
dataset_split = list()
dataset_copy = list(dataset)
fold_size = int(len(dataset) / n_folds)
for i in range(n_folds):
fold = list()
while len(fold) < fold_size:
index = randrange(len(dataset_copy))
fold.append(dataset_copy.pop(index))
dataset_split.append(fold)
return dataset_split
# Calculate accuracy percentage
def accuracy_metric(actual, predicted):
correct = 0
for i in range(len(actual)):
if actual[i] == predicted[i]:
correct += 1
return correct / float(len(actual)) * 100.0
# Evaluate an algorithm using a cross validation split
def evaluate_algorithm(dataset, algorithm, n_folds, *args):
folds = cross_validation_split(dataset, n_folds)
scores = list()
for fold in folds:
train_set = list(folds)
train_set.remove(fold)
train_set = sum(train_set, [])
test_set = list()
for row in fold:
row_copy = list(row)
test_set.append(row_copy)
row_copy[-1] = None
predicted = algorithm(train_set, test_set, *args)
actual = [row[-1] for row in fold]
accuracy = accuracy_metric(actual, predicted)
scores.append(accuracy)
return scores
# Split a dataset based on an attribute and an attribute value
def test_split(index, value, dataset):
left, right = list(), list()
for row in dataset:
if row[index] < value:
left.append(row)
else:
right.append(row)
return left, right
# Calculate the Gini index for a split dataset
def gini_index(groups, classes):
# count all samples at split point
n_instances = float(sum([len(group) for group in groups]))
# sum weighted Gini index for each group
gini = 0.0
for group in groups:
size = float(len(group))
# avoid divide by zero
if size == 0:
continue
score = 0.0
# score the group based on the score for each class
for class_val in classes:
p = [row[-1] for row in group].count(class_val) / size
score += p * p
# weight the group score by its relative size
gini += (1.0 - score) * (size / n_instances)
return gini
# Select the best split point for a dataset
def get_split(dataset):
class_values = list(set(row[-1] for row in dataset))
b_index, b_value, b_score, b_groups = 999, 999, 999, None
for index in range(len(dataset[0])-1):
for row in dataset:
groups = test_split(index, row[index], dataset)
gini = gini_index(groups, class_values)
if gini < b_score:
b_index, b_value, b_score, b_groups = index, row[index], gini, groups
return {'index':b_index, 'value':b_value, 'groups':b_groups}
# Create a terminal node value
def to_terminal(group):
outcomes = [row[-1] for row in group]
return max(set(outcomes), key=outcomes.count)
# Create child splits for a node or make terminal
def split(node, max_depth, min_size, depth):
left, right = node['groups']
del(node['groups'])
# check for a no split
if not left or not right:
node['left'] = node['right'] = to_terminal(left + right)
return
# check for max depth
if depth >= max_depth:
node['left'], node['right'] = to_terminal(left), to_terminal(right)
return
# process left child
if len(left) <= min_size:
node['left'] = to_terminal(left)
else:
node['left'] = get_split(left)
split(node['left'], max_depth, min_size, depth+1)
# process right child
if len(right) <= min_size:
node['right'] = to_terminal(right)
else:
node['right'] = get_split(right)
split(node['right'], max_depth, min_size, depth+1)
# Build a decision tree
def build_tree(train, max_depth, min_size):
root = get_split(train)
split(root, max_depth, min_size, 1)
return root
# Make a prediction with a decision tree
def predict(node, row):
if row[node['index']] < node['value']:
if isinstance(node['left'], dict):
return predict(node['left'], row)
else:
return node['left']
else:
if isinstance(node['right'], dict):
return predict(node['right'], row)
else:
return node['right']
# Classification and Regression Tree Algorithm
def decision_tree(train, test, max_depth, min_size):
tree = build_tree(train, max_depth, min_size)
predictions = list()
for row in test:
prediction = predict(tree, row)
predictions.append(prediction)
return(predictions)
# Test CART
seed(1)
# load and prepare data
filename = 'DataFiles/rideclass.csv'
dataset = load_csv(filename)
# convert string attributes to integers
for i in range(len(dataset[0])):
str_column_to_float(dataset, i)
# evaluate algorithm
n_folds = 5
max_depth = 5
min_size = 10
scores = evaluate_algorithm(dataset, decision_tree, n_folds, max_depth, min_size)
print('Scores: %s' % scores)
print('Mean Accuracy: %.3f%%' % (sum(scores)/float(len(scores))))
!ec
!split
===== Entropy and the ID3 algorithm =====
-172
View File
@@ -1,172 +0,0 @@
# CART on the Bank Note dataset
from random import seed
from random import randrange
from csv import reader
# Load a CSV file
def load_csv(filename):
file = open(filename, "rb")
lines = reader(file)
dataset = list(lines)
return dataset
# Convert string column to float
def str_column_to_float(dataset, column):
for row in dataset:
row[column] = float(row[column].strip())
# Split a dataset into k folds
def cross_validation_split(dataset, n_folds):
dataset_split = list()
dataset_copy = list(dataset)
fold_size = int(len(dataset) / n_folds)
for i in range(n_folds):
fold = list()
while len(fold) < fold_size:
index = randrange(len(dataset_copy))
fold.append(dataset_copy.pop(index))
dataset_split.append(fold)
return dataset_split
# Calculate accuracy percentage
def accuracy_metric(actual, predicted):
correct = 0
for i in range(len(actual)):
if actual[i] == predicted[i]:
correct += 1
return correct / float(len(actual)) * 100.0
# Evaluate an algorithm using a cross validation split
def evaluate_algorithm(dataset, algorithm, n_folds, *args):
folds = cross_validation_split(dataset, n_folds)
scores = list()
for fold in folds:
train_set = list(folds)
train_set.remove(fold)
train_set = sum(train_set, [])
test_set = list()
for row in fold:
row_copy = list(row)
test_set.append(row_copy)
row_copy[-1] = None
predicted = algorithm(train_set, test_set, *args)
actual = [row[-1] for row in fold]
accuracy = accuracy_metric(actual, predicted)
scores.append(accuracy)
return scores
# Split a dataset based on an attribute and an attribute value
def test_split(index, value, dataset):
left, right = list(), list()
for row in dataset:
if row[index] < value:
left.append(row)
else:
right.append(row)
return left, right
# Calculate the Gini index for a split dataset
def gini_index(groups, classes):
# count all samples at split point
n_instances = float(sum([len(group) for group in groups]))
# sum weighted Gini index for each group
gini = 0.0
for group in groups:
size = float(len(group))
# avoid divide by zero
if size == 0:
continue
score = 0.0
# score the group based on the score for each class
for class_val in classes:
p = [row[-1] for row in group].count(class_val) / size
score += p * p
# weight the group score by its relative size
gini += (1.0 - score) * (size / n_instances)
return gini
# Select the best split point for a dataset
def get_split(dataset):
class_values = list(set(row[-1] for row in dataset))
b_index, b_value, b_score, b_groups = 999, 999, 999, None
for index in range(len(dataset[0])-1):
for row in dataset:
groups = test_split(index, row[index], dataset)
gini = gini_index(groups, class_values)
if gini < b_score:
b_index, b_value, b_score, b_groups = index, row[index], gini, groups
return {'index':b_index, 'value':b_value, 'groups':b_groups}
# Create a terminal node value
def to_terminal(group):
outcomes = [row[-1] for row in group]
return max(set(outcomes), key=outcomes.count)
# Create child splits for a node or make terminal
def split(node, max_depth, min_size, depth):
left, right = node['groups']
del(node['groups'])
# check for a no split
if not left or not right:
node['left'] = node['right'] = to_terminal(left + right)
return
# check for max depth
if depth >= max_depth:
node['left'], node['right'] = to_terminal(left), to_terminal(right)
return
# process left child
if len(left) <= min_size:
node['left'] = to_terminal(left)
else:
node['left'] = get_split(left)
split(node['left'], max_depth, min_size, depth+1)
# process right child
if len(right) <= min_size:
node['right'] = to_terminal(right)
else:
node['right'] = get_split(right)
split(node['right'], max_depth, min_size, depth+1)
# Build a decision tree
def build_tree(train, max_depth, min_size):
root = get_split(train)
split(root, max_depth, min_size, 1)
return root
# Make a prediction with a decision tree
def predict(node, row):
if row[node['index']] < node['value']:
if isinstance(node['left'], dict):
return predict(node['left'], row)
else:
return node['left']
else:
if isinstance(node['right'], dict):
return predict(node['right'], row)
else:
return node['right']
# Classification and Regression Tree Algorithm
def decision_tree(train, test, max_depth, min_size):
tree = build_tree(train, max_depth, min_size)
predictions = list()
for row in test:
prediction = predict(tree, row)
predictions.append(prediction)
return(predictions)
# Test CART on Bank Note dataset
seed(1)
# load and prepare data
filename = 'DataFiles/ride.csv'
dataset = load_csv(filename)
# convert string attributes to integers
for i in range(len(dataset[0])):
str_column_to_float(dataset, i)
# evaluate algorithm
n_folds = 5
max_depth = 5
min_size = 10
scores = evaluate_algorithm(dataset, decision_tree, n_folds, max_depth, min_size)
print('Scores: %s' % scores)
print('Mean Accuracy: %.3f%%' % (sum(scores)/float(len(scores))))
-187
View File
@@ -1,187 +0,0 @@
import re
import math
from collections import deque
# x is examples in training set
# y is set of attributes
# label is target attributes
# Node is a class which has properties values, childs, and next
# root is top node in the decision tree
class Node(object):
def __init__(self):
self.value = None
self.next = None
self.childs = None
# Simple class of Decision Tree
# Aimed for who want to learn Decision Tree, so it is not optimized
class DecisionTree(object):
def __init__(self, sample, attributes, labels):
self.sample = sample
self.attributes = attributes
self.labels = labels
self.labelCodes = None
self.labelCodesCount = None
self.initLabelCodes()
# print(self.labelCodes)
self.root = None
self.entropy = self.getEntropy([x for x in range(len(self.labels))])
def initLabelCodes(self):
self.labelCodes = []
self.labelCodesCount = []
for l in self.labels:
if l not in self.labelCodes:
self.labelCodes.append(l)
self.labelCodesCount.append(0)
self.labelCodesCount[self.labelCodes.index(l)] += 1
def getLabelCodeId(self, sampleId):
return self.labelCodes.index(self.labels[sampleId])
def getAttributeValues(self, sampleIds, attributeId):
vals = []
for sid in sampleIds:
val = self.sample[sid][attributeId]
if val not in vals:
vals.append(val)
# print(vals)
return vals
def getEntropy(self, sampleIds):
entropy = 0
labelCount = [0] * len(self.labelCodes)
for sid in sampleIds:
labelCount[self.getLabelCodeId(sid)] += 1
# print("-ge", labelCount)
for lv in labelCount:
# print(lv)
if lv != 0:
entropy += -lv/len(sampleIds) * math.log(lv/len(sampleIds), 2)
else:
entropy += 0
return entropy
def getDominantLabel(self, sampleIds):
labelCodesCount = [0] * len(self.labelCodes)
for sid in sampleIds:
labelCodesCount[self.labelCodes.index(self.labels[sid])] += 1
return self.labelCodes[labelCodesCount.index(max(labelCodesCount))]
def getInformationGain(self, sampleIds, attributeId):
gain = self.getEntropy(sampleIds)
attributeVals = []
attributeValsCount = []
attributeValsIds = []
for sid in sampleIds:
val = self.sample[sid][attributeId]
if val not in attributeVals:
attributeVals.append(val)
attributeValsCount.append(0)
attributeValsIds.append([])
vid = attributeVals.index(val)
attributeValsCount[vid] += 1
attributeValsIds[vid].append(sid)
# print("-gig", self.attributes[attributeId])
for vc, vids in zip(attributeValsCount, attributeValsIds):
# print("-gig", vids)
gain -= vc/len(sampleIds) * self.getEntropy(vids)
return gain
def getAttributeMaxInformationGain(self, sampleIds, attributeIds):
attributesEntropy = [0] * len(attributeIds)
for i, attId in zip(range(len(attributeIds)), attributeIds):
attributesEntropy[i] = self.getInformationGain(sampleIds, attId)
maxId = attributeIds[attributesEntropy.index(max(attributesEntropy))]
return self.attributes[maxId], maxId
def isSingleLabeled(self, sampleIds):
label = self.labels[sampleIds[0]]
for sid in sampleIds:
if self.labels[sid] != label:
return False
return True
def getLabel(self, sampleId):
return self.labels[sampleId]
def id3(self):
sampleIds = [x for x in range(len(self.sample))]
attributeIds = [x for x in range(len(self.attributes))]
self.root = self.id3Recv(sampleIds, attributeIds, self.root)
def id3Recv(self, sampleIds, attributeIds, root):
root = Node() # Initialize current root
if self.isSingleLabeled(sampleIds):
root.value = self.labels[sampleIds[0]]
return root
# print(attributeIds)
if len(attributeIds) == 0:
root.value = self.getDominantLabel(sampleIds)
return root
bestAttrName, bestAttrId = self.getAttributeMaxInformationGain(
sampleIds, attributeIds)
# print(bestAttrName)
root.value = bestAttrName
root.childs = [] # Create list of children
for value in self.getAttributeValues(sampleIds, bestAttrId):
# print(value)
child = Node()
child.value = value
root.childs.append(child) # Append new child node to current
# root
childSampleIds = []
for sid in sampleIds:
if self.sample[sid][bestAttrId] == value:
childSampleIds.append(sid)
if len(childSampleIds) == 0:
child.next = self.getDominantLabel(sampleIds)
else:
# print(bestAttrName, bestAttrId)
# print(attributeIds)
if len(attributeIds) > 0 and bestAttrId in attributeIds:
toRemove = attributeIds.index(bestAttrId)
attributeIds.pop(toRemove)
child.next = self.id3Recv(
childSampleIds, attributeIds, child.next)
return root
def printTree(self):
if self.root:
roots = deque()
roots.append(self.root)
while len(roots) > 0:
root = roots.popleft()
print(root.value)
if root.childs:
for child in root.childs:
print('({})'.format(child.value))
roots.append(child.next)
elif root.next:
print(root.next)
def test():
f = open('rideclass.csv')
attributes = f.readline().split(',')
attributes = attributes[1:len(attributes)-1]
print(attributes)
sample = f.readlines()
f.close()
for i in range(len(sample)):
sample[i] = re.sub('\d+,', '', sample[i])
sample[i] = sample[i].strip().split(',')
labels = []
for s in sample:
labels.append(s.pop())
# print(sample)
# print(labels)
decisionTree = DecisionTree(sample, attributes, labels)
print("System entropy {}".format(decisionTree.entropy))
decisionTree.id3()
decisionTree.printTree()
if __name__ == '__main__':
test()
-29
View File
@@ -1,29 +0,0 @@
from sklearn.datasets import load_breast_cancer
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.tree import export_graphviz
from IPython.display import Image
from pydot import graph_from_dot_data
import pandas as pd
import numpy as np
cancer = load_breast_cancer()
X = pd.DataFrame(cancer.data, columns=cancer.feature_names)
y = pd.Categorical.from_codes(cancer.target, cancer.target_names)
y = pd.get_dummies(y)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
tree_clf = DecisionTreeClassifier(max_depth=5)
tree_clf.fit(X_train, y_train)
export_graphviz(
tree_clf,
out_file="cancer.dot",
feature_names=cancer.feature_names,
class_names=cancer.target_names,
rounded=True,
filled=True
)
-80
View File
@@ -1,80 +0,0 @@
# Common imports
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.tree import export_graphviz
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from IPython.display import Image
from pydot import graph_from_dot_data
import os
# Where to save the figures and data files
PROJECT_ROOT_DIR = "Results"
FIGURE_ID = "Results/FigureFiles"
DATA_ID = "DataFiles/"
if not os.path.exists(PROJECT_ROOT_DIR):
os.mkdir(PROJECT_ROOT_DIR)
if not os.path.exists(FIGURE_ID):
os.makedirs(FIGURE_ID)
if not os.path.exists(DATA_ID):
os.makedirs(DATA_ID)
def image_path(fig_id):
return os.path.join(FIGURE_ID, fig_id)
def data_path(dat_id):
return os.path.join(DATA_ID, dat_id)
def save_fig(fig_id):
plt.savefig(image_path(fig_id) + ".png", format='png')
infile = open(data_path("ride.csv"),'r')
# Read the experimental data with Pandas
from IPython.display import display
ridedata = pd.read_csv(infile,names = ('Outlook','Temperature','Humidity','Wind','Ride'))
ridedata = pd.DataFrame(ridedata)
display(ridedata)
# Features and targets
X = ridedata.loc[:, ridedata.columns != 'Ride'].values
display(X)
y = ridedata.loc[:, ridedata.columns == 'Ride'].values
display(y)
# Categorical variables to one-hot's
onehotencoder = OneHotEncoder(categories="auto")
X = ColumnTransformer(
[("", onehotencoder)],
remainder="passthrough").fit_transform(X)
y.shape
display(X)
display(y)
"""
X = pd.DataFrame(ridedata.data, columns=ridedata.feature_names)
y = pd.Categorical.from_codes(ridedata.target, ridedata.target_names)
y = pd.get_dummies(y)
tree_clf = DecisionTreeClassifier(max_depth=2)
tree_clf.fit(X, y)
export_graphviz(
tree_clf,
out_file="ride.dot",
feature_names=tree_clf.feature_names,
class_names=tree_clf.target_names,
rounded=True,
filled=True
)
"""