lolamontes69

treepredict.py for Ch7 Programming Collective Intelligence

Jul 24th, 2013
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.52 KB | None | 0 0
  1. from PIL import Image,ImageDraw
  2.  
  3. my_data=[line.split('\t') for line in file('decision_tree_example.txt')]
  4. # Replace '/n' or it taints the data (example:{'Basic\n': 4, 'Premium\n': 1, 'Basic': 1})
  5. for a in range(len(my_data)):
  6.     for b in range(len(my_data[a])):
  7.         my_data[a][b] = my_data[a][b].replace('\n','')
  8.  
  9.  
  10. class decisionnode:
  11.     def __init__(self,col=-1,value=None,results=None,tb=None,fb=None):
  12.         self.col=col
  13.         self.value=value
  14.         self.results=results
  15.         self.tb=tb
  16.         self.fb=fb
  17.  
  18. # Divides a set on a specific column. Can handle numeric or nominal values
  19. def divideset(rows,column,value):
  20.     try: value = int(value) # The numerical data is saved as strings within my_data
  21.     except: pass
  22.  
  23.     # Make a function that tells us if a row is in the first group (true) or the second (false)
  24.     split_function=None
  25.     if isinstance(value,int) or isinstance(value,float):
  26.         split_function=lambda row: int(row[column])>=value
  27.     else:
  28.         split_function=lambda row:row[column]==value
  29.        
  30.     # Divide the rows into two sets and return them
  31.     set1=[row for row in rows if split_function(row)]
  32.     set2=[row for row in rows if not split_function(row)]
  33.     return (set1,set2)
  34.  
  35. # Create counts of possible results ( the last column of each row is the result)
  36. def uniquecounts(rows):
  37.     results={}
  38.     for row in rows:
  39.         # The result is the last column
  40.         r=row[len(row)-1]
  41.         if r not in results: results[r]=0
  42.         results[r]+=1
  43.     return results
  44.  
  45. # Probability that a randomly placed item will be in the wrong category
  46. def giniimpurity(rows):
  47.     total=len(rows)
  48.     counts=uniquecounts(rows)
  49.     imp=0
  50.     for k1 in counts:
  51.         p1=float(counts[k1])/total
  52.         for k2 in counts:
  53.             if k1==k2: continue
  54.             p2=float(counts[k2])/total
  55.             imp+=p1*p2
  56.     return imp
  57.  
  58. # Entropy is the sum of p(x)log(p(x)) across all the different possible results
  59. def entropy(rows):
  60.     from math import log
  61.     log2=lambda x:log(x)/log(2)
  62.     results=uniquecounts(rows)
  63.     # Now calculate the entropy
  64.     ent=0.0
  65.     for r in results.keys():
  66.         p=float(results[r])/len(rows)
  67.         ent=ent-p*log2(p)
  68.     return ent
  69.  
  70. def buildtree(rows,scoref=entropy):
  71.     if len(rows)==0: return decisionnode()
  72.     current_score=scoref(rows)
  73.  
  74.     # set up some variables to track the best criteria
  75.     best_gain=0.0
  76.     best_criteria=None
  77.     best_sets=None
  78.  
  79.     column_count=len(rows[0])-1
  80.     for col in range(0,column_count):
  81.         # Generate the list of different values in this column
  82.         column_values={}
  83.         for row in rows:
  84.             column_values[row[col]]=1
  85.         # Now try dividing the rows up for each value in this column
  86.         for value in column_values.keys():
  87.             (set1,set2)=divideset(rows,col,value)
  88.  
  89.             # Information gain
  90.             p=float(len(set1))/len(rows)
  91.             gain=current_score-p*scoref(set1)-(1-p)*scoref(set2)
  92.             if gain>best_gain and len(set1)>0 and len(set2)>0:
  93.                 best_gain=gain
  94.                 best_criteria=(col,value)
  95.                 best_sets=(set1,set2)
  96.     # Create the subbranches
  97.     if best_gain>0:
  98.         trueBranch=buildtree(best_sets[0],scoref)                        # corrected adding scoref
  99.         falseBranch=buildtree(best_sets[1],scoref)                       # corrected adding scoref
  100.         return decisionnode(col=best_criteria[0],value=best_criteria[1],
  101.                             tb=trueBranch,fb=falseBranch)
  102.     else:
  103.         return decisionnode(results=uniquecounts(rows))
  104.  
  105. def printtree(tree,indent='  '):
  106.     # Is this a leaf node?
  107.     if tree.results!=None:
  108.         print str(tree.results)
  109.     else:
  110.         # Print the criteria
  111.         print str(tree.col)+':'+str(tree.value)+'? '
  112.  
  113.         # Print the branches
  114.         print indent+'T->',
  115.         printtree(tree.tb,indent+'  ')
  116.         print indent+'F->',
  117.         printtree(tree.fb,indent+'  ')
  118.  
  119. def getwidth(tree):
  120.     if tree.tb==None and tree.fb==None: return 1
  121.     return getwidth(tree.tb)+getwidth(tree.fb)
  122.  
  123. def getdepth(tree):
  124.     if tree.tb==None and tree.fb==None: return 0
  125.     return max(getdepth(tree.tb),getdepth(tree.fb))+1
  126.  
  127. def drawtree(tree,jpeg='tree.jpg'):
  128.     w=getwidth(tree)*100
  129.     h=getdepth(tree)*100+120
  130.  
  131.     img=Image.new('RGB',(w,h),(255,255,255))
  132.     draw=ImageDraw.Draw(img)
  133.  
  134.     drawnode(draw,tree,w/2,20)
  135.     img.save(jpeg,'JPEG')
  136.  
  137. def drawnode(draw,tree,x,y):
  138.     if tree.results==None:
  139.         # Get the width of each branch
  140.         w1=getwidth(tree.fb)*100
  141.         w2=getwidth(tree.tb)*100
  142.  
  143.         # Determine the total space required by this node
  144.         left=x-(w1+w2)/2
  145.         right=x+(w1+w2)/2
  146.  
  147.         # Draw the condition string
  148.         draw.text((x-20,y-10),str(tree.col)+':'+str(tree.value),(0,0,0))
  149.  
  150.         # Draw links to the branches
  151.         draw.line((x,y,left+w1/2,y+100),fill=(255,0,0))
  152.         draw.line((x,y,right-w2/2,y+100),fill=(255,0,0))
  153.  
  154.         # Draw the branch nodes
  155.         drawnode(draw,tree.fb,left+w1/2,y+100)
  156.         drawnode(draw,tree.tb,right-w2/2,y+100)
  157.     else:
  158.         txt=' \n'.join(['%s:%d'%v for v in tree.results.items()])
  159.         draw.text((x-20,y),txt,(0,0,0))
  160.  
  161. def classify(observation,tree):
  162.     if tree.results!=None:
  163.         return tree.results
  164.     else:
  165.         v=observation[tree.col]
  166.         branch=None
  167.         if isinstance(v,int) or isinstance(v,float):
  168.             if v>=tree.value: branch=tree.tb
  169.             else: branch=tree.fb
  170.         else:
  171.             if v==tree.value: branch=tree.tb
  172.             else: branch=tree.fb
  173.         return classify(observation,branch)
  174.  
  175. def prune(tree,mingain):
  176.     # If the branches aren't leaves prune them
  177.     if tree.tb.results==None:
  178.         prune(tree.tb,mingain)
  179.     if tree.fb.results==None:
  180.         prune(tree.fb,mingain)
  181.  
  182.     # If both the subbranches are now leaves, see if they should be merged
  183.     if tree.tb.results!=None and tree.fb.results!=None:
  184.         # Build a combined dataset
  185.         tb,fb=[],[]
  186.         for v,c in tree.tb.results.items():
  187.             tb+=[[v]]*c
  188.         for v,c in tree.fb.results.items():
  189.             fb+=[[v]]*c
  190.  
  191.         # Test the reduction in entropy
  192.         delta=entropy(tb+fb)-(entropy(tb)+entropy(fb))/2     # Xiaochen Wang CORRECTION
  193.         if delta<mingain:
  194.             # Merge the branches
  195.             tree.tb,tree.fb=None,None
  196.             tree.results=uniquecounts(tb+fb)
  197.  
  198. def mdclassify(observation,tree):
  199.     if tree.results!=None:
  200.         return tree.results
  201.     else:
  202.         v=observation[tree.col]
  203.         if v==None:
  204.             tr,fr=mdclassify(observation,tree.tb),mdclassify(observation,tree.fb)
  205.             tcount=sum(tr.values())
  206.             fcount=sum(fr.values())
  207.             tw=float(tcount)/(tcount+fcount)
  208.             fw=float(fcount)/(tcount+fcount)
  209.             result={}
  210.             for k,v in tr.items(): result[k]=v*tw
  211.             for k,v in fr.items(): result[k]=v*fw
  212.             return result
  213.         else:
  214.             if isinstance(v,int) or isinstance(v,float):
  215.                 if v>tree.value: branch=tree.tb
  216.                 else: branch=tree.fb
  217.             else:
  218.                 if v==tree.value: branch=tree.tb
  219.                 else: branch=tree.fb
  220.             return mdclassify(observation,branch)
  221.  
  222. def variance(rows):
  223.     if len(rows)==0: return 0
  224.     data=[float(row[len(row)-1]) for row in rows]
  225.     mean=sum(data)/len(data)
  226.     variance=sum([(d-mean)**2 for d in data])/len(data)
  227.     return variance
Advertisement
Add Comment
Please, Sign In to add comment