import pandas as pd
from math import log
import operator
import re
import random
from decision_tree.treePloter import createPlot


def simplify_label(dataset):
    # generate label
    dataset['label'] = 0
    dataset.loc[dataset['class'] == 'Iris-setosa', 'label'] = 1
    dataset.loc[dataset['class'] == 'Iris-versicolor', 'label'] = 2
    dataset.loc[dataset['class'] == 'Iris-virginica', 'label'] = 3
    return dataset

def majorityClass(dataSet):
    classList=dataSet.iloc[:,-1]
    classCount={}
    for one in classList:
        if one not in classCount.keys():
            classCount[one]=0
        classCount[one]+=1
    sortedClass=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClass[0][0]

def calcShannonEnt(dataSet):
    labelList=dataSet.iloc[:,-1]
    labelCount={}
    entropy=0.0
    for one in labelList:
        if one not in labelCount.keys():
            labelCount[one]=1
        else:
            labelCount[one]+=1
    for key in labelCount:
        prob=float(labelCount[key])/len(dataSet)
        entropy-=prob*log(prob,2)
    return entropy

def splitDataSet(dataSet,axis,value):
    greaterDataSet=dataSet[dataSet.iloc[:,axis]>=value]
    lessDataSet=dataSet[dataSet.iloc[:,axis]<value]
    greaterDataSet=greaterDataSet.drop(greaterDataSet.columns[axis],axis=1)
    #print(greaterDataSet)
    lessDataSet=lessDataSet.drop(lessDataSet.columns[axis],axis=1)
    #print(lessDataSet)
    return greaterDataSet,lessDataSet

def chooseBestFeat(dataSet):
    featList=dataSet.columns[:-1]
    #print(featList)
    baseEntropy=calcShannonEnt(dataSet)
    bestFeat=-1
    baseInfoGain=0.0
    meanVals=[]
    for i in range(len(featList)):
        classList=dataSet.iloc[:,i]
        meanVals.append(classList.mean())
        greaterDataSet, lessDataSet = splitDataSet(dataSet, i, meanVals[i])
        prob1=float(len(greaterDataSet))/len(dataSet)
        newEntropy1=prob1*calcShannonEnt(greaterDataSet)
        splitInfo1=prob1*log(prob1,2)
        prob2=float(len(lessDataSet))/len(dataSet)
        newEntropy2=prob2*calcShannonEnt(lessDataSet)
        splitInfo2=prob2*log(prob2,2)
        newInfoGain=(baseEntropy-newEntropy1-newEntropy2)/-(splitInfo1+splitInfo2)
        #newInfoGain = (baseEntropy - newEntropy1 - newEntropy2)
        #print('Gain '+dataSet.columns[i]+'= '+str(newInfoGain))
        if newInfoGain>baseInfoGain:
            bestFeat=i
            baseInfoGain=newInfoGain
    return bestFeat




def createTree(dataSet):
    labelList=dataSet.iloc[:,-1]
    if(len(dataSet.columns)==2):
        return majorityClass(dataSet)
    if(len(set(labelList))==1):
        return labelList.iloc[0]
    bestFeat=chooseBestFeat(dataSet)
    labelBestFeat=dataSet.columns[bestFeat]
    myTree = {labelBestFeat: {}}
    meanVal = dataSet.iloc[:, bestFeat].mean()
    greaterDataSet, lessDataSet = splitDataSet(dataSet, bestFeat, meanVal)
    for i in range(len(dataSet)):
        if(dataSet.iloc[i,bestFeat]>=meanVal):
            dataSet.iloc[i,bestFeat]=1
        else:
            dataSet.iloc[i,bestFeat]=0
    valueList = dataSet.iloc[:, bestFeat]
    uniqueVals = set(valueList)
    for value in uniqueVals:
        if (value == 1):
            myTree[labelBestFeat]['>=' + str(meanVal)] = createTree(greaterDataSet)
        else:
            myTree[labelBestFeat]['<' + str(meanVal)] = createTree(lessDataSet)
    return myTree

def getParameter(value):
    sig=re.match(r'(\D+){1}(\d+\.?\d*)',value)
    signal = sig.group(1)
    parameter = float(sig.group(2))
    #print('sig=')
    #print(sig.group(1))
    #print('parameter=')
    #print(float(sig.group(2)))
    return signal,parameter

def compareDataParameter(data,parameter):
    if((data-parameter)>=0.0):
        return '>='
    else:
        return '<'


def readTree(myTree,data,listEva):
    try:
        keys=myTree.keys()
        listKey=list(keys)
        for i in range(len(listKey)):
            tempTree=myTree[listKey[i]]
            values=tempTree.keys()
            listValue=list(values)
            feat=listKey[i]
            #print('feat='+listKey[i])
            for j in range(len(listValue)):
                #print(str(j)+': ')
                #print(listValue[j])
                signal,parameter=getParameter(listValue[j])
                temp=compareDataParameter(data[listKey[i]],parameter)
                if(signal==temp):
                    subTree=myTree[listKey[i]][listValue[j]]
                    if (subTree == 1 or subTree == 2 or subTree == 3):
                        #print('****result:')
                        #print(subTree)
                        listEva.append(subTree)
                        return subTree
                    else:
                        readTree(subTree, data,listEva)
                    #print('subTree is :')
                    #print(subTree)
                else:
                    j+=1
                    continue
    except Exception as e:
        print(e)


def classify(path,myTree,dataSet):
    #print(myTree)
    #print('\t')
    listFeat=dataSet.columns
    listEva=[]
    for x in range(len(dataSet)):
        one=dataSet.iloc[x,:]
        readTree(myTree,one,listEva)
        #listEva.append(result)
    #print(listEva)
    dataSet.insert(len(dataSet.columns),'evaluate',listEva)
    dataSet.to_csv(path+'result.csv')
    '''    
    try:
        keys=myTree.keys()
        listKey=list(keys)
        for i in range(len(listKey)):
            tempTree=myTree[listKey[i]]
            values=tempTree.keys()
            listValue=list(values)
            for j in range(len(listValue)):
                signal,parameter=getParameter(listValue[j])
                subTree=myTree[listKey[i]][listValue[j]]
                classify(myTree)
    except:
        print()
    '''
def judgeResult(result):
    judgeCount={}
    right='right'
    wrong='wrong'
    judgeCount[right]=0
    judgeCount[wrong]=0
    for i in range(len(result)):
        if(result.iloc[i,-1]==result.iloc[i,-2]):
            judgeCount[right]+=1
        else:
            judgeCount[wrong]+=1
    #print(judgeCount)
    print('the rate is : '+str(judgeCount[right]/len(result)))


if __name__ == '__main__':
    path = '/home/tyler/machine_learning/data/'
    iris_train=pd.read_csv(path+'iris_train.csv')
    iris_train.drop('class',axis=1,inplace=True)
    iris_test=pd.read_csv(path+'iris_evaluate.csv')
    myTree=createTree(iris_train)
    #Stree={'petal_length': {'<3.805714285714286': {'petal_width': {'<0.3609756097560974': 1, '>=0.3609756097560974': {'sepal_width': {'<3.1307692307692303': 2, '>=3.1307692307692303': 1}}}}, '>=3.805714285714286': {'petal_width': {'<1.7156249999999997': {'sepal_width': {'<2.7909090909090906': 2, '>=2.7909090909090906': 2}}, '>=1.7156249999999997': {'sepal_width': {'<2.996774193548387': 3, '>=2.996774193548387': 3}}}}}}
    print(myTree)
    createPlot(myTree)
    classify(path,myTree,iris_test)
    result=pd.read_csv(path+'result.csv')
    judgeResult(result)