code: def estimate_mutual_information(x, y):
      
      xy = np.concatenate((x, y), axis=1)
      epsilon = _calculate_epsilon(xy)
      h_x = estimate_entropy(x, epsilon)
      h_y = estimate_entropy(y, epsilon)
      h_xy = estimate_entropy(xy, epsilon)
      return max(0, h_x + h_y - h_xy)
docs: Estimate the mutual information of two datasets.
  
      Mutual information is a measure of dependence between
      two datasets and is calculated as:
  
          $I(x;y) = H(x) + H(y) - H(x,y)$
  
      Where H(x) is the Shannon entropy of x. For continuous datasets,
      adapts the Kraskov Estimator [1] for mutual information.
  
      Args:
          x (array-like): An array with shape (n_samples, n_features_x)
          y (array-like): An array with shape (n_samples, n_features_y)
  
      Returns:
          float: A floating point number representing the mutual
              information of x and y. This calculation is *exact*
              for entirely discrete datasets and *approximate* if
              there are continuous columns present.
  
      References:
  
      .. [1] A. Kraskov, H. Stogbauer and P. Grassberger, "Estimating mutual
        information". Phys. Rev. E 69, 2004.