import numpy as np
import pandas as pd

data_df = pd.read_csv('../data/feature_set.csv')
Y = data_df['Class']
feature_names = data_df.columns.values[2:]
#print feature_names

def entropy(target):
    # Get the number of users
    n = len(target)
    # print np.bincount(np.array([0, 1, 1, 1, 0, 0,1])) outputs [3,4]
    # Count how frequently each unique value occurs
    counts = np.bincount(target).astype(float)[1:]
    # Initialize entropy
    entropy = 0
    # If the split is perfect, return 0
    if len(counts) <= 1 or 0 in counts:
        return entropy
    # Otherwise, for each possible value, update entropy
    for count in counts:
        entropy += math.log(count/n, len(counts)) * count/n
        # math.log(a,b)= logb(a)
    # Return entropy
    return -1 * entropy

def information_gain(feature, threshold, target):
    # Dealing with numpy arrays makes this slightly easier
    target = np.array(target)
    feature = np.array(feature)
    #print "feature is",
    #print feature
    # Cut the feature vector on the threshold
    feature = (feature < threshold)
    #print "feature is",
    #print feature
    # Initialize information gain with the parent entropy
    ig = entropy(target)
    # For both sides of the threshold, update information gain
    for level, count in zip([0, 1], np.bincount(feature).astype(float)):  # coutput likes [(0, 250.0), (1, 250.0)]
        ig -= count/len(feature) * entropy(target[feature == level])
    # Return information gain
    return ig

def best_threshold(number):
    
    # define the following two dict variables to record the maximum information gain info and thresholds
    feature_ig = {}
    feature_thres = {}
    
    # figure out all feature's information gain and relevant threshold
    for i in range(0,len(feature_names)):
        maximum_ig = 0
        maximum_threshold = 0
        for threshold in data_df[feature_names[i]]:
            ig = information_gain(data_df[feature_names[i]], threshold, np.array(Y))
            if ig > maximum_ig:
                maximum_ig = ig
                maximum_threshold = threshold
        
        feature_ig[feature_names[i]] = maximum_ig
        feature_thres[feature_names[i]] = maximum_threshold

   
    
    # find out the most informative 'n' features
    # sort via information gain, pay atention to that the dict has been converted to list of tuple
    feature_ig = sorted(feature_ig.items(), key=lambda x:x[1])
    
    print "The most {} informative feature, the corresponding threshold and maximum information gain are listed below:".format(number)
    for i in range(0,number):
        feature = feature_ig[len(feature_names)-(i+1)][0]
        ig = feature_ig[len(feature_names)-(i+1)][1]
        thres = feature_thres[feature]
        print "the {}th most informative feature is {}, IG is {:.3}, threshold is {}".format(i+1, feature, ig, thres)

best_threshold(len(feature_names))