using System;
using System.Collections.Generic;
using
System.Linq;
namespace ID3
{
public static class
Program
{
static void Main(string[]
args)
{
var R = new Dictionary<string, List<string>>();
R.Add(“Age”, new List<string>() { “old”,
“mid”, “new” });
R.Add(“Competition”,
new List<string>() { “yes”, “no” });
R.Add(“Type”, new List<string>() { “hwr”, “swr”
});
var C
= “Profit”;
var
TrainingSet = GetTrainingData();
var algorithm = new
Id3Algorithm();
Tree
desicionTree = algorithm.ID3(R, C, “root”, TrainingSet);
}
private static
List<TrainingRecord>
GetTrainingData()
{
var
trainingRecords = new List<TrainingRecord>();
Dictionary<string, string> attributes;
attributes = new Dictionary<string, string>();
attributes.Add(“Age”, “old”);
attributes.Add(“Competition”, “yes”);
attributes.Add(“Type”, “swr”);
trainingRecords.Add(new
TrainingRecord(attributes, false));
attributes = new Dictionary<string,
string>();
attributes.Add(“Age”,
“old”);
attributes.Add(“Competition”, “no”);
attributes.Add(“Type”, “swr”);
trainingRecords.Add(new
TrainingRecord(attributes, false));
attributes = new Dictionary<string,
string>();
attributes.Add(“Age”,
“old”);
attributes.Add(“Competition”, “no”);
attributes.Add(“Type”, “hwr”);
trainingRecords.Add(new
TrainingRecord(attributes, false));
attributes = new Dictionary<string,
string>();
attributes.Add(“Age”,
“mid”);
attributes.Add(“Competition”, “yes”);
attributes.Add(“Type”, “swr”);
trainingRecords.Add(new
TrainingRecord(attributes, false));
attributes = new Dictionary<string,
string>();
attributes.Add(“Age”,
“mid”);
attributes.Add(“Competition”, “yes”);
attributes.Add(“Type”, “hwr”);
trainingRecords.Add(new
TrainingRecord(attributes, false));
attributes = new Dictionary<string,
string>();
attributes.Add(“Age”,
“mid”);
attributes.Add(“Competition”, “no”);
attributes.Add(“Type”, “hwr”);
trainingRecords.Add(new
TrainingRecord(attributes, true));
attributes = new Dictionary<string,
string>();
attributes.Add(“Age”,
“mid”);
attributes.Add(“Competition”, “no”);
attributes.Add(“Type”, “swr”);
trainingRecords.Add(new
TrainingRecord(attributes, true));
attributes = new Dictionary<string,
string>();
attributes.Add(“Age”,
“new”);
attributes.Add(“Competition”, “yes”);
attributes.Add(“Type”, “swr”);
trainingRecords.Add(new
TrainingRecord(attributes, true));
attributes = new Dictionary<string,
string>();
attributes.Add(“Age”,
“new”);
attributes.Add(“Competition”, “no”);
attributes.Add(“Type”, “hwr”);
trainingRecords.Add(new
TrainingRecord(attributes, true));
attributes = new Dictionary<string,
string>();
attributes.Add(“Age”,
“new”);
attributes.Add(“Competition”, “no”);
attributes.Add(“Type”, “swr”);
trainingRecords.Add(new
TrainingRecord(attributes, true));
return
trainingRecords;
}
}
internal class Tree
{
public string Name { get;
private set;
}
public
string ArcName { get; private set; }
public bool
IsLeaf{ get; private set; }
public Dictionary<string,
Tree> Trees { get; private set;
}
public Tree(string
name, string arcName, Dictionary<string, Tree> trees)
{
Name = name;
ArcName = arcName;
Trees = trees;
if (Trees == null) IsLeaf = true;
else
if (Trees.Count <= 0) IsLeaf = true;
}
}
internal class TrainingRecord
{
public Dictionary<string, string>
Attributes { get; private set; }
public bool Success { get;
private set;
}
public TrainingRecord(Dictionary<string,
string> attributes, bool success)
{
Attributes = attributes;
Success = success;
}
}
/* function ID3 (R: множина
некатегоризаційних властивостей,
C: категоризаційна властивість,
S: множина для
навчання) returns дерево прийняття рішень;
begin
Якщо S пуста,
повернути один вузол із значенням невдача;
Якщо S складаєтсья із рядків, для
яких значення категоризаційної
властивості одне й те ж,
повернути
єдиний вузол із тим значенням;
Якщо R пуста, тоді повернути єдиний вузол із
значенням, яке є
найбільш частішим серед значень катеригоційної
властивості,
що було знайдено серед рядків S;
Нехай D є
властивістю із найбільшим приростом Gain(D,S)
серед
властивостей в множині R;
Нехай {dj| j=1,2, .., m} – значення
властивості D;
Нехай {Sj| j=1,2, .., m} – підмножини S, що включають
відповідні
рядки із значенням dj для властивості D;
Повернути дерево із коренем
поміченим D і дуги позначені
d1, d2, .., dm що продовжуються наступними
деревами
ID3(R-{D}, C, S1),
ID3(R-{D}, C, S2), .., ID3(R-{D}, C, Sm);
end ID3;
*/
internal class
Id3Algorithm
{
public Tree ID3(Dictionary<string,
List<string>> R, string
C, string arcName, List<TrainingRecord> S)
{
//1
if(S.Count <= 0) return new
Tree(false.ToString(), arcName, null);
//2
var prevValue = S[0].Success;
foreach
(var trainingRecord in S)
{
if(prevValue
!= trainingRecord.Success)
{
prevValue =
trainingRecord.Success;
break;
}
}
if(prevValue ==
S[0].Success)
{
return
new Tree(prevValue.ToString(),
arcName, null);
}
//3
if(R.Count <= 0)
{
var sCount = S.Where(x =>
x.Success).Count();
var fCount = S.Where(x =>
!x.Success).Count();
var resValue = (sCount < fCount) ? true : false;
new Tree(resValue.ToString(), arcName, null);
}
//4
double
maxGain = double.MinValue;
string
maxAtrb = string.Empty;
foreach
(var attribute in R)
{
double
currGain = Gain(attribute.Key, attribute.Value, S);
if(currGain
> maxGain)
{
maxGain = currGain;
maxAtrb = attribute.Key;
}
}
var partitioning = new Dictionary<string, List<TrainingRecord>>();
foreach (var posValue in R[maxAtrb])
{
var Si = S.Where(x =>
x.Attributes[maxAtrb] == posValue).ToList();
partitioning.Add(posValue, Si);
}
R.Remove(maxAtrb);
var childTrees = new Dictionary<string, Tree>();
foreach (var Si in
partitioning)
{
childTrees.Add(Si.Key, ID3(R, C,
Si.Key, Si.Value));
}
return new
Tree(maxAtrb, arcName, childTrees);
}
private double
Gain(string s, List<string>
posValues, List<TrainingRecord>
trainingRecords)
{
return
Info(trainingRecords) – Info(s, posValues, trainingRecords);
}
private double Info(string
attribute, List<string> posValues, List<TrainingRecord> list)
{
double nGeneral = list.Count;
double
sum = 0;
foreach (var value in posValues)
{
var sCount = list.Where(x =>
(x.Attributes[attribute] == value) && x.Success).Count();
var
fCount = list.Where(x => (x.Attributes[attribute] == value)
&& (!x.Success)).Count();
var n = (double)(sCount + fCount);
var iValue = I(new List<double>() { sCount / n, fCount / n });
sum += (n / nGeneral) * iValue;
}
return sum;
}
private double Info(List<TrainingRecord>
trainingRecords)
{
int n
= trainingRecords.Count;
var sCount = trainingRecords.Where(x =>
x.Success == true).Count();
var
fCount = trainingRecords.Where(x => x.Success == false).Count();
var p1 = sCount / (double)n;
var p2 = fCount / (double)n;
double
info = I(new List<double>()
{ p1, p2 });
return info;
}
private double
I(List<double> P)
{
double
sum = 0;
foreach (var p in P)
{
if
(p != 0)
{
sum += p * Math.Log(p, 2);
}
}
return
-sum;
}
}
}
I’m going to implement all this stuff online tomorrow for students who will listen to me.
code
more code
~~~~