code: def approximate_features(
      feature_set,
      cutoff_time,
      window,
      entityset,
      training_window=None,
      include_cutoff_time=True,
  ):
      """Given a set of features and cutoff_times to be passed to
      calculate_feature_matrix, calculates approximate values of some features
      to speed up calculations.  Cutoff times are sorted into
      window-sized buckets and the approximate feature values are only calculated
      at one cutoff time for each bucket.
  
  
      ..note:: this only approximates DirectFeatures of AggregationFeatures, on
          the target dataframe. In future versions, it may also be possible to
          approximate these features on other top-level dataframes
  
      Args:
          cutoff_time (pd.DataFrame): specifies what time to calculate
              the features for each instance at. The resulting feature matrix will use data
              up to and including the cutoff_time. A DataFrame with
              'instance_id' and 'time' columns.
  
          window (Timedelta or str): frequency to group instances with similar
              cutoff times by for features with costly calculations. For example,
              if bucket is 24 hours, all instances with cutoff times on the same
              day will use the same calculation for expensive features.
  
          entityset (:class:`.EntitySet`): An already initialized entityset.
  
          feature_set (:class:`.FeatureSet`): The features to be calculated.
  
          training_window (`Timedelta`, optional):
              Window defining how much older than the cutoff time data
              can be to be included when calculating the feature. If None, all older data is used.
  
          include_cutoff_time (bool):
              If True, data at cutoff times are included in feature calculations.
  
      """
      approx_fms_trie = Trie(path_constructor=RelationshipPath)
  
      target_time_colname = "target_time"
      cutoff_time.ww[target_time_colname] = cutoff_time["time"]
      approx_cutoffs = bin_cutoff_times(cutoff_time, window)
      cutoff_df_time_col = "time"
      cutoff_df_instance_col = "instance_id"
      # should this order be by dependencies so that calculate_feature_matrix
      # doesn't skip approximating something?
      for (
          relationship_path,
          approx_feature_names,
      ) in feature_set.approximate_feature_trie:
          if not approx_feature_names:
              continue
  
          (
              cutoffs_with_approx_e_ids,
              new_approx_dataframe_index_col,
          ) = _add_approx_dataframe_index_col(
              entityset,
              feature_set.target_df_name,
              approx_cutoffs.copy(),
              relationship_path,
          )
  
          # Select only columns we care about
          columns_we_want = [
              new_approx_dataframe_index_col,
              cutoff_df_time_col,
              target_time_colname,
          ]
  
          cutoffs_with_approx_e_ids = cutoffs_with_approx_e_ids[
              columns_we_want
          ]
          cutoffs_with_approx_e_ids = (
              cutoffs_with_approx_e_ids.drop_duplicates()
          )
          cutoffs_with_approx_e_ids.dropna(
              subset=[new_approx_dataframe_index_col],
              inplace=True,
          )
  
          approx_features = [
              feature_set.features_by_name[name]
              for name in approx_feature_names
          ]
          if cutoffs_with_approx_e_ids.empty:
              approx_fm = gen_empty_approx_features_df(approx_features)
          else:
              cutoffs_with_approx_e_ids.sort_values(
                  [cutoff_df_time_col, new_approx_dataframe_index_col],
                  inplace=True,
              )
              # CFM assumes specific column names for cutoff_time argument
              rename = {
                  new_approx_dataframe_index_col: cutoff_df_instance_col
              }
              cutoff_time_to_pass = cutoffs_with_approx_e_ids.rename(
                  columns=rename
              )
              cutoff_time_to_pass = cutoff_time_to_pass[
                  [cutoff_df_instance_col, cutoff_df_time_col]
              ]
  
              cutoff_time_to_pass.drop_duplicates(inplace=True)
              approx_fm = calculate_feature_matrix(
                  approx_features,
                  entityset,
                  cutoff_time=cutoff_time_to_pass,
                  training_window=training_window,
                  approximate=None,
                  cutoff_time_in_index=False,
                  chunk_size=cutoff_time_to_pass.shape[0],
                  include_cutoff_time=include_cutoff_time,
              )
  
          approx_fms_trie.get_node(relationship_path).value = approx_fm
  
      return approx_fms_trie
  
imports: import logging
  import math
  import os
  import shutil
  import time
  import warnings
  from datetime import datetime
  import cloudpickle
  import numpy
  import pandas
  from woodwork.logical_types import Age, AgeNullable, Boolean, BooleanNullable, Integer, IntegerNullable
  from featuretools.computational_backends.feature_set import FeatureSet
  from featuretools.computational_backends.feature_set_calculator import FeatureSetCalculator
  from featuretools.computational_backends.utils import _check_cutoff_time_type, _validate_cutoff_time, bin_cutoff_times, create_client_and_cluster, gather_approximate_features, gen_empty_approx_features_df, get_ww_types_from_features, save_csv_decorator
  from featuretools.entityset.relationship import RelationshipPath
  from featuretools.feature_base import AggregationFeature, FeatureBase
  from featuretools.utils import Trie
  from featuretools.utils.gen_utils import Library, import_or_none, import_or_raise, is_instance, make_tqdm_iterator
label_desc: Use image node_id 3 for calling a global function with example usage: approximate_features(feature_set, cutoff_time, window, entityset, training_window, include_cutoff_time) and returns: approx_fms_trie