code: def polynomial_features(X, degree):
      n_samples, n_features = np.shape(X)
  
      def index_combinations():
          combs = [
              combinations_with_replacement(range(n_features), i)
              for i in range(0, degree + 1)
          ]
          flat_combs = [item for sublist in combs for item in sublist]
          return flat_combs
  
      combinations = index_combinations()
      n_output_features = len(combinations)
      X_new = np.empty((n_samples, n_output_features))
  
      for i, index_combs in enumerate(combinations):
          X_new[:, i] = np.prod(X[:, index_combs], axis=1)
  
      return X_new
  
file_path: ML-From-Scratch/mlfromscratch/utils/data_manipulation.py
imports: from __future__ import division
  from itertools import combinations_with_replacement
  import numpy
  import math
  import sys
label_desc: Use image node_id 4 for calling a global function with example usage: polynomial_features(X, degree) and returns: X_new, flat_combs