code: def calculate_auc(auc_structure, sort_order, diff = None):
      
  
      # sort by best scores
      if sort_order == 'asc':
          auc_structure.sort(key=lambda x: float(x[1]))
      elif sort_order == 'dsc':
          auc_structure.sort(key=lambda x: float(x[1]), reverse=True)
  
      # AUC calculation <tpf>d
      auc = 0.                         # auc average
      n = 0                           # decoy count
      for mol in auc_structure:
          status = mol[3]
          if status == '0':
              tpf = mol[5]
              n += 1
              auc += tpf
      if n == 0:
          auc = 0
      else:
          auc = (1. / n) * auc
  
      if diff:
          return auc
      else:
          # confidence interval calculations
          n = len([x for x in auc_structure if x[3] == '0'])          # no of decoys
          p = len([x for x in auc_structure if x[3] == '1'])          # no of actives
          aucvar_a, aucvar_d = calculate_auc_var(auc_structure)       # variance due to active and decoys
          se = (aucvar_a / p + aucvar_d / n) ** 0.5                   # standard error
          ci = se * stats.t.ppf(1 - 0.025, n + p - 1)                 # 95% confidence interval
  
          # bounds
          lower = auc - ci
          upper = auc + ci
  
          # dumb limit checking (ADD LOGIT FUNCTION)
          if lower < 0:
           lower = 0.0
          if upper > 1:
            upper = 1.0
  
          return (auc, lower, upper)
docs: TO DO: Add logit bounds
      determine AUC and 95% confidence intervals (CI)
      :param roc_structure: auc_structure: list [(id, best_score, best_query, status, fpf, tpf), ..., ]
      :param sort_order: either 'asc' (binding free energy estimates) or 'dsc' (probabilities)
      :return (AUC, AUC - CI, AUC + CI): tuple