code: def LDA_base(x, labels):
      
      classes = np.array(tuple(set(labels)))
      cols = x.shape[1]
      # mean values for every class
      means = np.zeros((len(classes), cols))
      for i, cl in enumerate(classes):
          means[i] = np.mean(x[labels==cl], axis=0)
      # scatter matrices
      scatter_within = np.zeros((cols, cols))
      for cl, mean in zip(classes, means):
          scatter_class = np.zeros((cols, cols))
          for row in x[labels == cl]:
              dif = row - mean
              scatter_class += np.dot(dif.reshape(cols, 1), dif.reshape(1, cols))
          scatter_within += scatter_class
      total_mean = np.mean(x, axis=0)
      scatter_between = np.zeros((cols, cols))
      for cl, mean in zip(classes, means):
          dif = mean - total_mean
          dif_product = np.dot(dif.reshape(cols, 1), dif.reshape(1, cols))
          scatter_between += x[labels == cl, :].shape[0] * dif_product
      # eigenvalues and eigenvectors from scatter matrices
      scatter_product = np.dot(np.linalg.inv(scatter_within), scatter_between)
      eigen_values, eigen_vectors = np.linalg.eig(scatter_product)
      return eigen_values, eigen_vectors
docs: Base function used for Linear Discriminant Analysis.
  
      **Args:**
  
      * `x` : input matrix (2d array), every row represents new sample
  
      * `labels` : list of labels (iterable), every item should be label for \
        sample with corresponding index
  
      **Returns:**
      
      * `eigenvalues`, `eigenvectors` : eigenvalues and eigenvectors \
        from LDA analysis