public Node addNode(string attribute, string value_splitter, Node parent, string element_identifier = null)
        {
            if (element_identifier == null)
            {
                element_identifier = ElementHelper.generateElementId('N', element_counter);
            }
            Node newnode = new Node(element_identifier, attribute, value_splitter);

            if (root == null)
            {
                root = newnode;
            }
            else
            {
                parent.addChildNode(newnode);
                newnode.addParentNode(parent);
            }
            element_counter++;
            return(newnode);
        }
        public ContinuousNode addContinuousNode(string attribute, string value_splitter, double attribute_threshold, Node parent, string element_identifier = null)
        {
            if (element_identifier == null)
            {
                element_identifier = ElementHelper.generateElementId('N', element_counter);
            }
            ContinuousNode newnode = new ContinuousNode(element_identifier, attribute, value_splitter).setThreshold(attribute_threshold);

            if (root == null)
            {
                root = newnode;
            }
            else
            {
                parent.addChildNode(newnode);
                newnode.addParentNode(parent);
            }
            element_counter++;
            return(newnode);
        }
        private ObservationSet importCSV(string filepath, bool set_classifiers)
        {
            var reader            = new StreamReader(filepath);
            int row               = 0;
            int classifier_column = -1;

            // Loop through CSV lines.
            while (!reader.EndOfStream)
            {
                row++;
                string line   = reader.ReadLine();
                var    values = line.Split(this.seperator);

                if (row > 2)
                {
                    // This is an instance. The attributes have already been established.
                    DataInstance addition = new DataInstance(ElementHelper.generateElementId('D', instances.Count));
                    int          column   = 0;

                    // Find the properties of this instance.
                    foreach (string value in values)
                    {
                        // If we do not want to set the classifiers of the instances, we need to check we have not arrived at the
                        // Final column.
                        if (set_classifiers || column != classifier_column)
                        {
                            string key = "ERR";
                            if (column == classifier_column)
                            {
                                key = this.targetAttribute();
                            }
                            else
                            {
                                key = column_positions[column];
                            }
                            if (value == "")
                            {
                                addition.setProperty(key, null);
                            }
                            else
                            {
                                string value_to_set = value;
                                if (key != this.target && this.attributes[key] == "continuous")
                                {
                                    value_to_set = value.Replace(',', this.dec);
                                    value_to_set = value.Replace('.', this.dec);
                                }
                                addition.setProperty(key, value_to_set);
                            }
                        }
                        column++;
                    }
                    this.instances.Add(addition);
                }
                else
                {
                    if (row == 1)
                    {
                        int column = 0;
                        // This line describes the attribute names.
                        foreach (string value in values)
                        {
                            // Add it to the columns list.
                            this.column_positions.Add(value);
                            this.attributes.Add(value, "UNKNOWN");
                            column++;
                        }
                    }
                    else if (row == 2)
                    {
                        int column = 0;
                        // This line describes the attribute types
                        foreach (string value in values)
                        {
                            if (value == "classifier")
                            {
                                // Classifier column.
                                // First we remove it from the attributes dictionary, since we do not want the classifier to show up in the attributes.
                                this.attributes.Remove(this.column_positions[column]);

                                // Then, we make sure that we know the correct classifier.
                                this.target       = this.column_positions[column];
                                classifier_column = column;
                            }
                            else
                            {
                                if (value != "nominal" && value != "continuous")
                                {
                                    throw new Exception($"Unknown attribute type {value}.");
                                }
                                this.attributes[this.column_positions[column]] = value;
                            }

                            column++;
                        }
                    }
                }
            }

            // All data has been considered, let's return a ObservationSet.
            return(new ObservationSet(this.exampleSet(), this.targetAttribute(), this.exampleAttributeTypes()));
        }