Advertisement
Guest User

Untitled

a guest
Oct 19th, 2019
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.07 KB | None | 0 0
  1. import numpy as np
  2. from sklearn import datasets
  3. import scipy.stats
  4. import random
  5. import pandas as pd
  6. import matplotlib.pyplot as plt
  7.  
  8. # https://datascience.stackexchange.com/questions/39142/normalize-matrix-in-python-numpy
  9. def scale(X, x_min, x_max):
  10. nom = (X-X.min(axis=0))*(x_max-x_min)
  11. denom = X.max(axis=0) - X.min(axis=0)
  12. denom[denom==0] = 1
  13. return x_min + nom/denom
  14.  
  15.  
  16. class Preprocessor(object):
  17. def __init__(self, **args):
  18. self.__dict__.update(args)
  19. # OPTIONAL TODO
  20.  
  21. self.max = None
  22. self.min = None
  23. self.standard_deviation = None
  24. self.median = []
  25. self.iqr = []
  26. self.dataframe = None
  27. self.transformed_y = None
  28.  
  29. self.noise_quantile= []
  30.  
  31. def fit(self, X, y=None):
  32. '''
  33. Recibe los datos de entrada X y opcionalmente los datos de salida esperados y para preparar los modelos necesarios para
  34. el preprocesado de datos.
  35.  
  36. X Matriz bidimiensional con forma (u,v) donde u es el número de tuplas y v el número de variables
  37. y (opcional) Vector unidimensional con longitud u que contiene las salidas esperadas para cada una de las tuplas de X
  38. No devuelve nada
  39.  
  40. Params:
  41. Median: insertado en tuplas con valores nulos
  42. dataframe: copia de X en Pandas Dataframe. Manipulado por datos
  43. Returns:
  44. None
  45. Observaciones: Este método es llamado por transform dado que es necesario para realizar las operaciones con éxito.
  46. Podría declararse como privado. No se ha hecho por no modificar las bases dadas.
  47. '''
  48. self.max = np.amax(X, axis=0)
  49. self.min = np.amin(X, axis=0)
  50. self.median = np.median(X, axis=0)
  51. self.standard_deviation = np.std(X, axis=0)
  52. self.noise_quantile = np.quantile(X, 0.9, axis=0)
  53.  
  54.  
  55. if X.shape[0] == y.shape[0]:
  56. self.dataframe = pd.DataFrame(X)
  57. self.dataframe['target'] = y
  58. self.transformed_y = pd.DataFrame(y)
  59.  
  60. else:
  61. print("ERROR: Unmatching target and data sizes")
  62. exit(1)
  63.  
  64.  
  65.  
  66.  
  67. def transform(self, X, y=None):
  68. '''
  69. Recibe los datos de entrada X y opcionalmente los datos de salida esperados y para preprocesar los datos de entrada.
  70.  
  71. X Matriz bidimiensional con forma (u,v) donde u es el número de tuplas y v el número de variables
  72. y (opcional) Vector unidimensional con longitud u que contiene las salidas esperadas para cada una de las tuplas de X
  73. Devuelve el conjunto de datos X transformado
  74.  
  75. Operaciones:
  76. Limpieza de datos: Inserción de la mediana en los valores nulos. Boston carece de los mismos pero es necesario para casos generales.
  77. Reducción del dataset: Matriz de correlación para eliminar las tuplas irrelevantes. En este caso concreto obtenemos una relación
  78. razonable usando 2 columnas en lugar de 13.
  79. Idea de usar dataframe.corr: https://towardsdatascience.com/linear-regression-on-boston-housing-dataset-f409b7e4a155
  80. Returns:
  81. cor_dataset: X reducido y transformado a pd.Dataset
  82. transformed_y: y cambiado a tipo pd.Dataset
  83. Observaciones:
  84. No se han normalizado los datos. Comentado se presenta un esquema de la implementación pensada para hacerlo que hubiera sido
  85. normalización robusta. Sin embargo su apliación empeora considerablemente el resultado.
  86. '''
  87.  
  88. self.fit(X,y)
  89.  
  90.  
  91.  
  92. #Eliminar tuplas null usando dataframes
  93. if self.dataframe.isnull().sum().sum():
  94. is_na_dataframe = pd.isna(self.dataframe)
  95. for row in range(self.dataframe.shape[0]):
  96. for column in range(self.dataframe.shape[1]):
  97. if is_na_dataframe[row,column] == True:
  98. self.dataframe[row,column] = self.median[column]
  99.  
  100.  
  101. self.dataframe = self.dataframe.to_numpy()
  102. # eliminamos el ruido
  103.  
  104. for row in self.dataframe:
  105. temp = row[1:] - self.noise_quantile
  106. print("lo que devuelve any")
  107. print(temp.any() <= 0)
  108. print(temp)
  109. if temp.any() <= 0:
  110. print("borramos la row")
  111. print(row)
  112. self.dataframe = np.delete(self.dataframe, row, 0)
  113.  
  114.  
  115.  
  116. # normalizamos los datos
  117. self.dataframe = scale(self.dataframe[:,1:], self.min, self.max)
  118.  
  119. '''
  120. # Normalización de los datos mediante normalización robusta
  121. self.median = np.median(cor_dataset,axis=1)
  122. self.iqr = scipy.stats.iqr(cor_dataset, axis=1, rng=(25, 75))
  123.  
  124. print(self.iqr.shape)
  125. print(self.median.shape)
  126. print(cor_dataset.shape)
  127. for row in range(cor_dataset.shape[0]):
  128. for column in range(cor_dataset.shape[1]):
  129. if self.iqr[row] == 0:
  130. cor_dataset.iloc[row,column] = None
  131. continue
  132. cor_dataset.iloc[row,column] = (cor_dataset.iloc[row,column] - self.median[row])/self.iqr[row]
  133.  
  134. #Creamos una nueva media para valores normalizados
  135. mediana_normalizada = np.median(cor_dataset,axis=0)
  136.  
  137. # Si algún dato fuera problemático por el valor intercuartílico lo rellenamos con la media devalores normalizados
  138. if self.dataframe.isnull().sum().sum() != 0:
  139. is_na_dataframe = pd.isna(self.cor_dataset)
  140. for row in range(self.dataframe.shape[0]):
  141. for column in range(self.dataframe.shape[1]):
  142. if is_na_dataframe[row, column] == True:
  143. cor_dataset.iloc[row, column] = mediana_normalizada
  144.  
  145. '''
  146.  
  147.  
  148. #return cor_dataset,self.transformed_y
  149. return self.dataframe, self.transformed_y
  150.  
  151.  
  152.  
  153.  
  154.  
  155. class GradientDescent(object):
  156. def __init__(self, alfa, **args):
  157. self.alfa = alfa
  158. self.__dict__.update(args)
  159. # OPTIONAL TODO
  160. self.thetas = None
  161.  
  162. def fit(self, X, y):
  163. '''
  164. Recibe los datos de entrada X y los datos de salida esperados y para entrenar el modelo de descenso de gradiente.
  165.  
  166. X Matriz bidimiensional con forma (u,v) donde u es el número de tuplas y v el número de variables
  167. y Vector unidimensional con longitud u que contiene las salidas esperadas para cada una de las tuplas de X
  168. No devuelve nada
  169.  
  170. Método de entrenamiento de la regresión. Usa el algoritmo de la diapositiva 8 tema 3
  171.  
  172. params:
  173. thetas: Parámetro a optimizar. Es actualizado con cada vuelta del bucle y usado para calcular el mse
  174. returns:
  175. None
  176. cambios: el valor de theta.
  177.  
  178. Observaciones: El código comprueba mínimos locales. Podría usarse memoria para guardar mínimos y recorrer el
  179. espectro completo de alpha pero mirando el coste de computación y error obtenido esta implementación se ha considerado
  180. óptima.
  181. '''
  182. # TODO
  183. self.thetas = np.ones(X.shape[1])
  184. #TODO
  185.  
  186. print("Untrained mse: ",self.mse(X,y))
  187.  
  188. while True:
  189. old_mse = self.mse(X, y)
  190. self.fit_step(X, y)
  191. trained_mse = self.mse(X, y)
  192. if trained_mse > old_mse :
  193. break
  194. print("New mse: " , trained_mse)
  195.  
  196. def fit_step(self, X, y):
  197. '''
  198. Recibe los datos de entrada X y los datos de salida esperados y para realizar una actualización en batch
  199. de los valores thetas
  200.  
  201. X Matriz bidimiensional con forma (u,v) donde u es el número de tuplas y v el número de variables
  202. y Vector unidimensional con longitud u que contiene las salidas esperadas para cada una de las tuplas de X
  203. No devuelve nada
  204.  
  205. Llamado únicamente por fit() este método es quien hace los cambios reales sobre thetas.
  206.  
  207. Params:
  208. hypothesis: llamada al método predict() para obtener el resultado obtenido con las thetas actuales.
  209. summation: equivalente al sumatorio de la fórmula de la regresión (pg 17 tema 3)
  210. y: Soluciones reales a contrastar con la hipótesis
  211. theta: solución a la fórmula
  212.  
  213. Returns: N/A
  214.  
  215. Cambios:
  216. Actualiza el valor de Theta
  217.  
  218. '''
  219. # TODO
  220.  
  221. hypothesis = self.predict(X)
  222.  
  223. for column in range(X.shape[1]):
  224. summation = 0
  225. theta = 0
  226. for row in (range(X.shape[0])):
  227. summation += ((hypothesis[row] - y.iloc[row].item()) * X.iloc[row,column])
  228. theta = self.thetas[column] - ((self.alfa / X.shape[0]) * summation)
  229. # Guardamos en nuestro array de thetas el resultado obtenido para cada iteración de i
  230. self.thetas[column] = theta
  231.  
  232.  
  233. def predict(self, X):
  234. '''
  235. Recibe los datos de entrada X para estimar la salida estimada y_ segun el modelo entrenado
  236.  
  237. X Matriz bidimiensional con forma (u,v) donde u es el número de tuplas y v el número de variables
  238. y Vector unidimensional con longitud u que contiene las salidas esperadas para cada una de las tuplas de X
  239. Devuelve un vector unidimensional y_ de longitud u el cual contiene el conjunto de salidas estimadas para X
  240.  
  241. Transponemos thetas (n,) para poder multiplicarlo por X
  242. '''
  243. # TODO
  244. #Multiplicamos cada X por su índice
  245. return X.dot(self.thetas.T)
  246.  
  247. def mse(self, X, y):
  248. '''
  249. Recibe los datos de entrada X y los datos de salida esperados y para obtener el error cuadratico medio
  250. del modelo entrenado
  251.  
  252. X Matriz bidimiensional con forma (u,v) donde u es el número de tuplas y v el número de variables
  253. y Vector unidimensional con longitud u que contiene las salidas esperadas para cada una de las tuplas de X
  254. Devuelve el error cuadratico medio (float)
  255.  
  256. Aplicada fórmula de MSE del tema 2 diapositiva 3
  257.  
  258. Params:
  259. y_pred = hipótesis obtenida por la regresión
  260. mse = error cuadrático medio a calcular
  261. m = número de elementos en X (filas)
  262.  
  263. Returns:
  264. mse/m = error cuadrático medio
  265. '''
  266.  
  267. # TODO
  268. y_pred = self.predict(X)
  269.  
  270. mse = 0
  271. m = X.shape[0]
  272. i = 0
  273.  
  274. for prediction in y_pred:
  275. mse += ((prediction - y.iloc[i].item()) ** 2)
  276. i += 1
  277.  
  278. return mse / m
  279.  
  280.  
  281. if __name__ == "__main__":
  282. np.random.seed(1)
  283.  
  284. from sklearn import datasets
  285. from sklearn.preprocessing import MinMaxScaler
  286.  
  287. np.random.seed(1)
  288. X, y = datasets.load_diabetes(return_X_y=True)
  289.  
  290. preprocesado = Preprocessor()
  291. X,y = preprocesado.transform(X,y)
  292. print("cuantil")
  293. print(X.shape)
  294.  
  295. plt.plot(X[1,])
  296. plt.show()
  297.  
  298. '''
  299. X, y = datasets.load_boston(return_X_y=True)
  300.  
  301.  
  302. preprocessor = Preprocessor()
  303.  
  304. # Dividimos el número total de tuplas en un 70%
  305. # Podríamos considerar repartir las tuplas de manera aleatoria para mejorar eficiencia
  306.  
  307.  
  308. # Preprocesado de datos (utilizar el modelo de preprocesado creado)
  309. # TODO
  310. X,y = preprocessor.transform(X,y)
  311. num_of_rows = int((X.shape[0]) * 0.8)
  312.  
  313. X_train = X.iloc[:num_of_rows] # indexes rows for training data
  314. X_test = X.iloc[num_of_rows:] # indexes rows for test data
  315. y_train = y.iloc[:num_of_rows]
  316. y_test = y.iloc[num_of_rows:]
  317.  
  318. # Creación y entrenamiento del modelo de descenso de gradiente
  319. # TODO
  320. # Error mínimo conseguido 25.05 con este valor de alfa. Si es mayor salta enormemente los valores óptimos
  321. GD = GradientDescent(0.01)
  322. GD.fit(X_train, y_train)
  323.  
  324. #Resultado final
  325. print("MSE for test_subset: ")
  326. print(GD.mse(X_test, y_test))
  327. '''
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement