docs: def precision_recall(self, num_thresholds, target_class, probability_column=None):
      """Get precision, recall values from evaluation results.
  
      Args:
        num_thresholds: an integer. Number of thresholds.
        target_class: a string indciating the target class, i.e. "daisy" in flower classification.
        probability_column: the name of the probability column. If None, defaults to
            value of target_class.
  
      Returns:
        A DataFrame with columns: 'threshold', 'precision', 'recall' with number of rows
        equal to num_thresholds.
  
      Raises:
        Exception if the CSV headers do not include 'target' or probability_column, or BigQuery
        does not return 'target' or probability_column column.
      """
  
      if not probability_column:
        probability_column = target_class
  
      # threshold = 1.0 is excluded.
      thresholds = np.linspace(0, 1, num_thresholds + 1)[0:-1]
      if self._input_csv_files:
        df = self._get_data_from_csv_files()
        if 'target' not in df or probability_column not in df:
          raise ValueError('Cannot find "target" or "%s" column' % probability_column)
  
        total_target = sum(1 for x in df['target'] if x == target_class)
        total_predicted = []
        correct_predicted = []
        for threshold in thresholds:
          predicted_count = sum(1 for x in df[probability_column] if x > threshold)
          total_predicted.append(predicted_count)
          correct_count = len(df[(df[probability_column] > threshold) &
                              (df['target'] == target_class)])
          correct_predicted.append(correct_count)
  
        data = []
        for p, c, t in zip(total_predicted, correct_predicted, thresholds):
          precision = (float)(c) / p if p > 0. else 0.
          recall = (float)(c) / total_target if total_target > 0. else 0.
          data.append({'precision': precision, 'recall': recall, 'threshold': t})
        return pd.DataFrame(data)
  
      elif self._bigquery:
        total_predicted_query = bq.Query("""
          SELECT
            COUNT(*) as total_predicted
          FROM
            %s
          CROSS JOIN
            (SELECT * FROM UNNEST ([%s]) as t)
          WHERE
            %s > t
          GROUP BY t
          ORDER BY t
        """ % (self._bigquery, ','.join(map(str, thresholds)), probability_column))
  
        correct_predicted_query = bq.Query("""
          SELECT
            COUNT(*) as correct_predicted
          FROM
            %s
          CROSS JOIN
            (SELECT * FROM UNNEST ([%s]) as t)
          WHERE
            %s > t AND target='%s'
          GROUP BY t
          ORDER BY t
        """ % (self._bigquery, ','.join(map(str, thresholds)), probability_column, target_class))
  
        total_target_query = bq.Query("""
          SELECT
            COUNT(*) as total_target
          FROM
            %s
          WHERE
            target='%s'
        """ % (self._bigquery, target_class))
  
        total_predicted = total_predicted_query.execute().result()
        correct_predicted = correct_predicted_query.execute().result()
        total_target = total_target_query.execute().result()[0]['total_target']
        data = []
        for p, c, t in zip(total_predicted, correct_predicted, thresholds):
          precision = ((float)(c['correct_predicted']) / p['total_predicted']
                       if p['total_predicted'] > 0. else 0.)
          recall = (float)(c['correct_predicted']) / total_target if total_target > 0. else 0.
          data.append({'precision': precision, 'recall': recall, 'threshold': t})
        return pd.DataFrame(data)