class_docstr: Calculates the values of a set of features for given instance ids.
code: def _calculate_groupby_features(
      self, features, frame, _df_trie, progress_callback
  ):
      # set default values to handle the null group
      default_values = {}
      for f in features:
          for name in f.get_feature_names():
              default_values[name] = f.default_value
  
      frame = pd.concat(
          [frame, pd.DataFrame(default_values, index=frame.index)],
          axis=1,
      )
  
      # handle when no data
      if frame.shape[0] == 0:
          progress_callback(len(features) / float(self.num_features))
  
          return frame
  
      groupby = features[0].groupby.get_name()
      grouped = frame.groupby(groupby)
      groups = frame[
          groupby
      ].unique()  # get all the unique group name to iterate over later
  
      for f in features:
          feature_vals = []
          for _ in range(f.number_output_features):
              feature_vals.append([])
  
          for group in groups:
              # skip null key if it exists
              if pd.isnull(group):
                  continue
  
              column_names = [bf.get_name() for bf in f.base_features]
              # exclude the groupby column from being passed to the function
              column_data = [
                  grouped[name].get_group(group)
                  for name in column_names[:-1]
              ]
              feature_func = f.get_function()
  
              # apply the function to the relevant dataframe slice and add the
              # feature row to the results dataframe.
              if f.primitive.uses_calc_time:
                  values = feature_func(
                      *column_data, time=self.time_last
                  )
              else:
                  values = feature_func(*column_data)
  
              if f.number_output_features == 1:
                  values = [values]
  
              # make sure index is aligned
              for i, value in enumerate(values):
                  if isinstance(value, pd.Series):
                      value.index = column_data[0].index
                  else:
                      value = pd.Series(
                          value, index=column_data[0].index
                      )
                  feature_vals[i].append(value)
  
          if any(feature_vals):
              assert len(feature_vals) == len(f.get_feature_names())
              for col_vals, name in zip(
                  feature_vals, f.get_feature_names()
              ):
                  frame[name].update(pd.concat(col_vals))
  
          progress_callback(1 / float(self.num_features))
  
      return frame
  
imports: from datetime import datetime
  from functools import partial
  import numpy
  import pandas
  import pandas.api.types
  from featuretools.entityset.relationship import RelationshipPath
  from featuretools.exceptions import UnknownFeature
  from featuretools.feature_base import AggregationFeature, DirectFeature, GroupByTransformFeature, IdentityFeature, TransformFeature
  from featuretools.utils import Trie
  from featuretools.utils.gen_utils import Library, get_relationship_column_id, import_or_none, is_instance
label_desc: Use image node_id 10 for calling the FeatureSetCalculator obj's underlying member method code with example usage: obj._calculate_groupby_features(features, frame, _df_trie, progress_callback) and returns: frame, frame