source: proiecte/Parallel-DT/R8/Src/build.c @ 26

Last change on this file since 26 was 26, checked in by (none), 14 years ago

blabla

File size: 11.7 KB
Line 
1/*************************************************************************/
2/*                                                                       */
3/*    Central tree-forming algorithm incorporating all criteria          */
4/*    ---------------------------------------------------------          */
5/*                                                                       */
6/*************************************************************************/
7
8
9#include "defns.i"
10#include "types.i"
11#include "extern.i"
12
13
14ItemCount
15        *Weight,        /* Weight[i]  = current fraction of item i */
16        **Freq,         /* Freq[x][c] = no. items of class c with outcome x */
17        *ValFreq,       /* ValFreq[x]   = no. items with outcome x */
18        *ClassFreq;     /* ClassFreq[c] = no. items of class c */
19
20float
21        *Gain,          /* Gain[a] = info gain by split on att a */
22        *Info,          /* Info[a] = potential info of split on att a */
23        *Bar,           /* Bar[a]  = best threshold for contin att a */
24        *UnknownRate;   /* UnknownRate[a] = current unknown rate for att a */
25
26Boolean
27        *Tested,        /* Tested[a] set if att a has already been tested */
28        MultiVal;       /* true when all atts have many values */
29
30
31        /*  External variables initialised here  */
32
33extern float
34        *SplitGain,     /* SplitGain[i] = gain with att value of item i as threshold */
35        *SplitInfo;     /* SplitInfo[i] = potential info ditto */
36
37extern ItemCount
38        *Slice1,        /* Slice1[c]    = saved values of Freq[x][c] in subset.c */
39        *Slice2;        /* Slice2[c]    = saved values of Freq[y][c] */
40
41extern Set
42        **Subset;       /* Subset[a][s] = subset s for att a */
43
44extern short
45        *Subsets;       /* Subsets[a] = no. subsets for att a */
46
47
48
49/*************************************************************************/
50/*                                                                       */
51/*              Allocate space for tree tables                           */
52/*                                                                       */
53/*************************************************************************/
54
55
56    InitialiseTreeData()
57/*  ------------------  */
58{ 
59    DiscrValue v;
60    Attribute a;
61
62    Tested      = (char *) calloc(MaxAtt+1, sizeof(char));
63
64    Gain        = (float *) calloc(MaxAtt+1, sizeof(float));
65    Info        = (float *) calloc(MaxAtt+1, sizeof(float));
66    Bar         = (float *) calloc(MaxAtt+1, sizeof(float));
67
68    Subset = (Set **) calloc(MaxAtt+1, sizeof(Set *));
69    ForEach(a, 0, MaxAtt)
70    {
71        if ( MaxAttVal[a] )
72        {
73            Subset[a]  = (Set *) calloc(MaxDiscrVal+1, sizeof(Set));
74            ForEach(v, 0, MaxAttVal[a])
75            {
76                Subset[a][v] = (Set) malloc((MaxAttVal[a]>>3) + 1);
77            }
78        }
79    }
80    Subsets = (short *) calloc(MaxAtt+1, sizeof(short));
81
82    SplitGain = (float *) calloc(MaxItem+1, sizeof(float));
83    SplitInfo = (float *) calloc(MaxItem+1, sizeof(float));
84
85    Weight = (ItemCount *) calloc(MaxItem+1, sizeof(ItemCount));
86
87    Freq  = (ItemCount **) calloc(MaxDiscrVal+1, sizeof(ItemCount *));
88    ForEach(v, 0, MaxDiscrVal)
89    {
90        Freq[v]  = (ItemCount *) calloc(MaxClass+1, sizeof(ItemCount));
91    }
92
93    ValFreq = (ItemCount *) calloc(MaxDiscrVal+1, sizeof(ItemCount));
94    ClassFreq = (ItemCount *) calloc(MaxClass+1, sizeof(ItemCount));
95
96    Slice1 = (ItemCount *) calloc(MaxClass+2, sizeof(ItemCount));
97    Slice2 = (ItemCount *) calloc(MaxClass+2, sizeof(ItemCount));
98
99    UnknownRate = (float *) calloc(MaxAtt+1, sizeof(float));
100
101    /*  Check whether all attributes have many discrete values  */
102
103    MultiVal = true;
104    if ( ! SUBSET )
105    {
106        for ( a = 0 ; MultiVal && a <= MaxAtt ; a++ )
107        {
108            if ( SpecialStatus[a] != IGNORE )
109            {
110                MultiVal = MaxAttVal[a] >= 0.3 * (MaxItem + 1);
111            }
112        }
113    }
114}
115
116
117
118/*************************************************************************/
119/*                                                                       */
120/*              Initialise the weight of each item                       */
121/*                                                                       */
122/*************************************************************************/
123
124
125    InitialiseWeights()
126/*  -----------------  */
127{
128    ItemNo i;
129
130    ForEach(i, 0, MaxItem)
131    {
132        Weight[i] = 1.0;
133    }
134}
135
136
137
138/*************************************************************************/
139/*                                                                       */
140/*  Build a decision tree for the cases Fp through Lp:                   */
141/*                                                                       */
142/*  - if all cases are of the same class, the tree is a leaf and so      */
143/*      the leaf is returned labelled with this class                    */
144/*                                                                       */
145/*  - for each attribute, calculate the potential information provided   */
146/*      by a test on the attribute (based on the probabilities of each   */
147/*      case having a particular value for the attribute), and the gain  */
148/*      in information that would result from a test on the attribute    */
149/*      (based on the probabilities of each case with a particular       */
150/*      value for the attribute being of a particular class)             */
151/*                                                                       */
152/*  - on the basis of these figures, and depending on the current        */
153/*      selection criterion, find the best attribute to branch on.       */
154/*      Note:  this version will not allow a split on an attribute       */
155/*      unless two or more subsets have at least MINOBJS items.          */
156/*                                                                       */
157/*  - try branching and test whether better than forming a leaf          */
158/*                                                                       */
159/*************************************************************************/
160
161
162Tree FormTree(Fp, Lp)
163/*   ---------  */
164    ItemNo Fp, Lp; 
165{ 
166    ItemNo i, Kp, Ep, Group();
167    ItemCount Cases, NoBestClass, KnownCases, CountItems();
168    float Factor, BestVal, Val, AvGain=0, Worth();
169    Attribute Att, BestAtt, Possible=0;
170    ClassNo c, BestClass;
171    Tree Node, Leaf();
172    DiscrValue v;
173    Boolean PrevAllKnown;
174
175    Cases = CountItems(Fp, Lp);
176
177    /*  Generate the class frequency distribution  */
178
179    ForEach(c, 0, MaxClass)
180    {
181        ClassFreq[c] = 0;
182    }
183    ForEach(i, Fp, Lp)
184    { 
185        ClassFreq[ Class(Item[i]) ] += Weight[i];
186    } 
187
188    /*  Find the most frequent class  */
189
190    BestClass = 0;
191    ForEach(c, 0, MaxClass)
192    {
193        if ( ClassFreq[c] > ClassFreq[BestClass] )
194        {
195            BestClass = c;
196        }
197    }
198    NoBestClass = ClassFreq[BestClass];
199
200    Node = Leaf(ClassFreq, BestClass, Cases, Cases - NoBestClass);
201
202    /*  If all cases are of the same class or there are not enough
203        cases to divide, the tree is a leaf  */
204
205    if ( NoBestClass == Cases  || Cases < 2 * MINOBJS )
206    { 
207        return Node;
208    } 
209
210    Verbosity(1)
211        printf("\n%d items, total weight %.1f\n", Lp - Fp + 1, Cases);
212
213    /*  For each available attribute, find the information and gain  */
214
215    ForEach(Att, 0, MaxAtt) 
216    { 
217        Gain[Att] = -Epsilon;
218
219        if ( SpecialStatus[Att] == IGNORE ) continue;
220
221        if ( MaxAttVal[Att] )
222        {
223            /*  discrete valued attribute  */
224
225            if ( SUBSET && MaxAttVal[Att] > 2 )
226            {
227                EvalSubset(Att, Fp, Lp, Cases);
228            }
229            else
230            if ( ! Tested[Att] )
231            {
232                EvalDiscreteAtt(Att, Fp, Lp, Cases);
233            }
234        }
235        else
236        { 
237            /*  continuous attribute  */
238
239            EvalContinuousAtt(Att, Fp, Lp);
240        } 
241
242        /*  Update average gain, excluding attributes with very many values  */
243
244        if ( Gain[Att] > -Epsilon &&
245             ( MultiVal || MaxAttVal[Att] < 0.3 * (MaxItem + 1) ) )
246        {
247            Possible++;
248            AvGain += Gain[Att];
249        }
250    } 
251
252    /*  Find the best attribute according to the given criterion  */
253
254    BestVal = -Epsilon;
255    BestAtt = None;
256    AvGain  = ( Possible ? AvGain / Possible : 1E6 );
257
258    Verbosity(2)
259    {
260        if ( AvGain < 1E6 ) printf("\taverage gain %.3f\n", AvGain);
261    }
262
263    ForEach(Att, 0, MaxAtt) 
264    { 
265        if ( Gain[Att] > -Epsilon )
266        { 
267            Val = Worth(Info[Att], Gain[Att], AvGain);
268            if ( Val > BestVal ) 
269            { 
270                BestAtt  = Att; 
271                BestVal = Val;
272            } 
273        } 
274    } 
275
276    /*  Decide whether to branch or not  */ 
277
278    if ( BestAtt != None )
279    { 
280        Verbosity(1)
281        {
282            printf("\tbest attribute %s", AttName[BestAtt]);
283            if ( ! MaxAttVal[BestAtt] )
284            {
285                printf(" cut %.3f", Bar[BestAtt]);
286            }
287            printf(" inf %.3f gain %.3f val %.3f\n",
288                   Info[BestAtt], Gain[BestAtt], BestVal);
289        }       
290
291        /*  Build a node of the selected test  */
292
293        if ( MaxAttVal[BestAtt] )
294        {
295            /*  Discrete valued attribute  */
296
297            if ( SUBSET && MaxAttVal[BestAtt] > 2 )
298            {
299                SubsetTest(Node, BestAtt);
300            }
301            else
302            {
303                DiscreteTest(Node, BestAtt);
304            }
305        }
306        else
307        { 
308            /*  Continuous attribute  */
309
310            ContinTest(Node, BestAtt);
311        } 
312
313        /*  Remove unknown attribute values  */
314
315        PrevAllKnown = AllKnown;
316
317        Kp = Group(0, Fp, Lp, Node) + 1;
318        if ( Kp != Fp ) AllKnown = false;
319        KnownCases = Cases - CountItems(Fp, Kp-1);
320        UnknownRate[BestAtt] = (Cases - KnownCases) / (Cases + 0.001);
321
322        Verbosity(1)
323        {
324            if ( UnknownRate[BestAtt] > 0 )
325            {
326                printf("\tunknown rate for %s = %.3f\n",
327                       AttName[BestAtt], UnknownRate[BestAtt]);
328            }
329        }
330
331        /*  Recursive divide and conquer  */
332
333        ++Tested[BestAtt];
334
335        Ep = Kp - 1;
336        Node->Errors = 0;
337
338        ForEach(v, 1, Node->Forks)
339        {
340            Ep = Group(v, Kp, Lp, Node);
341
342            if ( Kp <= Ep )
343            {
344                Factor = CountItems(Kp, Ep) / KnownCases;
345
346                ForEach(i, Fp, Kp-1)
347                {
348                    Weight[i] *= Factor;
349                }
350
351                Node->Branch[v] = FormTree(Fp, Ep);
352                Node->Errors += Node->Branch[v]->Errors;
353
354                Group(0, Fp, Ep, Node);
355                ForEach(i, Fp, Kp-1)
356                {
357                    Weight[i] /= Factor;
358                }
359            }
360            else
361            {
362                Node->Branch[v] = Leaf(Node->ClassDist, BestClass, 0.0, 0.0);
363            }
364        }
365
366        --Tested[BestAtt];
367        AllKnown = PrevAllKnown;
368
369        /*  See whether we would have been no worse off with a leaf  */
370
371        if ( Node->Errors >= Cases - NoBestClass - Epsilon )
372        { 
373            Verbosity(1)
374                printf("Collapse tree for %d items to leaf %s\n",
375                        Lp - Fp + 1, ClassName[BestClass]);
376
377            Node->NodeType = 0;
378        } 
379    }
380    else
381    { 
382        Verbosity(1)
383            printf("\tno sensible splits  %.1f/%.1f\n",
384                   Cases, Cases - NoBestClass);
385    } 
386
387    return Node; 
388} 
389
390
391
392/*************************************************************************/
393/*                                                                       */
394/*  Group together the items corresponding to branch V of a test         */
395/*  and return the index of the last such                                */
396/*                                                                       */
397/*  Note: if V equals zero, group the unknown values                     */
398/*                                                                       */
399/*************************************************************************/
400
401
402ItemNo Group(V, Fp, Lp, TestNode)
403/*     -----  */
404    DiscrValue V;
405    ItemNo Fp, Lp;
406    Tree TestNode;
407{
408    ItemNo i;
409    Attribute Att;
410    float Thresh;
411    Set SS;
412    void Swap();
413
414    Att = TestNode->Tested;
415
416    if ( V )
417    {
418        /*  Group items on the value of attribute Att, and depending
419            on the type of branch  */
420
421        switch ( TestNode->NodeType )
422        {
423            case BrDiscr:
424
425                ForEach(i, Fp, Lp)
426                {
427                    if ( DVal(Item[i], Att) == V ) Swap(Fp++, i);
428                }
429                break;
430
431            case ThreshContin:
432
433                Thresh = TestNode->Cut;
434                ForEach(i, Fp, Lp)
435                {
436                    if ( (CVal(Item[i], Att) <= Thresh) == (V == 1) ) Swap(Fp++, i);
437                }
438                break;
439
440            case BrSubset:
441
442                SS = TestNode->Subset[V];
443                ForEach(i, Fp, Lp)
444                {
445                    if ( In(DVal(Item[i], Att), SS) ) Swap(Fp++, i);
446                }
447                break;
448        }
449    }
450    else
451    {
452        /*  Group together unknown values  */
453
454        switch ( TestNode->NodeType )
455        {
456            case BrDiscr:
457            case BrSubset:
458
459                ForEach(i, Fp, Lp)
460                {
461                    if ( ! DVal(Item[i], Att) ) Swap(Fp++, i);
462                }
463                break;
464
465            case ThreshContin:
466
467                ForEach(i, Fp, Lp)
468                {
469                    if ( CVal(Item[i], Att) == Unknown ) Swap(Fp++, i);
470                }
471                break;
472        }
473    }
474
475    return Fp - 1;
476}
477
478
479
480/*************************************************************************/
481/*                                                                       */
482/*      Return the total weight of items from Fp to Lp                   */
483/*                                                                       */
484/*************************************************************************/
485
486
487ItemCount CountItems(Fp, Lp)
488/*        ----------  */
489    ItemNo Fp, Lp;
490{
491    register ItemCount Sum=0.0, *Wt, *LWt;
492
493    if ( AllKnown ) return Lp - Fp + 1;
494
495    for ( Wt = Weight + Fp, LWt = Weight + Lp ; Wt <= LWt ; )
496    {
497        Sum += *Wt++;
498    }
499
500    return Sum;
501}
502
503
504
505/*************************************************************************/
506/*                                                                       */
507/*              Exchange items at a and b                                */
508/*                                                                       */
509/*************************************************************************/
510
511
512void Swap(a,b)
513/*   ----  */
514    ItemNo a, b;
515{
516    register Description Hold;
517    register ItemCount HoldW;
518
519    Hold = Item[a];
520    Item[a] = Item[b];
521    Item[b] = Hold;
522
523    HoldW = Weight[a];
524    Weight[a] = Weight[b];
525    Weight[b] = HoldW;
526}
Note: See TracBrowser for help on using the repository browser.