code: def _SMOTE(T, N, k, h = 1.0):
      
      n_minority_samples, n_features = T.shape
  
      if N < 100:
          #create synthetic samples only for a subset of T.
          #TODO: select random minortiy samples
          N = 100
          pass
  
      if (N % 100) != 0:
          raise ValueError("N must be < 100 or multiple of 100")
  
      N = N/100
      n_synthetic_samples = N * n_minority_samples
      S = np.zeros(shape=(n_synthetic_samples, n_features))
  
      #Learn nearest neighbours
      neigh = NearestNeighbors(n_neighbors = k)
      neigh.fit(T)
  
      #Calculate synthetic samples
      for i in range(n_minority_samples):
          nn = neigh.kneighbors(T[i], return_distance=False)
          for n in range(int(N)):
              nn_index = choice(nn[0])
              #NOTE: nn includes T[i], we don't want to select it
              while nn_index == i:
                  nn_index = choice(nn[0])
  
              dif = T[nn_index] - T[i]
              gap = np.random.uniform(low = 0.0, high = h)
              S[n + i * N, :] = T[i,:] + gap * dif[:]
  
      return S
docs: Returns (N/100) * n_minority_samples synthetic minority samples.
  
      Parameters
      ----------
      T : array-like, shape = [n_minority_samples, n_features]
          Holds the minority samples
      N : percetange of new synthetic samples:
          n_synthetic_samples = N/100 * n_minority_samples. Can be < 100.
      k : int. Number of nearest neighbours.
  
      Returns
      -------
      S : Synthetic samples. array,
          shape = [(N/100) * n_minority_samples, n_features].