<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Decision Trees
By Parijat Mazumdar (GitHub ID
Step1:  We want to create a decision tree from the above training dataset. The first step for that is to encode the data into numeric values and bind them to Shogun's features and multiclass labels.
Step2:  Next, we learn our decision tree using the features and labels created.
Step3:  Our decision tree is ready now and we want to use it to make some predictions over test data. So, let us create some test data examples first.
Step4:  Next, as with training data, we encode our test dataset and bind it to Shogun features. Then, we apply our decision tree to the test examples to obtain the predicted labels.
Step5:  Finally let us tabulate the results obtained and compare them with our intuitive predictions.
Step6:  So, do the predictions made by our decision tree match our inferences from training set? Yes! For example, from the training set we infer that the individual having low income has low usage and also all individuals going to college have medium usage. The decision tree predicts the same for both cases. 
Example using a real dataset
We choose the car evaluation dataset from the UCI Machine Learning Repository as our real-world dataset. The car.names file of the dataset enumerates the class categories as well as the non-class attributes. Each car categorized into one of 4 classes 
Step7:  Next, let us read the file and form Shogun features and labels.
Step8:  From the entire dataset, let us choose some test vectors to form our test dataset.
Step9:  Next step is to train our decision tree using the training features and applying it to our test dataset to get predicted output classes.
Step10:  Finally, let us compare our predicted labels with test labels to find out the percentage error of our classification model.
Step11:  We see that the accuracy is moderately high. Thus our decision tree can evaluate any car given its features with a high success rate. As a final exercise, let us examine the effect of training dataset size on the accuracy of decision tree.
Step12:  NOTE 
Step13:  In the above plot the training data points are are marked with different colours of crosses where each colour corresponds to a particular label. The test data points are marked by black circles. For us it is a trivial task to assign correct colours (i.e. labels) to the black points. Let us see how accurately C4.5 assigns colours to these test points.
Now let us train a decision tree using the C4.5 algorithm. We need to create a Shogun C4.5 tree object and supply training features and training labels to it. We also need to specify which attribute is categorical and which is continuous. The attribute types can be specified using set_feature_types method through which all categorical attributes are set as True and continuous attributes as False.
Step14:  Now that we have trained the decision tree, we can use it to classify our test vectors.
Step15:  Let us use the output labels to colour our test data points to qualitatively judge the performance of the decision tree.
Step16:  We see that the decision tree trained using the C4.5 algorithm works almost perfectly in this toy dataset. Now let us try this algorithm on a real world dataset. 
Example using a real dataset
In this section we will investigate that how accurately we can predict the species of an Iris flower using a C4.5 trained decision tree. In this example we will use petal length, petal width, sepal length and sepal width as our attributes to decide among 3 classes of Iris 
Step17:  Because there is no separate test dataset, we first divide the given dataset into training and testing subsets.
Step18:  Before marching forward with applying C4.5, let us plot the data to get a better understanding. The given data points are 4-D and hence cannot be conveniently plotted. We need to reduce the number of dimensions to 2. This reduction can be achieved using any dimension reduction algorithm like PCA. However for the sake of brevity, let us just choose two highly correlated dimensions, petal width and petal length (see summary statistics), right away for plotting.
Step19:  First, let us create Shogun features and labels from the given data.
Step20:  We know for fact that decision trees tend to overfit. Hence pruning becomes a necessary step. In case of toy dataset, we skipped the pruning step because the dataset was simple and noise-free. But in case of a real dataset like the Iris dataset pruning cannot be skipped. So we have to partition the training dataset into the training subset and the validation subset.
Step21:  Now we train the decision tree first, then prune it and finally use it to get output labels for test vectors.
Step22:  Let us calculate the accuracy of the classification made by our tree as well as plot the results for qualitative evaluation.
Step23:  From the evaluation of results, we infer that, with the help of a C4.5 trained decision tree, we can predict (with high accuracy) the type of Iris plant given its petal and sepal widths and lengths.
Classification and Regression Trees (CART)
The CART algorithm is a popular decision tree learning algorithm introduced by Breiman et al. Unlike ID3 and C4.5, the learnt decision tree in this case can be used for both multiclass classification and regression depending on the type of dependent variable. The tree growing process comprises of recursive binary splitting of nodes. To find the best split at each node, all possible splits of all available predictive attributes are considered. The best split is the one that maximises some splitting criterion. For classification tasks, ie. when the dependent attribute is categorical, the Gini index is used as the splitting criterion. For regression tasks, ie. when the dependent variable is continuous, the least squares deviation is used. Let us learn about Shogun's CART implementation by working on two toy problems, one on classification and the other on regression.
Classification example using toy data
Let us consider the same dataset as that in the C4.5 toy example. We re-create the dataset and plot it first.
Step24:  Next, we supply necessary parameters to the CART algorithm and use it train our decision tree.
Step25:  In the above code snippet, we see four parameters being supplied to the CART tree object. feat_types supplies knowledge of attribute types of training data to the CART algorithm and problem_type specifies whether it is a multiclass classification problem (PT_MULTICLASS) or a regression problem (PT_REGRESSION). The boolean parameter use_cv_pruning switches on cross-validation pruning  of the trained tree and num_folds specifies the number of folds of cross-validation to be applied while pruning. At this point, let us divert ourselves briefly towards undertanding what kind of pruning strategy is employed by Shogun's CART implementation. The CART algorithm uses the cost-complexity pruning strategy. Cost-Complexity pruning yields a list of subtrees of varying depths using complexity normalized resubstitution error, $R_\alpha(T)$. Resubstitution error, R(T), measures how well a decision tree fits the training data. But, this measure favours larger trees over smaller ones. Hence the complexity normalized resubstitution error metric is used which adds penalty for increased complexity and in-turn counters overfitting.
$R_\alpha(T)=R(T)+\alpha \times (numleaves)$
The best subtree among the list of subtrees can be chosen using cross validation or using the best-fit metric in the validation dataset. Setting use_cv_pruning in the above code snippet basically tells the CART object to use cross-validation to choose the best among the subtrees generated by cost-complexity pruning.
Let us now get back on track and use the trained tree to classify our test data.
Step26:  Regression example using toy data
In this example, we form the training dataset by sampling points from a sinusoidal curve and see how well a decision tree, trained using these samples, re-creates the actual sinusoid.
Step27:  Next, we train our CART-tree.
Step28:  Now let us use the trained decision tree to regress over the entire range of the previously depicted sinusoid.
Step29:  As we can see from the above plot, CART-induced decision tree follows the reference sinusoid quite beautifully!
Classification example using real dataset
In this section, we will apply the CART algorithm on the Iris dataset. Remember that the Iris dataset provides us with just a training dataset and no separate test dataset. In case of the C4.5 example discussed earlier, we ourselves divided the entire training dataset into training subset and test subset. In this section, we will employ a different strategy i.e. cross validation. In cross-validation, we divide the training dataset into n subsets where n is a user controlled parameter. We perform n iterations of training and testing in which, at each iteration, we choose one of the n subsets as our test dataset and the remaining n-1 subsets as our training dataset. The performance of the model is usually taken as the average of the performances in various iterations. Shogun's cross validation class makes it really easy to apply cross-validation to any model of our choice. Let us realize this by applying cross-validation to CART-tree trained over Iris dataset. We start by reading the data.
Step30:  Next, we setup the model which is CART-tree in this case.
Step31:  Finally we can use Shogun's cross-validation class to get performance.
Step32:  We get a mean accuracy of about 0.93-0.94. This number essentially means that a CART-tree trained using this dataset is expected to classify Iris flowers, given their required attributes, with an accuracy of 93-94% in a real world scenario. The parameters required by Shogun's cross-validation class should be noted in the above code snippet. The class requires the model, training features, training labels, splitting strategy and evaluation method to be specified. 
Regression using real dataset
In this section, we evaluate CART-induced decision tree over the Servo dataset. Using this dataset, we essentially want to train a model  which can predict the rise time of a servomechanism given the required parameters which are the two (integer) gain settings and two (nominal) choices of mechanical linkages. Let us read the dataset first.
Step33:  The servo dataset is a small training dataset (contains just 167 training vectors) with no separate test dataset, like the Iris dataset. Hence we will apply the same cross-validation strategy we applied in case of the Iris dataset. However, to make things interesting let us play around with a yet-untouched parameter of CART-induced tree i.e. the maximum allowed tree depth. As the tree depth increases, the tree becomes more complex and hence fits the training data more closely. By setting a maximum allowed tree depth, we restrict the complexity of trained tree and hence avoid over-fitting. But choosing a low value of the maximum allowed tree depth may lead to early stopping i.e. under-fitting. Let us explore how we can decide the appropriate value of the max-allowed-tree-depth parameter. Let us create a method, which takes max-allowed-tree-depth parameter as input and returns the corresponding cross-validated error as output.
Step34:  Next, let us supply a range of max_depth values to the above method and plot the returned cross-validated errors.
Step35:  From the above plot quite clearly gives us the most appropriate value of maximum allowed depth. We see that the first minima occurs at a maximum allowed depth of 6-8. Hence, one of these should be the desired value. It is to be noted that the error metric that we are discussing here is the mean squared error. Thus, from the above plot, we can also claim that, given required parameters, our CART-flavoured decision tree can predict the rise time within an average error range of $\pm0.5$ (i.e. square root of 0.25 which is the approximate minimum cross-validated error). The relative error i.e  average_error/range_of_labels comes out to be ~30%.
CHi-squared Automatic Interaction Detection (CHAID)
The CHAID is an algorithm for decision tree learning proposed by Kass (1980). It is similar in functionality to CART in the sense that both can be used for classification as well as regression. But unlike CART, CHAID internally handles only categorical features. The continuous features are first converted into ordinal categorical features for the CHAID algorithm to be able to use them. This conversion is done by binning of feature values.The number of bins (K) has to be supplied by the user. Given K, a predictor is split in such a way that all the bins get the same number (more or less) of distinct predictor values. The maximum feature value in each bin is used as a breakpoint.
An important parameter in the CHAID tree growing process is the p-value. The p-value is the metric that is used for deciding which categories of predictor values to merge during merging as well as for deciding the best attribute during splitting. The p-value is calculated using different hypothesis testing methods depending on the type of dependent variable (nominal, ordinal or continuous). A more detailed discussion on the CHAID algorithm can be found in the documentation of the CCHAIDTree class in Shogun. Let us move on to a more interesting topic which is learning to use CHAID using Shogun's python API.  
Classification example using toy dataset
Let us re-use the toy classification dataset used in C4.5 and CART to see the API usage of CHAID as well as to qualitatively compare the results of the CHAID algorithm with the other two.
Step36:  Now, we set up our CHAID-tree with appropriate parameters and train over given data.
Step37:  An important point to be noted in the above code snippet is that CHAID training modifies the training data. The actual continuous feature values are replaced by the discrete ordinal values obtained during continuous to ordinal conversion. Notice the difference between the original feature matrix and the updated matrix. The updated matrix contains only 10 distinct values denoting all values of the original matrix for feature dimension at row index 1.
With a CHAID-trained decision tree at our disposal, it's time to apply it to colour our test points.
Step38:  Regression example with toy dataset
In this section, we re-work the sinusoid curve fitting example (earlier used in CART toy regression).
Step39:  As usual, we start by setting up our decision tree and training it.
Step40:  Next, we use the trained decision tree to follow the reference sinusoid.
Step41:  A distinguishing feature about the predicted curve is the presence of steps. These steps are essentially an artifact of continuous to ordinal conversion. If we decrease the number of bins for the conversion the step widths will increase.
Classification example over real dataset
In this section, we will try to estimate the quality of wine based on 13 attributes like alcohol content, malic acid, magnesium content, etc. using the wine dataset. Let us first read the dataset using Shogun's CSV file reader.
Step42:  Like the case of CART, here we are also interested in finding out the approximate accuracy with which our CHAID tree trained on this dataset will perform in real world. Hence, we will apply the cross validation strategy. But first we specify the parameters of the CHAID tree.
Step43:  Next we set up the cross-validation class and get back the error estimate we want i.e mean classification error.
Step44:  Regression example using real dataset
In this section, we try to predict the value of houses in Boston using 13 attributes, like per capita crime rate in neighborhood, number of rooms, nitrous oxide concentration in air, proportion of non-retail business in the area etc. Out of the 13 attributes 12 are continuous and 1 (the Charles river dummy variable) is binary nominal. Let us load the dataset as our first step. For this, we can directly use Shogun's CSV file reader class.
Step45:  Next, we set up the parameters for the CHAID tree as well as the cross-validation class.
<ASSISTANT_TASK:>
Python Code:
import os
import numpy as np
import shogun as sg
import matplotlib.pyplot as plt
%matplotlib inline
SHOGUN_DATA_DIR=os.getenv('SHOGUN_DATA_DIR', '../../../../data')
# training data
train_income=['Low','Medium','Low','High','Low','High','Medium','Medium','High','Low','Medium',
'Medium','High','Low','Medium']
train_age = ['Old','Young','Old','Young','Old','Young','Young','Old','Old','Old','Young','Old',
'Old','Old','Young']
train_education = ['University','College','University','University','University','College','College',
'High School','University','High School','College','High School','University','High School','College']
train_marital = ['Married','Single','Married','Single','Married','Single','Married','Single','Single',
'Married','Married','Single','Single','Married','Married']
train_usage = ['Low','Medium','Low','High','Low','Medium','Medium','Low','High','Low','Medium','Low',
'High','Low','Medium']
# print data
print('Training Data Table : \n')
print('Income \t\t Age \t\t Education \t\t Marital Status \t Usage')
for i in range(len(train_income)):
	print(train_income[i]+' \t\t '+train_age[i]+' \t\t '+train_education[i]+' \t\t '+train_marital[i]+' \t\t '+train_usage[i])
Explanation: Decision Trees
By Parijat Mazumdar (GitHub ID: mazumdarparijat)
This notebook illustrates the use of decision trees in Shogun for classification and regression. Various decision tree learning algorithms like ID3, C4.5, CART, CHAID have been discussed in detail using both intuitive toy datasets as well as real-world datasets.
Decision Tree Basics
Decision Trees are a non-parametric supervised learning method that can be used for both classification and regression. Decision trees essentially encode a set of if-then-else rules which can be used to predict target variable given data features. These if-then-else rules are formed using the training dataset with the aim to satisfy as many training data instances as possible. The formation of these rules (aka. decision tree) from training data is called decision tree learning. Various decision tree learning algorithms have been developed and they work best in different situations. An advantage of decision trees is that they can model any type of function for classification or regression which other techniques cannot. But a decision tree is highly prone to overfitting and bias towards training data. So, decision trees are used for very large datasets which are assumed to represent the ground truth well. Additionally, certain tree pruning algorithms are also used to tackle overfitting.   
ID3 (Iterative Dichotomiser 3)
ID3 is a straightforward decision tree learning algorithm developed by Ross Quinlan. ID3 is applicable only in cases where the attributes (or features) defining data examples are categorical in nature and the data examples belong to pre-defined, clearly distinguishable (ie. well defined) classes. ID3 is an iterative greedy algorithm which starts with the root node and eventually builds the entire tree. At each node, the "best" attribute to classify data is chosen. The "best" attribute is chosen using the information gain metric. Once an attribute is chosen in a node, the data examples in the node are categorized into sub-groups based on the attribute values that they have. Basically, all data examples having the same attribute value are put together in the same sub-group. These sub-groups form the children of the present node and the algorithm is repeated for each of the newly formed children nodes. This goes on until all the data members of a node belong to the same class or all the attributes are exhausted. In the latter case, the class predicted may be erroneous and generally the mode of the classes appearing in the node is chosen as the predictive class. 
Pseudocode for ID3 Algorithm
Example using a Simple dataset
In this section, we create a simple example where we try to predict the usage of mobile phones by individuals based on their income, age, education and marital status. Each of the attributes have been categorized into 2 or 3 types. Let us create the training dataset and tabulate it first.
End of explanation
# encoding dictionary
income = {'Low' : 1.0, 'Medium' : 2.0, 'High' : 3.0}
age = {'Young' : 1.0, 'Old' : 2.0}
education = {'High School' : 1.0, 'College' : 2.0, 'University' : 3.0}
marital_status = {'Married' : 1.0, 'Single' : 2.0}
usage = {'Low' : 1.0, 'Medium' : 2.0, 'High' : 3.0}
# encode training data
for i in range(len(train_income)):
    train_income[i] = income[train_income[i]]
    train_age[i] = age[train_age[i]]
    train_education[i] = education[train_education[i]]
    train_marital[i] = marital_status[train_marital[i]]
    train_usage[i] = usage[train_usage[i]]
    
# form Shogun feature matrix
train_data = np.array([train_income, train_age, train_education, train_marital])
train_feats = sg.create_features(train_data);
# form Shogun multiclass labels
labels = sg.create_labels(np.array(train_usage));
Explanation: We want to create a decision tree from the above training dataset. The first step for that is to encode the data into numeric values and bind them to Shogun's features and multiclass labels.
End of explanation
# create ID3ClassifierTree object
id3 = sg.create_machine("ID3ClassifierTree", labels=labels)
# learn the tree from training features
is_successful = id3.train(train_feats)
Explanation: Next, we learn our decision tree using the features and labels created.
End of explanation
# test data
test_income = ['Medium','Medium','Low','High','High']
test_age = ['Old','Young','Old','Young','Old']
test_education = ['University','College','High School','University','College']
test_marital = ['Married','Single','Married','Single','Married']
test_usage = ['Low','Medium','Low','High','High']
# tabulate test data
print('Test Data Table : \n')
print('Income \t\t Age \t\t Education \t\t Marital Status \t Usage')
for i in range(len(test_income)):
    print(test_income[i]+' \t\t '+test_age[i]+' \t\t '+test_education[i]+' \t\t '+test_marital[i]+' \t\t ?')
Explanation: Our decision tree is ready now and we want to use it to make some predictions over test data. So, let us create some test data examples first.
End of explanation
# encode test data
for i in range(len(test_income)):
    test_income[i] = income[test_income[i]]
    test_age[i] = age[test_age[i]]
    test_education[i] = education[test_education[i]]
    test_marital[i] = marital_status[test_marital[i]]
# bind to shogun features    
test_data = np.array([test_income, test_age, test_education, test_marital])
test_feats = sg.create_features(test_data)
# apply decision tree classification
test_labels = id3.apply(test_feats)
Explanation: Next, as with training data, we encode our test dataset and bind it to Shogun features. Then, we apply our decision tree to the test examples to obtain the predicted labels.
End of explanation
output = test_labels.get("labels");
output_labels=[0]*len(output)
# decode back test data for printing
for i in range(len(test_income)):
    test_income[i]=list(income.keys())[list(income.values()).index(test_income[i])]
    test_age[i]=list(age.keys())[list(age.values()).index(test_age[i])]
    test_education[i]=list(education.keys())[list(education.values()).index(test_education[i])]
    test_marital[i]=list(marital_status.keys())[list(marital_status.values()).index(test_marital[i])]
    output_labels[i]=list(usage.keys())[list(usage.values()).index(output[i])]
# print output data
print('Final Test Data Table : \n')
print('Income \t Age \t Education \t Marital Status \t Usage(predicted)')
for i in range(len(test_income)):
	print(test_income[i]+' \t '+test_age[i]+' \t '+test_education[i]+' \t '+test_marital[i]+' \t\t '+output_labels[i])
Explanation: Finally let us tabulate the results obtained and compare them with our intuitive predictions.
End of explanation
# class attribute
evaluation = {'unacc' : 1.0, 'acc' : 2.0, 'good' : 3.0, 'vgood' : 4.0}
# non-class attributes
buying = {'vhigh' : 1.0, 'high' : 2.0, 'med' : 3.0, 'low' : 4.0}
maint = {'vhigh' : 1.0, 'high' : 2.0, 'med' : 3.0, 'low' : 4.0}
doors = {'2' : 1.0, '3' : 2.0, '4' : 3.0, '5more' : 4.0}
persons = {'2' : 1.0, '4' : 2.0, 'more' : 3.0}
lug_boot = {'small' : 1.0, 'med' : 2.0, 'big' : 3.0}
safety = {'low' : 1.0, 'med' : 2.0, 'high' : 3.0}
Explanation: So, do the predictions made by our decision tree match our inferences from training set? Yes! For example, from the training set we infer that the individual having low income has low usage and also all individuals going to college have medium usage. The decision tree predicts the same for both cases. 
Example using a real dataset
We choose the car evaluation dataset from the UCI Machine Learning Repository as our real-world dataset. The car.names file of the dataset enumerates the class categories as well as the non-class attributes. Each car categorized into one of 4 classes : unacc, acc, good, vgood. Each car is judged using 6 attributes : buying, maint, doors, persons, lug_boot, safety. Each of these attributes can take 3-4 values. Let us first make a dictionary to encode strings to numeric values using information from cars.names file.
End of explanation
with open( os.path.join(SHOGUN_DATA_DIR, 'uci/car/car.data'), 'r') as f:
    feats = []
    labels = []
    # read data from file and encode
    for line in f:
        words = line.rstrip().split(',')
        words[0] = buying[words[0]]
        words[1] = maint[words[1]]
        words[2] = doors[words[2]]
        words[3] = persons[words[3]]
        words[4] = lug_boot[words[4]]
        words[5] = safety[words[5]]
        words[6] = evaluation[words[6]]
        feats.append(words[0:6])
        labels.append(words[6])
Explanation: Next, let us read the file and form Shogun features and labels.
End of explanation
feats = np.array(feats)
labels = np.array(labels)
# number of test vectors
num_test_vectors = 200;
test_indices = np.random.randint(feats.shape[0], size = num_test_vectors)
test_features = feats[test_indices]
test_labels = labels[test_indices]
# remove test vectors from training set
feats = np.delete(feats,test_indices,0)
labels = np.delete(labels,test_indices,0)
Explanation: From the entire dataset, let us choose some test vectors to form our test dataset.
End of explanation
# shogun test features and labels
test_feats = sg.create_features(test_features.T)
test_labels = sg.create_labels(test_labels)
# method for id3 training and
def ID3_routine(feats, labels):
    # Shogun train features and labels
    train_feats = sg.create_features(feats.T)
    train_lab = sg.create_labels(labels)
    # create ID3ClassifierTree object
    id3 = sg.create_machine("ID3ClassifierTree", labels=train_lab)
    # learn the tree from training features
    id3.train(train_feats)
    # apply to test dataset
    output = id3.apply(test_feats)
    
    return output
output = ID3_routine(feats, labels)
Explanation: Next step is to train our decision tree using the training features and applying it to our test dataset to get predicted output classes.
End of explanation
# Shogun object for calculating multiclass accuracy
accuracy = sg.create_evaluation("MulticlassAccuracy")
print('Accuracy : ' + str(accuracy.evaluate(output, test_labels)))
Explanation: Finally, let us compare our predicted labels with test labels to find out the percentage error of our classification model.
End of explanation
# list of error rates for all training dataset sizes
error_rate = []
# number of error rate readings taken for each value of dataset size
num_repetitions = 3
# loop over training dataset size
for i in range(500,1600,200):
    indices = np.random.randint(feats.shape[0], size = i)
    train_features = feats[indices]
    train_labels = labels[indices]
    
    average_error = 0
    for i in range(num_repetitions):
        output = ID3_routine(train_features, train_labels)
        average_error = average_error + (1-accuracy.evaluate(output, test_labels))
        
    error_rate.append(average_error/num_repetitions)
# plot the error rates    
from scipy.interpolate import interp1d
fig,axis = plt.subplots(1,1)
x = np.arange(500,1600,200)
f = interp1d(x, error_rate)
xnew = np.linspace(500,1500,100)
plt.plot(x,error_rate,'o',xnew,f(xnew),'-')
plt.xlim([400,1600])
plt.xlabel('training dataset size')
plt.ylabel('Classification Error')
plt.title('Decision Tree Performance')
plt.show()
Explanation: We see that the accuracy is moderately high. Thus our decision tree can evaluate any car given its features with a high success rate. As a final exercise, let us examine the effect of training dataset size on the accuracy of decision tree.
End of explanation
def create_toy_classification_dataset(ncat,do_plot):
    # create attribute values and labels for class 1
    x = np.ones((1,ncat))
    y = 1+np.random.rand(1,ncat)*4
    lab = np.zeros(ncat)
    # add attribute values and labels for class 2
    x = np.concatenate((x,np.ones((1,ncat))),1)
    y = np.concatenate((y,5+np.random.rand(1,ncat)*4),1)
    lab = np.concatenate((lab,np.ones(ncat)))
    # add attribute values and labels for class 3
    x = np.concatenate((x,2*np.ones((1,ncat))),1)
    y = np.concatenate((y,1+np.random.rand(1,ncat)*8),1)
    lab = np.concatenate((lab,2*np.ones(ncat)))
    # create test data
    ntest = 20
    x_t = np.concatenate((np.ones((1,int(3*ntest/4))),2*np.ones((1,int(ntest/4)))),1)
    y_t = 1+np.random.rand(1,ntest)*8
    if do_plot:
        # plot training data
        c = ['r','g','b']
        for i in range(3):
            plt.scatter(x[0,lab==i],y[0,lab==i],color=c[i],marker='x',s=50)
        # plot test data
        plt.scatter(x_t[0,:],y_t[0,:],color='k',s=10,alpha=0.8)
        plt.xlabel('attribute X')
        plt.ylabel('attribute Y')
        plt.show()
    # form training feature matrix
    train_feats = sg.create_features(np.concatenate((x,y),0))
    # from training labels
    train_labels = sg.create_labels(lab)
    # from test feature matrix
    test_feats = sg.create_features(np.concatenate((x_t,y_t),0))
    
    return (train_feats,train_labels,test_feats);
train_feats,train_labels,test_feats = create_toy_classification_dataset(20,True)
Explanation: NOTE : The above code snippet takes about half a minute to execute. Please wait patiently.
From the above plot, we see that error rate decreases steadily as we increase the training dataset size. Although in this case, the decrease in error rate is not very significant, in many datasets this decrease in error rate can be substantial.
C4.5
The C4.5 algorithm is essentially an extension of the ID3 algorithm for decision tree learning. It has the additional capability of handling continuous attributes and attributes with missing values. The tree growing process in case of C4.5 is same as that of ID3 i.e. finding the best split at each node using the information gain metric. But in case of continuous attribute, the C4.5 algorithm has to perform the additional step of converting it to a two-value categorical attribute by splitting about a suitable threshold. This threshold is chosen in a way such that the resultant split produces maximum information gain. Let us start exploring Shogun's C4.5 algorithm API with a toy example. 
Example using toy dataset
Let us consider a 3-class classification using 2 attributes. One of the attributes (say attribute X) is a 2-class categorical attribute depicted by values 1 and 2. The other attribute (say attribute Y) is a continuous attribute having values between 1 and 9. The simple rules of classification are as follows : if X=1 and Y $\epsilon$ [1,5), data point belongs to class 1, if X=1 and Y $\epsilon$ [5,9), data point belongs to class 2 and if X=2, data point belongs to class 3. Let us realize the toy dataset by plotting it.
End of explanation
# steps in C4.5 Tree training bundled together in a python method
def train_tree(feats,types,labels):
    # C4.5 Tree object
    tree = sg.create_machine("C45ClassifierTree", labels=labels, m_nominal=types)
    # supply training matrix and train
    tree.train(feats)
    
    return tree
# specify attribute types X is categorical hence True, Y is continuous hence False
feat_types = np.array([True,False])
# get back trained tree
C45Tree = train_tree(train_feats,feat_types,train_labels)
Explanation: In the above plot the training data points are are marked with different colours of crosses where each colour corresponds to a particular label. The test data points are marked by black circles. For us it is a trivial task to assign correct colours (i.e. labels) to the black points. Let us see how accurately C4.5 assigns colours to these test points.
Now let us train a decision tree using the C4.5 algorithm. We need to create a Shogun C4.5 tree object and supply training features and training labels to it. We also need to specify which attribute is categorical and which is continuous. The attribute types can be specified using set_feature_types method through which all categorical attributes are set as True and continuous attributes as False.
End of explanation
def classify_data(tree,data):
    # get classification labels
    output = tree.apply(data)   
    # get classification certainty
    output_certainty=tree.get('m_certainty')
    
    return output,output_certainty
out_labels,out_certainty = classify_data(C45Tree,test_feats)
Explanation: Now that we have trained the decision tree, we can use it to classify our test vectors.
End of explanation
# plot results
def plot_toy_classification_results(train_feats,train_labels,test_feats,test_labels):
    train = train_feats.get('feature_matrix')
    lab = train_labels.get("labels")
    test = test_feats.get('feature_matrix')
    out_labels = test_labels.get("labels")
    
    c = ['r','g','b']
    for i in range(out_labels.size):
        plt.scatter(test[0,i],test[1,i],color=c[np.int32(out_labels[i])],s=50)
    # plot training dataset for visual comparison
    for i in range(3):
        plt.scatter(train[0,lab==i],train[1,lab==i],color=c[i],marker='x',s=30,alpha=0.7)
    plt.show()
    
plot_toy_classification_results(train_feats,train_labels,test_feats,out_labels)
Explanation: Let us use the output labels to colour our test data points to qualitatively judge the performance of the decision tree.
End of explanation
import csv
# dictionary to encode class names to class labels
to_label = {'Iris-setosa' : 0.0, 'Iris-versicolor' : 1.0, 'Iris-virginica' : 2.0}
# read csv file and separate out labels and features
lab = []
feat = []
with open( os.path.join(SHOGUN_DATA_DIR, 'uci/iris/iris.data')) as csvfile:
    csvread = csv.reader(csvfile,delimiter=',')
    for row in csvread:
        feat.append([float(i) for i in row[0:4]])
        lab.append(to_label[row[4]])
lab = np.array(lab)
feat = np.array(feat).T
Explanation: We see that the decision tree trained using the C4.5 algorithm works almost perfectly in this toy dataset. Now let us try this algorithm on a real world dataset. 
Example using a real dataset
In this section we will investigate that how accurately we can predict the species of an Iris flower using a C4.5 trained decision tree. In this example we will use petal length, petal width, sepal length and sepal width as our attributes to decide among 3 classes of Iris : Iris Setosa, Iris Versicolor and Iris Verginica. Let us start by suitably reading the dataset.
End of explanation
# no.of vectors in test dataset
ntest = 25
# no. of vectors in train dataset
ntrain = 150-ntest
# randomize the order of vectors
subset = np.int32(np.random.permutation(150))
# choose 1st ntrain from randomized set as training vectors
feats_train = feat[:,subset[0:ntrain]]
# form training labels correspondingly
train_labels = lab[subset[0:ntrain]]
# form test features and labels (for accuracy evaluations)
feats_test = feat[:,subset[ntrain:ntrain+ntest]]
test_labels = lab[subset[ntrain:ntrain+ntest]]
Explanation: Because there is no separate test dataset, we first divide the given dataset into training and testing subsets.
End of explanation
# plot training features
c = ['r', 'g', 'b']
for i in range(3):
    plt.scatter(feats_train[2,train_labels==i],feats_train[3,train_labels==i],color=c[i],marker='x')
# plot test data points in black
plt.scatter(feats_test[2,:],feats_test[3,:],color='k',marker='o')
plt.show()
Explanation: Before marching forward with applying C4.5, let us plot the data to get a better understanding. The given data points are 4-D and hence cannot be conveniently plotted. We need to reduce the number of dimensions to 2. This reduction can be achieved using any dimension reduction algorithm like PCA. However for the sake of brevity, let us just choose two highly correlated dimensions, petal width and petal length (see summary statistics), right away for plotting.
End of explanation
# training data
feats_train = sg.create_features(feats_train)
train_labels = sg.create_labels(train_labels)
# test data
feats_test = sg.create_features(feats_test)
test_labels = sg.create_labels(test_labels)
Explanation: First, let us create Shogun features and labels from the given data.
End of explanation
# randomize the order of vectors
subset = np.int32(np.random.permutation(ntrain))
nvalidation = 45
# form training subset and validation subset
train_subset = subset[0:ntrain-nvalidation]
validation_subset = subset[ntrain-nvalidation:ntrain]
Explanation: We know for fact that decision trees tend to overfit. Hence pruning becomes a necessary step. In case of toy dataset, we skipped the pruning step because the dataset was simple and noise-free. But in case of a real dataset like the Iris dataset pruning cannot be skipped. So we have to partition the training dataset into the training subset and the validation subset.
End of explanation
# set attribute types - all continuous
feature_types = np.array([False, False, False, False])
# remove validation subset before training the tree
feats_train.add_subset(train_subset)
train_labels.add_subset(train_subset)
# train tree
C45Tree = train_tree(feats_train,feature_types,train_labels)
# bring back validation subset
feats_train.remove_subset()
train_labels.remove_subset()
# remove data belonging to training subset
feats_train.add_subset(validation_subset)
train_labels.add_subset(validation_subset)
# FIXME: expose C45ClassifierTree::prune_tree
# prune the tree
# C45Tree.prune_tree(feats_train,train_labels)
# bring back training subset
feats_train.remove_subset()
train_labels.remove_subset()
# get results
output, output_certainty = classify_data(C45Tree,feats_test)
Explanation: Now we train the decision tree first, then prune it and finally use it to get output labels for test vectors.
End of explanation
# Shogun object for calculating multiclass accuracy
accuracy = sg.create_evaluation("MulticlassAccuracy")
print('Accuracy : ' + str(accuracy.evaluate(output, test_labels)))
# convert MulticlassLabels object to labels vector
output = output.get("labels")
test_labels = test_labels.get("labels")
train_labels = train_labels.get("labels")
# convert features object to matrix
feats_test = feats_test.get('feature_matrix')
feats_train = feats_train.get('feature_matrix')
# plot ground truth
for i in range(3):
    plt.scatter(feats_test[2,test_labels==i],feats_test[3,test_labels==i],color=c[i],marker='x',s=100)
# plot predicted labels
for i in range(output.size):
    plt.scatter(feats_test[2,i],feats_test[3,i],color=c[np.int32(output[i])],marker='o',s=30*output_certainty[i])
        
plt.show()
Explanation: Let us calculate the accuracy of the classification made by our tree as well as plot the results for qualitative evaluation.
End of explanation
train_feats,train_labels,test_feats=create_toy_classification_dataset(20,True)
Explanation: From the evaluation of results, we infer that, with the help of a C4.5 trained decision tree, we can predict (with high accuracy) the type of Iris plant given its petal and sepal widths and lengths.
Classification and Regression Trees (CART)
The CART algorithm is a popular decision tree learning algorithm introduced by Breiman et al. Unlike ID3 and C4.5, the learnt decision tree in this case can be used for both multiclass classification and regression depending on the type of dependent variable. The tree growing process comprises of recursive binary splitting of nodes. To find the best split at each node, all possible splits of all available predictive attributes are considered. The best split is the one that maximises some splitting criterion. For classification tasks, ie. when the dependent attribute is categorical, the Gini index is used as the splitting criterion. For regression tasks, ie. when the dependent variable is continuous, the least squares deviation is used. Let us learn about Shogun's CART implementation by working on two toy problems, one on classification and the other on regression.
Classification example using toy data
Let us consider the same dataset as that in the C4.5 toy example. We re-create the dataset and plot it first.
End of explanation
def train_carttree(feat_types,problem_type,num_folds,use_cv_pruning,labels,feats):
    # create CART tree object
    c = sg.create_machine("CARTree", nominal=feat_types,
                   mode=problem_type,
                   folds=num_folds,
                   apply_cv_pruning=use_cv_pruning,
                   labels=labels)
    # train using training features
    c.train(feats)
    
    return c
# form feature types True for nominal (attribute X), False for ordinal/continuous (attribute Y)
ft = np.array([True, False])
# get back trained tree
cart = train_carttree(ft, "PT_MULTICLASS", 5, True, train_labels, train_feats)
Explanation: Next, we supply necessary parameters to the CART algorithm and use it train our decision tree.
End of explanation
# get output labels
output_labels = cart.apply(test_feats)
plot_toy_classification_results(train_feats,train_labels,test_feats,output_labels)
Explanation: In the above code snippet, we see four parameters being supplied to the CART tree object. feat_types supplies knowledge of attribute types of training data to the CART algorithm and problem_type specifies whether it is a multiclass classification problem (PT_MULTICLASS) or a regression problem (PT_REGRESSION). The boolean parameter use_cv_pruning switches on cross-validation pruning  of the trained tree and num_folds specifies the number of folds of cross-validation to be applied while pruning. At this point, let us divert ourselves briefly towards undertanding what kind of pruning strategy is employed by Shogun's CART implementation. The CART algorithm uses the cost-complexity pruning strategy. Cost-Complexity pruning yields a list of subtrees of varying depths using complexity normalized resubstitution error, $R_\alpha(T)$. Resubstitution error, R(T), measures how well a decision tree fits the training data. But, this measure favours larger trees over smaller ones. Hence the complexity normalized resubstitution error metric is used which adds penalty for increased complexity and in-turn counters overfitting.
$R_\alpha(T)=R(T)+\alpha \times (numleaves)$
The best subtree among the list of subtrees can be chosen using cross validation or using the best-fit metric in the validation dataset. Setting use_cv_pruning in the above code snippet basically tells the CART object to use cross-validation to choose the best among the subtrees generated by cost-complexity pruning.
Let us now get back on track and use the trained tree to classify our test data.
End of explanation
def create_toy_regression_dataset(nsamples,noise_var):
    # randomly choose positions in X axis between 0 to 16
    samples_x = np.random.rand(1,nsamples)*16
    # find out y (=sin(x)) values for the sampled x positions and add noise to it
    samples_y = np.sin(samples_x)+(np.random.rand(1,nsamples)-0.5)*noise_var
    # plot the samples
    plt.scatter(samples_x,samples_y,color='b',marker='x')
    
    # create training features
    train_feats = sg.create_features(samples_x)
    # training labels
    train_labels = sg.create_labels(samples_y[0,:])
    return (train_feats,train_labels)
# plot the reference sinusoid
def plot_ref_sinusoid():
    plot_x = np.linspace(-2,18,100)
    plt.plot(plot_x,np.sin(plot_x),color='y',linewidth=1.5)
    plt.xlabel('Feature values')
    plt.ylabel('Labels')
    plt.xlim([-3,19])
    plt.ylim([-1.5,1.5])
# number of samples is 300, noise variance is 0.5
train_feats,train_labels = create_toy_regression_dataset(300,0.5)
plot_ref_sinusoid()
plt.show()
Explanation: Regression example using toy data
In this example, we form the training dataset by sampling points from a sinusoidal curve and see how well a decision tree, trained using these samples, re-creates the actual sinusoid.
End of explanation
# feature type - continuous
feat_type = np.array([False])
# get back trained tree
cart = train_carttree(feat_type, "PT_REGRESSION", 5, True, train_labels, train_feats)
Explanation: Next, we train our CART-tree.
End of explanation
def plot_predicted_sinusoid(cart):
    # regression range - 0 to 16
    x_test = np.array([np.linspace(0,16,100)])
    # form Shogun features
    test_feats = sg.create_features(x_test)
    # apply regression using our previously trained CART-tree
    regression_output = cart.apply(test_feats).get("labels")
    # plot the result
    plt.plot(x_test[0,:],regression_output,linewidth=2.0)
    # plot reference sinusoid
    plot_ref_sinusoid()
    plt.show()
    
plot_predicted_sinusoid(cart)
Explanation: Now let us use the trained decision tree to regress over the entire range of the previously depicted sinusoid.
End of explanation
# dictionary to encode class names to class labels
to_label = {'Iris-setosa' : 0.0, 'Iris-versicolor' : 1.0, 'Iris-virginica' : 2.0}
# read csv file and separate out labels and features
lab = []
feat = []
with open( os.path.join(SHOGUN_DATA_DIR, 'uci/iris/iris.data')) as csvfile:
    csvread = csv.reader(csvfile,delimiter=',')
    for row in csvread:
        feat.append([float(i) for i in row[0:4]])
        lab.append(to_label[row[4]])
lab = np.array(lab)
feat = np.array(feat).T
# plot the dataset using two highly correlated attributes
c = ['r', 'g', 'b']
for i in range(3):
    plt.scatter(feat[2,lab==i],feat[3,lab==i],color=c[i],marker='x')
    
plt.show()
Explanation: As we can see from the above plot, CART-induced decision tree follows the reference sinusoid quite beautifully!
Classification example using real dataset
In this section, we will apply the CART algorithm on the Iris dataset. Remember that the Iris dataset provides us with just a training dataset and no separate test dataset. In case of the C4.5 example discussed earlier, we ourselves divided the entire training dataset into training subset and test subset. In this section, we will employ a different strategy i.e. cross validation. In cross-validation, we divide the training dataset into n subsets where n is a user controlled parameter. We perform n iterations of training and testing in which, at each iteration, we choose one of the n subsets as our test dataset and the remaining n-1 subsets as our training dataset. The performance of the model is usually taken as the average of the performances in various iterations. Shogun's cross validation class makes it really easy to apply cross-validation to any model of our choice. Let us realize this by applying cross-validation to CART-tree trained over Iris dataset. We start by reading the data.
End of explanation
# set attribute types - all continuous
feature_types = np.array([False, False, False, False])
# setup CART-tree with cross validation pruning switched off
cart = sg.create_machine("CARTree", nominal=feature_types,
                  mode="PT_MULTICLASS",
                  folds=5,
                  apply_cv_pruning=False)
Explanation: Next, we setup the model which is CART-tree in this case.
End of explanation
# training features
feats_train = sg.create_features(feat)
# training labels
labels_train = sg.create_labels(lab)
# set evaluation criteria - multiclass accuracy
accuracy = sg.create_evaluation("MulticlassAccuracy")
# set splitting criteria - 10 fold cross-validation
split = sg.create_splitting_strategy("CrossValidationSplitting", labels=labels_train, num_subsets=10)
# set cross-validation parameters 
cross_val = sg.create_machine_evaluation("CrossValidation",
                                  machine=cart,
                                  features=feats_train,
                                  labels=labels_train,
                                  splitting_strategy=split,
                                  evaluation_criterion=accuracy,
                                  num_runs=10)
# get cross validation result
# CARTree is not x-validatable
result = cross_val.evaluate()
print(result)
print('Mean Accuracy : ' + str(result.get("mean")))
Explanation: Finally we can use Shogun's cross-validation class to get performance.
End of explanation
# dictionary to convert string features to integer values
to_int = {'A' : 1, 'B' : 2, 'C' : 3, 'D' : 4, 'E' : 5}
# read csv file and separate out labels and features
lab = []
feat = []
with open( os.path.join(SHOGUN_DATA_DIR, 'uci/servo/servo.data')) as csvfile:
    csvread = csv.reader(csvfile,delimiter=',')
    for row in csvread:
        feat.append([to_int[row[0]], to_int[row[1]], float(row[2]), float(row[3])])
        lab.append(float(row[4]))
lab = np.array(lab)
feat = np.array(feat).T
Explanation: We get a mean accuracy of about 0.93-0.94. This number essentially means that a CART-tree trained using this dataset is expected to classify Iris flowers, given their required attributes, with an accuracy of 93-94% in a real world scenario. The parameters required by Shogun's cross-validation class should be noted in the above code snippet. The class requires the model, training features, training labels, splitting strategy and evaluation method to be specified. 
Regression using real dataset
In this section, we evaluate CART-induced decision tree over the Servo dataset. Using this dataset, we essentially want to train a model  which can predict the rise time of a servomechanism given the required parameters which are the two (integer) gain settings and two (nominal) choices of mechanical linkages. Let us read the dataset first.
End of explanation
# form training features
feats_train = sg.create_features(feat)
# form training labels
labels_train = sg.create_labels(lab)
def get_cv_error(max_depth):
    # set attribute types - 2 nominal and 2 ordinal
    feature_types = np.array([True, True, False, False])
    # setup CART-tree with cross validation pruning switched off
    cart = sg.create_machine("CARTree", nominal=feature_types,
                      mode="PT_REGRESSION",
                      folds=5,
                      apply_cv_pruning=False,
                     max_depth=max_depth)
    # set evaluation criteria - mean squared error
    accuracy = sg.create_evaluation("MeanSquaredError")
    # set splitting criteria - 10 fold cross-validation
    split = sg.create_splitting_strategy("CrossValidationSplitting", labels=labels_train, num_subsets=10)
    # set cross-validation parameters 
    cross_val = sg.create_machine_evaluation("CrossValidation",
                                      machine=cart,
                                      features=feats_train,
                                      labels=labels_train,
                                      splitting_strategy=split,
                                      evaluation_criterion=accuracy,
                                      num_runs=10)
    # return cross validation result
    return cross_val.evaluate().get("mean")
Explanation: The servo dataset is a small training dataset (contains just 167 training vectors) with no separate test dataset, like the Iris dataset. Hence we will apply the same cross-validation strategy we applied in case of the Iris dataset. However, to make things interesting let us play around with a yet-untouched parameter of CART-induced tree i.e. the maximum allowed tree depth. As the tree depth increases, the tree becomes more complex and hence fits the training data more closely. By setting a maximum allowed tree depth, we restrict the complexity of trained tree and hence avoid over-fitting. But choosing a low value of the maximum allowed tree depth may lead to early stopping i.e. under-fitting. Let us explore how we can decide the appropriate value of the max-allowed-tree-depth parameter. Let us create a method, which takes max-allowed-tree-depth parameter as input and returns the corresponding cross-validated error as output.
End of explanation
import matplotlib.pyplot as plt
cv_errors = [get_cv_error(i) for i in range(1,15)]
plt.plot(range(1,15),cv_errors,'bo',range(1,15),cv_errors,'k')
plt.xlabel('max_allowed_depth')
plt.ylabel('cross-validated error')
plt.ylim(0,1.2)
plt.show()
Explanation: Next, let us supply a range of max_depth values to the above method and plot the returned cross-validated errors.
End of explanation
train_feats,train_labels,test_feats = create_toy_classification_dataset(20,True)
Explanation: From the above plot quite clearly gives us the most appropriate value of maximum allowed depth. We see that the first minima occurs at a maximum allowed depth of 6-8. Hence, one of these should be the desired value. It is to be noted that the error metric that we are discussing here is the mean squared error. Thus, from the above plot, we can also claim that, given required parameters, our CART-flavoured decision tree can predict the rise time within an average error range of $\pm0.5$ (i.e. square root of 0.25 which is the approximate minimum cross-validated error). The relative error i.e  average_error/range_of_labels comes out to be ~30%.
CHi-squared Automatic Interaction Detection (CHAID)
The CHAID is an algorithm for decision tree learning proposed by Kass (1980). It is similar in functionality to CART in the sense that both can be used for classification as well as regression. But unlike CART, CHAID internally handles only categorical features. The continuous features are first converted into ordinal categorical features for the CHAID algorithm to be able to use them. This conversion is done by binning of feature values.The number of bins (K) has to be supplied by the user. Given K, a predictor is split in such a way that all the bins get the same number (more or less) of distinct predictor values. The maximum feature value in each bin is used as a breakpoint.
An important parameter in the CHAID tree growing process is the p-value. The p-value is the metric that is used for deciding which categories of predictor values to merge during merging as well as for deciding the best attribute during splitting. The p-value is calculated using different hypothesis testing methods depending on the type of dependent variable (nominal, ordinal or continuous). A more detailed discussion on the CHAID algorithm can be found in the documentation of the CCHAIDTree class in Shogun. Let us move on to a more interesting topic which is learning to use CHAID using Shogun's python API.  
Classification example using toy dataset
Let us re-use the toy classification dataset used in C4.5 and CART to see the API usage of CHAID as well as to qualitatively compare the results of the CHAID algorithm with the other two.
End of explanation
def train_chaidtree(dependent_var_type,feature_types,num_bins,feats,labels):
    # create CHAID tree object
    c = sg.create_machine("CHAIDTree", dependent_vartype=dependent_var_type,
                   feature_types=feature_types,
                   num_breakpoints=num_bins,
                   labels=labels)
    # train using training features
    c.train(feats)
    
    return c
# form feature types 0 for nominal (attribute X), 2 for continuous (attribute Y)
ft = np.array([0, 2],dtype=np.int32)
# cache training matrix
train_feats_cache=sg.create_features(train_feats.get("feature_matrix"))
# get back trained tree - dependent variable type is nominal (hence 0), number of bins for binning is 10  
chaid = train_chaidtree(0,ft,10,train_feats,train_labels)
print('updated_matrix')
print(train_feats.get('feature_matrix'))
print('')
print('original_matrix')
print(train_feats_cache.get('feature_matrix'))
Explanation: Now, we set up our CHAID-tree with appropriate parameters and train over given data.
End of explanation
# get output labels
output_labels = chaid.apply(test_feats)
plot_toy_classification_results(train_feats_cache,train_labels,test_feats,output_labels)
Explanation: An important point to be noted in the above code snippet is that CHAID training modifies the training data. The actual continuous feature values are replaced by the discrete ordinal values obtained during continuous to ordinal conversion. Notice the difference between the original feature matrix and the updated matrix. The updated matrix contains only 10 distinct values denoting all values of the original matrix for feature dimension at row index 1.
With a CHAID-trained decision tree at our disposal, it's time to apply it to colour our test points.
End of explanation
train_feats,train_labels = create_toy_regression_dataset(300,0.5)
plot_ref_sinusoid()
plt.show()
Explanation: Regression example with toy dataset
In this section, we re-work the sinusoid curve fitting example (earlier used in CART toy regression).
End of explanation
# feature type - continuous
feat_type = np.array([2],dtype=np.int32)
# get back trained tree
chaid = train_chaidtree(2,feat_type, 50, train_feats, train_labels)
Explanation: As usual, we start by setting up our decision tree and training it.
End of explanation
plot_predicted_sinusoid(chaid)
Explanation: Next, we use the trained decision tree to follow the reference sinusoid.
End of explanation
train_feats = sg.create_features(sg.read_csv( os.path.join(SHOGUN_DATA_DIR, 'uci/wine/fm_wine.dat')))
train_labels = sg.create_labels(sg.read_csv( os.path.join(SHOGUN_DATA_DIR, 'uci/wine/label_wine.dat')))
Explanation: A distinguishing feature about the predicted curve is the presence of steps. These steps are essentially an artifact of continuous to ordinal conversion. If we decrease the number of bins for the conversion the step widths will increase.
Classification example over real dataset
In this section, we will try to estimate the quality of wine based on 13 attributes like alcohol content, malic acid, magnesium content, etc. using the wine dataset. Let us first read the dataset using Shogun's CSV file reader.
End of explanation
# set attribute types - all attributes are continuous(2)
feature_types = np.array([2 for i in range(13)],dtype=np.int32)    
# setup CHAID tree - dependent variable is nominal(0), feature types set, number of bins(20)
chaid = sg.create_machine("CHAIDTree", dependent_vartype=0,
                   feature_types=feature_types,
                   num_breakpoints=20)
Explanation: Like the case of CART, here we are also interested in finding out the approximate accuracy with which our CHAID tree trained on this dataset will perform in real world. Hence, we will apply the cross validation strategy. But first we specify the parameters of the CHAID tree.
End of explanation
# set evaluation criteria - multiclass accuracy
accuracy = sg.create_evaluation("MulticlassAccuracy")
    
# set splitting criteria - 10 fold cross-validation
split = sg.create_splitting_strategy("CrossValidationSplitting", labels=train_labels, num_subsets=10)
# set cross-validation parameters 
cross_val = sg.create_machine_evaluation("CrossValidation",
                                  machine=chaid,
                                  features=train_feats,
                                  labels=train_labels,
                                  splitting_strategy=split,
                                  evaluation_criterion=accuracy,
                                  num_runs=10)
# CHAIDTree is not x-validatable
print(f"Mean classification accuracy : {cross_val.evaluate().get('mean')*100} %")
Explanation: Next we set up the cross-validation class and get back the error estimate we want i.e mean classification error.
End of explanation
train_feats=sg.create_features(sg.read_csv( os.path.join(SHOGUN_DATA_DIR, 'uci/housing/fm_housing.dat')))
train_labels=sg.create_labels(sg.read_csv( os.path.join(SHOGUN_DATA_DIR, 'uci/housing/housing_label.dat')))
# print range of regression labels - this is useful for calculating relative deviation later 
print('labels range : '+str(np.ptp(train_labels.get("labels"))))
Explanation: Regression example using real dataset
In this section, we try to predict the value of houses in Boston using 13 attributes, like per capita crime rate in neighborhood, number of rooms, nitrous oxide concentration in air, proportion of non-retail business in the area etc. Out of the 13 attributes 12 are continuous and 1 (the Charles river dummy variable) is binary nominal. Let us load the dataset as our first step. For this, we can directly use Shogun's CSV file reader class.
End of explanation
def get_cv_error(max_depth):
    # set feature types - all continuous(2) except 4th column which is nominal(0) 
    feature_types = np.array([2]*13,dtype=np.int32)
    feature_types[3]=0
    feature_types[8]=1
    feature_types[9]=1    
    # setup CHAID-tree
    chaid = sg.create_machine("CHAIDTree", dependent_vartype=2,
                       feature_types=feature_types,
                       num_breakpoints=10,
                       max_tree_depth=10)
    # set evaluation criteria - mean squared error
    accuracy = sg.create_evaluation("MeanSquaredError")
    # set splitting criteria - 5 fold cross-validation
    split = sg.create_splitting_strategy("CrossValidationSplitting", 
                                  labels=train_labels, 
                                  num_subsets=5)
    # set cross-validation parameters 
    cross_val = sg.create_machine_evaluation("CrossValidation",
                                      machine=chaid,
                                      features=train_feats,
                                      labels=train_labels,
                                      splitting_strategy=split,
                                      evaluation_criterion=accuracy,
                                      num_runs=3)
    # return cross validation result
    return cross_val.evaluate().get("mean")
cv_errors = [get_cv_error(i) for i in range(1,10)]
plt.plot(range(1,10),cv_errors,'bo',range(1,10),cv_errors,'k')
plt.xlabel('max_allowed_depth')
plt.ylabel('cross-validated error')
plt.show()
Explanation: Next, we set up the parameters for the CHAID tree as well as the cross-validation class.
End of explanation
<END_TASK>