code: ########## 6.6.1. O lema de Johnson-Lindenstrauss ##########
  
  
  
      # O principal resultado teórico por trás da eficiência da projeção aleatória é o lema de Johnson-Lindenstrauss (citando a Wikipedia):
  
      # Em matemática, o lema de Johnson-Lindenstrauss é um resultado sobre embeddings de baixa distorção de pontos de alta dimensão em espaço euclidiano de baixa dimensão. O lema afirma que um pequeno conjunto de pontos em um espaço de alta dimensão pode ser incorporado em um espaço de dimensão muito menor de tal forma que as distâncias entre os pontos sejam praticamente preservadas. O mapa usado para a incorporação é pelo menos Lipschitz, e pode até ser considerado uma projeção ortogonal.
  
      # Conhecendo apenas o número de amostras, o johnson_lindenstrauss_min_dim estima conservadoramente o tamanho mínimo do subespaço aleatório para garantir uma distorção limitada introduzida pela projeção aleatória: 
  
  
  from sklearn.random_projection import johnson_lindenstrauss_min_dim
  johnson_lindenstrauss_min_dim(n_samples=1e6, eps=0.5)
  
  johnson_lindenstrauss_min_dim(n_samples=1e6, eps=[0.5, 0.1, 0.01])
  
  johnson_lindenstrauss_min_dim(n_samples=[1e4, 1e5, 1e6], eps=0.1)
  
  
  
          # https://scikit-learn.org/stable/auto_examples/miscellaneous/plot_johnson_lindenstrauss_bound.html 
  
  
  
      ## Exemplos:
  
      ## See The Johnson-Lindenstrauss bound for embedding with random projections for a theoretical explication on the Johnson-Lindenstrauss lemma and an empirical validation using sparse random matrices. (https://scikit-learn.org/stable/auto_examples/miscellaneous/plot_johnson_lindenstrauss_bound.html#sphx-glr-auto-examples-miscellaneous-plot-johnson-lindenstrauss-bound-py)
  
  
  
  
  
  
      ## Referências:
  
      ## Sanjoy Dasgupta and Anupam Gupta, 1999. An elementary proof of the Johnson-Lindenstrauss Lemma. ( http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.39.3334&rep=rep1&type=pdf) ########## 6.1.2. Transformando alvo em regressão ##########
  
  
      # TransformedTargetRegressor transforma os destinos y antes de ajustar um modelo de regressão. As previsões são mapeadas de volta ao espaço original por meio de uma transformação inversa. Toma como argumento o regressor que será usado para previsão e o transformador que será aplicado à variável alvo: 
  
  import numpy as np
  from sklearn.datasets import fetch_california_housing
  from sklearn.compose import TransformedTargetRegressor
  from sklearn.preprocessing import QuantileTransformer
  from sklearn.linear_model import LinearRegression
  from sklearn.model_selection import train_test_split
  X, y = fetch_california_housing(return_X_y=True)
  X, y = X[:2000, :], y[:2000]  # selecione um subconjunto de dados 
  transformer = QuantileTransformer(output_distribution='normal')
  regressor = LinearRegression()
  regr = TransformedTargetRegressor(regressor=regressor,
                                    transformer=transformer)
  X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
  regr.fit(X_train, y_train)
  print('R2 score: {0:.2f}'.format(regr.score(X_test, y_test)))
  raw_target_regr = LinearRegression().fit(X_train, y_train)
  print('R2 score: {0:.2f}'.format(raw_target_regr.score(X_test, y_test)))
  
  
      # Para transformações simples, ao invés de um objeto Transformer, pode-se passar um par de funções, definindo a transformação e seu mapeamento inverso: 
  
  def func(x):
      return np.log(x)
  def inverse_func(x):
      return np.exp(x)
  
      # Posteriormente, o objeto é criado como: 
  
  regr = TransformedTargetRegressor(regressor=regressor,
                                    func=func,
                                    inverse_func=inverse_func)
  regr.fit(X_train, y_train)
  TransformedTargetRegressor(...)
  print('R2 score: {0:.2f}'.format(regr.score(X_test, y_test)))
  
  
      # Por padrão, as funções fornecidas são verificadas em cada ajuste para serem o inverso uma da outra. No entanto, é possível contornar essa verificação definindo check_inverse como False: 
  
  def inverse_func(x):
      return x
  regr = TransformedTargetRegressor(regressor=regressor,
                                    func=func,
                                    inverse_func=inverse_func,
                                    check_inverse=False)
  regr.fit(X_train, y_train)
  TransformedTargetRegressor(...)
  print('R2 score: {0:.2f}'.format(regr.score(X_test, y_test)))
  
  
      # Nota: A transformação pode ser acionada configurando transformador ou o par de funções func e inverse_func. No entanto, definir ambas as opções gerará um erro. 
  
  
  
      ## Exemplos:
  
      ## https://scikit-learn.org/stable/auto_examples/compose/plot_transformed_target.html#sphx-glr-auto-examples-compose-plot-transformed-target-py
apis: sklearn.random_projection.johnson_lindenstrauss_min_dim
apis: sklearn.compose.TransformedTargetRegressor sklearn.preprocessing.QuantileTransformer sklearn.linear_model.LinearRegression numpy.exp numpy.log sklearn.model_selection.train_test_split sklearn.datasets.fetch_california_housing