text: #-*-coding:utf-8-*-
  import numpy as np
  import pandas as pd
  import scipy as sp
  import scipy.special as special
  import random
  
  #平滑，这个快一点；
  # hyper=HyperParam(1, 1);
  # hyper.update_from_data_by_moment(show, click)
  class HyperParam(object):
      def __init__(self, alpha, beta):
          self.alpha = alpha
          self.beta = beta
  
      def sample_from_beta(self, alpha, beta, num, imp_upperbound):
          sample = numpy.random.beta(alpha, beta, num)
          I = []
          C = []
          for click_ratio in sample:
              imp = random.random() * imp_upperbound
              #imp = imp_upperbound
              click = imp * click_ratio
              I.append(imp)
              C.append(click)
          return I, C
  
      def update_from_data_by_FPI(self, tries, success, iter_num, epsilon):
          '''estimate alpha, beta using fixed point iteration'''
          for i in range(iter_num):
              new_alpha, new_beta = self.__fixed_point_iteration(tries, success, self.alpha, self.beta)
              if abs(new_alpha-self.alpha)<epsilon and abs(new_beta-self.beta)<epsilon:
                  break
              self.alpha = new_alpha
              self.beta = new_beta
  
      def __fixed_point_iteration(self, tries, success, alpha, beta):
          '''fixed point iteration'''
          sumfenzialpha = 0.0
          sumfenzibeta = 0.0
          sumfenmu = 0.0
          for i in range(len(tries)):
              sumfenzialpha += (special.digamma(success[i]+alpha) - special.digamma(alpha))
              sumfenzibeta += (special.digamma(tries[i]-success[i]+beta) - special.digamma(beta))
              sumfenmu += (special.digamma(tries[i]+alpha+beta) - special.digamma(alpha+beta))
  
          return alpha*(sumfenzialpha/sumfenmu), beta*(sumfenzibeta/sumfenmu)
  
      def update_from_data_by_moment(self, tries, success):
          '''estimate alpha, beta using moment estimation'''
          mean, var = self.__compute_moment(tries, success)
          self.alpha = (mean+0.000001) * ((mean+0.000001) * (1.000001 - mean) / (var+0.000001) - 1)
          
          self.beta = (1.000001 - mean) * ((mean+0.000001) * (1.000001 - mean) / (var+0.000001) - 1)
  
      def __compute_moment(self, tries, success):
          '''moment estimation'''
          ctr_list = []
          var = 0.0
  
          for i in range(len(tries)):
             
              ctr_list.append(float(success[i])/float(tries[i]+0.0000001))
          mean = sum(ctr_list)/len(ctr_list)
          for ctr in ctr_list:
              var += pow(ctr-mean, 2)
  
          return mean, var/(len(ctr_list)-1)
  
  
  
  
  class BayesianSmoothing(object):
      def __init__(self, alpha, beta):
          self.alpha = alpha
          self.beta = beta
  
      def sample(self, alpha, beta, num, imp_upperbound):
          sample = np.random.beta(alpha, beta, num)
          I = []
          C = []
          for clk_rt in sample:
              imp = random.random() * imp_upperbound
              imp = imp_upperbound
              clk = imp * clk_rt
              I.append(imp)
              C.append(clk)
          return I, C
  
      def update(self, imps, clks, iter_num, epsilon):
          for i in range(iter_num):
              print('~~~~~~~~~~~~~~%d~~~~~~~~~~~~~~~~' %(i))
              new_alpha, new_beta = self.__fixed_point_iteration(imps, clks, self.alpha, self.beta)
              if abs(new_alpha - self.alpha) < epsilon and abs(new_beta - self.beta) < epsilon:
                  break
              self.alpha = new_alpha
              self.beta = new_beta
  
      def __fixed_point_iteration(self, imps, clks, alpha, beta):
          numerator_alpha = 0.0
          numerator_beta = 0.0
          denominator = 0.0
  
          for i in range(len(imps)):
              numerator_alpha += (special.digamma(clks[i] + alpha) - special.digamma(alpha))
              numerator_beta += (special.digamma(imps[i] - clks[i] + beta) - special.digamma(beta))
              denominator += (special.digamma(imps[i] + alpha + beta) - special.digamma(alpha + beta))
  
          return alpha * (numerator_alpha / denominator), beta * (numerator_beta / denominator)
  
  
  
  def bs_utilize(count_all_column, count_1_column):
     
      hyper = HyperParam(1, 1);
      hyper.update_from_data_by_moment(count_all_column.values, count_1_column.values)
  
  
      smoothed = (count_1_column + hyper.alpha) / (count_all_column + hyper.alpha + hyper.beta)
     
      return smoothed
  
  
  
  if __name__ == '__main__':
      pass
      