/// <summary> /// Найти решение /// </summary> /// <param name="item"></param> /// <returns></returns> public int Decide(Item item) { DecisionNode current_node = Root; while (current_node.Decision == null) { for (int i = 0; i < item.Values.Count(); ++i) { if (current_node.Attribute == item.Values[i].Attribute) { current_node = current_node.Compute(item.Values[i].Value); break; } } } return((int)current_node.Decision); }
static DecisionNode ID3(Item[] instances, AttributeVariable target_attribute, AttributeVariable[] attributes) { int yes_cnt = 0, no_cnt = 0; for (int i = 0; i < instances.Count(); ++i) { double?value = instances[i].FindAttributeValue(target_attribute); if (value == null) { throw new Exception("Не инициализировано значение атрибута " + target_attribute + " в " + i + " примере"); } if (value == 0) { ++no_cnt; } else if (value == 1) { ++yes_cnt; } else { throw new Exception("Значение атрибута " + target_attribute + " должно быть 0 или 1"); } } // если все значения target_attribute - ноль, дерево будет состоять из единственного узла, приволящим к решению 0 if (no_cnt == instances.Count()) { return(new DecisionNode(0)); } // аналогично, если все значения - 1 if (yes_cnt == instances.Count()) { return(new DecisionNode(1)); } // Если список атрибутов пуст - выводится узел, состоящий из наиболее встречающегося значения if (attributes.Count() == 0) { if (yes_cnt > no_cnt) { return(new DecisionNode(1)); } else { return(new DecisionNode(0)); } } // Ищем атрибут, который лучше всего классифицирует примеры double max_gain = 0, current_gain; AttributeVariable best_attribute = attributes[0]; for (int i = 0; i < attributes.Count(); ++i) { current_gain = Gain(instances, target_attribute, attributes[i]); if (current_gain > max_gain) { best_attribute = attributes[i]; max_gain = current_gain; } } List <double?> node_values = new List <double?>(); foreach (double n in best_attribute.Range) { node_values.Add(n); } List <DecisionNode> Branches = new List <DecisionNode>(); int k = 0; // для каждого значения атрибута добавляем ветку foreach (double n in best_attribute.Range) { List <Item> Examples = new List <Item>(); // выделяем примеры, которые соответсвуют текущему значению атрибуты for (int i = 0; i < instances.Count(); ++i) { if (instances[i].FindAttributeValue(best_attribute) == n) { Examples.Add(instances[i]); } } // если не найдено примеров, добавляем лист с наиболее встречающимся значением if (Examples.Count() == 0) { if (yes_cnt > no_cnt) { Branches.Add(new DecisionNode(ComparisonKind.Equal, (double)node_values[k], 1)); } else { Branches.Add(new DecisionNode(ComparisonKind.Equal, (double)node_values[k], 0)); } } else { List <AttributeVariable> new_attributes_list = attributes.ToList(); new_attributes_list.Remove(best_attribute); Branches.Add(ID3(Examples.ToArray(), target_attribute, new_attributes_list.ToArray())); Branches.Last().Value = node_values[k]; Branches.Last().Comparison = ComparisonKind.Equal; } ++k; } DecisionNode root = new DecisionNode(best_attribute); root.Branches = Branches.ToArray(); return(root); }
static DecisionNode C45(Item[] instances, AttributeVariable target_attribute, AttributeVariable[] attributes) { int yes_cnt = 0, no_cnt = 0; for (int i = 0; i < instances.Count(); ++i) { double?value = instances[i].FindAttributeValue(target_attribute); if (value == null) { throw new Exception("Не инициализировано значение атрибута " + target_attribute + " в " + i + " примере"); } if (value == 0) { ++no_cnt; } else if (value == 1) { ++yes_cnt; } else { throw new Exception("Значение атрибута " + target_attribute + " должно быть 0 или 1"); } } // если все значения target_attribute - ноль, дерево будет состоять из единственного узла, приволящим к решению 0 if (no_cnt == instances.Count()) { return(new DecisionNode(0)); } // аналогично, если все значения - 1 if (yes_cnt == instances.Count()) { return(new DecisionNode(1)); } // Если список атрибутов пуст - выводится узел, состоящий из наиболее встречающегося значения if (attributes.Count() == 0) { if (yes_cnt > no_cnt) { return(new DecisionNode(1)); } else { return(new DecisionNode(0)); } } // Ищем атрибут, который лучше всего классифицирует примеры double max_gain = 0, current_gain; AttributeVariable best_attribute = attributes[0]; double node_value = best_attribute.Range[0]; int m = Convert.ToInt32(Math.Sqrt(attributes.Length)); List <int> randomNumbers = Enumerable.Range(0, attributes.Length).OrderBy(x => rnd.Next()).Take(m).ToList(); //for (int i = 0; i < attributes.Count(); ++i) foreach (int index in randomNumbers) { double _node_value; current_gain = Gain(instances, target_attribute, attributes[index], out _node_value); if (current_gain > max_gain) { best_attribute = attributes[index]; max_gain = current_gain; node_value = _node_value; } } List <DecisionNode> Branches = new List <DecisionNode>(); if (best_attribute.Nature == DecisionVariableKind.Discrete) { List <double?> node_values = new List <double?>(); foreach (double n in best_attribute.Range) { node_values.Add(n); } int k = 0; // для каждого значения атрибута добавляем ветку foreach (double n in best_attribute.Range) { List <Item> Examples = new List <Item>(); // выделяем примеры, которые соответсвуют текущему значению атрибуты for (int i = 0; i < instances.Count(); ++i) { if (instances[i].FindAttributeValue(best_attribute) == n) { Examples.Add(instances[i]); } } // если не найдено примеров, добавляем лист с наиболее встречающимся значением if (Examples.Count() == 0) { if (yes_cnt > no_cnt) { Branches.Add(new DecisionNode(ComparisonKind.Equal, (double)node_values[k], 1)); } else { Branches.Add(new DecisionNode(ComparisonKind.Equal, (double)node_values[k], 0)); } } else { List <AttributeVariable> new_attributes_list = attributes.ToList(); new_attributes_list.Remove(best_attribute); Branches.Add(C45(Examples.ToArray(), target_attribute, new_attributes_list.ToArray())); Branches.Last().Value = node_values[k]; Branches.Last().Comparison = ComparisonKind.Equal; } ++k; } } else // атрибут непрерывный { List <Item> Examples = new List <Item>(); // выделяем примеры, которые меньше либо равны текущего значения атрибута for (int i = 0; i < instances.Count(); ++i) { if (ComparisonExtensions.Compare(ComparisonKind.LessThanOrEqual, (double)instances[i].FindAttributeValue(best_attribute), node_value)) { Examples.Add(instances[i]); } } // если не найдено примеров, добавляем лист с наиболее встречающимся значением if (Examples.Count() == 0) { if (yes_cnt > no_cnt) { Branches.Add(new DecisionNode(ComparisonKind.LessThanOrEqual, (double)node_value, 1)); } else { Branches.Add(new DecisionNode(ComparisonKind.LessThanOrEqual, (double)node_value, 0)); } } else { List <AttributeVariable> new_attributes_list = attributes.ToList(); new_attributes_list.Remove(best_attribute); Branches.Add(C45(Examples.ToArray(), target_attribute, new_attributes_list.ToArray())); Branches.Last().Value = node_value; Branches.Last().Comparison = ComparisonKind.LessThanOrEqual; } Examples.Clear(); // аналогично для значений, которые больше заданного for (int i = 0; i < instances.Count(); ++i) { if (ComparisonExtensions.Compare(ComparisonKind.GreaterThan, (double)instances[i].FindAttributeValue(best_attribute), node_value)) { Examples.Add(instances[i]); } } if (Examples.Count() == 0) { if (yes_cnt > no_cnt) { Branches.Add(new DecisionNode(ComparisonKind.GreaterThan, (double)node_value, 1)); } else { Branches.Add(new DecisionNode(ComparisonKind.GreaterThan, (double)node_value, 0)); } } else { List <AttributeVariable> new_attributes_list = attributes.ToList(); new_attributes_list.Remove(best_attribute); Branches.Add(C45(Examples.ToArray(), target_attribute, new_attributes_list.ToArray())); Branches.Last().Value = node_value; Branches.Last().Comparison = ComparisonKind.GreaterThan; } } DecisionNode root = new DecisionNode(best_attribute); root.Branches = Branches.ToArray(); return(root); }
public DecisionTree(DecisionNode root) { this.Root = root; }