<jupyter_start><jupyter_text>Práctica Machine Learning mIA-X Clasificación de patrones técnicos  Primera IteracionEn esta version se requiere generar un modelo que clasifique un patron de doble suelo y mostrar losresultados que muestren que dicho modelo es mejor que la aleatoriedad. Opcionalmente el alumno puedeelegir un patron tecnico distinto que sea de su interes.  Importamos librerias<jupyter_code>import numpy as np
import pandas as pd
import pickle

import matplotlib.pyplot as plt

import sklearn<jupyter_output><empty_output><jupyter_text>Cargamos la serie del IBEX<jupyter_code>with open('benchmark_data.pkl', 'rb') as handle:
    bm = pickle.load(handle)
ibex = bm['ibex']
ibex.head()<jupyter_output><empty_output><jupyter_text>Lectura de ejemplos<jupyter_code>ejemplos = pd.read_csv('ejemplos_doble_suelo.csv')
ejemplos.columns = ['fecha','etiqueta']
ejemplos<jupyter_output><empty_output><jupyter_text>Sacamos posición en la que se encuentra la fecha en el índice<jupyter_code>idx = ibex.index.get_loc(ejemplos.fecha.iloc[20])
idx
ibex.iloc[idx]<jupyter_output><empty_output><jupyter_text>Con el índice numérico reconstruimos la ventana<jupyter_code>window=30
windata = ibex.iloc[idx:idx+window]
windata.head()
windata.shape<jupyter_output><empty_output><jupyter_text>Análisis exploratorio<jupyter_code>ejemplos.describe()
ejemplos['etiqueta'].hist()<jupyter_output><empty_output><jupyter_text>Tipología de las variables<jupyter_code>ejemplos.dtypes<jupyter_output><empty_output><jupyter_text>Comprobamos si hay NAs<jupyter_code>ejemplos.isna().any()<jupyter_output><empty_output><jupyter_text>Ingeniería de Características 1. Retornos simples de la ventana<jupyter_code>def window_simple_returns(data):
    r = data.close.iloc[-1]/data.close.iloc[0] - 1
    return r 
window_simple_returns(windata)<jupyter_output><empty_output><jupyter_text>2. Retornos logaritmicos de la ventana<jupyter_code>def window_log_returns(data):
    r = np.log(data.close.iloc[-1])/np.log(data.close.iloc[0])
    return r 
window_log_returns(windata)<jupyter_output><empty_output><jupyter_text>3. Numero de días que pasan entre el máximo y el mínimo de la ventana<jupyter_code>def days_between_max_min(data):
    
    maximum = data.high.max()
    minimum = data.low.min()
    days_between_max_min_index = abs(data[data.high == maximum].index - data[data.low == minimum].index)
    days_between_max_min = (days_between_max_min_index / np.timedelta64(1, 'D')).astype(int).tolist()[0]
    return days_between_max_min
days_between_max_min(windata)<jupyter_output><empty_output><jupyter_text>4. Si ocurre primero el máximo o el mínimo<jupyter_code>def first_max_min(data):
    
    maximum = data.high.max()
    minimum = data.low.min()
    maximum_date = data[data.high == maximum].index
    minimum_date = data[data.low == minimum].index
    if maximum_date < minimum_date:
        first_max = 1
    else:
        first_max = 0
    
    return first_max
first_max_min(windata)<jupyter_output><empty_output><jupyter_text>5. Numero de veces en la ventana que se llega cerca del mínimo<jupyter_code>def treshold_min(data):
    minimum = data.low.min()
    th = 1.02
    df = data[data['low'] < th*minimum]
    df.shape[0]
             
    n = df.shape[0]*100/100
    
    return n
treshold_min(windata)<jupyter_output><empty_output><jupyter_text>6. Numero de veces en la ventana que se llega cerca del máximo<jupyter_code>def treshold_max(data):
    maximum = data.high.max()
    th = 0.99
    df= data[data['high'] > th*maximum]
    df.shape[0]
             
    n = df.shape[0]*100/100
    
    return n
treshold_max(windata)<jupyter_output><empty_output><jupyter_text>Preprocesamiento de los datos Inclusión de features en ejemplos<jupyter_code>ejemplos['feature1'] = np.zeros(len(ejemplos))
ejemplos['feature2'] = np.zeros(len(ejemplos))
ejemplos['feature3'] = np.zeros(len(ejemplos))
ejemplos['feature4'] = np.zeros(len(ejemplos))
ejemplos['feature5'] = np.zeros(len(ejemplos))
ejemplos['feature6'] = np.zeros(len(ejemplos))
ejemplos.head()
for i in range(len(ejemplos)):
    
    idx = ibex.index.get_loc(ejemplos.fecha.iloc[i])
    windata = ibex.iloc[idx:idx+window]
    
    ejemplos.feature1[i] = window_simple_returns(windata)
    ejemplos.feature2[i] = window_log_returns(windata)
    ejemplos.feature3[i] = days_between_max_min(windata)
    ejemplos.feature4[i] = first_max_min(windata)
    ejemplos.feature5[i] = treshold_min(windata)
    ejemplos.feature6[i] = treshold_max(windata)
ejemplos.head()<jupyter_output><empty_output><jupyter_text>Preprocesamos los datos para conseguir un conjunto de entrenamiento de calidad<jupyter_code>def preprocesamiento(df):
  
    # Eliminar columnas con NAs
    df = df.dropna()
    
    # Cambiar orden de columnas
    df = df[['fecha', 'feature1', 'feature2', 'feature3','feature4','feature5','feature6', 'etiqueta']]
    
    # Eliminar características basadas en texto
    features_to_drop = ["fecha"]
    df = df.drop(features_to_drop, axis=1)
    

    return df
ejemplos = preprocesamiento(ejemplos)
ejemplos.head()<jupyter_output><empty_output><jupyter_text>Análisis exploratorio tras la inclusión de las características Análisis estadístico de las variables<jupyter_code>ejemplos.describe()<jupyter_output><empty_output><jupyter_text>Tipología de las variables<jupyter_code>ejemplos.dtypes<jupyter_output><empty_output><jupyter_text>Comprobamos si hay NAs<jupyter_code>ejemplos.isna().any()<jupyter_output><empty_output><jupyter_text>Estandarización de variablesEstandarizar las variables siempre es una buena practica.<jupyter_code>from sklearn.preprocessing import StandardScaler<jupyter_output><empty_output><jupyter_text>Separamos nuestra variable objetivo del conjunto de datos para realizar la estandarización<jupyter_code>features = ejemplos.loc[:, ejemplos.columns !='etiqueta']
target = ejemplos.etiqueta<jupyter_output><empty_output><jupyter_text>Estandarizamos los datos con una media = 0  y desviación típica = 1<jupyter_code>scaler = StandardScaler()
features[['feature1', 'feature2','feature3','feature4','feature5','feature6']] = scaler.fit_transform(features[['feature1', 'feature2','feature3','feature4','feature5','feature6']])
features.describe().round(decimals=3)
target.value_counts()
target.value_counts()/target.shape[0]<jupyter_output><empty_output><jupyter_text>Árbol de decisiónUtilizaremos un árbol de decisión para realizar la clasificación de los patrones de doble suelo  Separación del conjunto en train/test<jupyter_code>from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(features.values,
                                                    target.values,
                                                    test_size=0.3,
                                                    stratify=target)<jupyter_output><empty_output><jupyter_text>Inicializamos el modelo<jupyter_code>from sklearn.tree import DecisionTreeClassifier
Tree = DecisionTreeClassifier(max_depth=5)<jupyter_output><empty_output><jupyter_text>Entrenamos el modelo<jupyter_code>Tree = Tree.fit(x_train, y_train)
print(Tree.classes_)<jupyter_output>[0. 1.]<jupyter_text>Evaluamos el modelo<jupyter_code>from sklearn.metrics import confusion_matrix, accuracy_score, auc, roc_auc_score, roc_curve<jupyter_output><empty_output><jupyter_text>Calculamos las predicciones<jupyter_code>test_pred = Tree.predict(x_test)
test_pred.shape<jupyter_output><empty_output><jupyter_text>- Matriz de confusion<jupyter_code>def matriz_confusion(y_real, y_pred):
    real = pd.Series(y_real, name='Real')
    predicted = pd.Series(y_pred, name="Predicted")
    
    return pd.crosstab(predicted, real)
matriz_confusion(y_test, test_pred)<jupyter_output><empty_output><jupyter_text>- Accuracy , AUCROC , curva ROC Accuracy<jupyter_code>accuracy_score(y_test, test_pred)<jupyter_output><empty_output><jupyter_text>La clase de interés en nuestro problema es la etiqueta '1.0', por lo que nos interesa calcular los ratios en referencia a dicha clase.La predicción probabilística corresponde a la posición 1<jupyter_code>train_pred_proba = Tree.predict_proba(x_train)
train_posprob = train_pred_proba[:,1]
test_pred_proba = Tree.predict_proba(x_test)
test_posprob = test_pred_proba[:,1]<jupyter_output><empty_output><jupyter_text>Área de la curva ROC<jupyter_code>roc_auc_score(y_test, test_posprob)<jupyter_output><empty_output><jupyter_text>Curva ROC<jupyter_code>train_fpr, train_tpr, train_thr = roc_curve(y_train, train_posprob)
test_fpr, test_tpr, test_thr = roc_curve(y_test, test_posprob)
fig, ax = plt.subplots(figsize=(5,5))
plt.plot(train_fpr, train_tpr, color='r', label='train')
plt.plot(test_fpr, test_tpr, color='g', label='test')

plt.plot([0,1],[0,1])
plt.xlim([0.0, 1.0])
plt.ylim([0.0,1.0])
plt.legend(loc='lower right')<jupyter_output><empty_output><jupyter_text>___<jupyter_code>auc(test_fpr, test_tpr)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11046381357831056, 'fraction_numerical': 0.011427291059825229, 'mean_word_length': 6.199193548387097, 'pattern_counts': {'":': 0, '<': 134, '<?xml version=': 0, '>': 133, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '33', 'dir': 'jupyter-structured-clean-dedup', 'id': '178612', 'license': 'MIT', 'n_tokens_mistral': 3373, 'n_tokens_neox': 3329, 'n_words': 554, 'path': 'primera_iteracion.ipynb', 'repo_name': 'luisalro/miax-TechnicalAnalysisPatterns_Detection', 'size': '8926'}