{"cells":[{"metadata":{"_uuid":"e154a47bf09b8770980486e87786317a1b3038e1"},"cell_type":"markdown","source":"# TL; DR\n\nJust adding some small improvements to the original kernel. Using a 5-fold instead of a single model, also a simple threshold search instead of using a flat value.  "},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport pyarrow.parquet as pq\nimport os\nimport numpy as np\nfrom keras.layers import *\nfrom keras.models import Model\nfrom tqdm import tqdm\nfrom sklearn.model_selection import train_test_split\nfrom keras.callbacks import ModelCheckpoint\nfrom keras import backend as K\nfrom keras import optimizers\nfrom sklearn.model_selection import GridSearchCV, StratifiedKFold\n\nfrom keras.callbacks import *\nfrom tqdm import tqdm","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6e6379386e44afc69bee8895a52da22199e888fb"},"cell_type":"code","source":"N_SPLITS = 5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c3340ee96becb5ca8f075d9c44b7df383ddba5ee"},"cell_type":"code","source":"def matthews_correlation(y_true, y_pred):\n    '''Calculates the Matthews correlation coefficient measure for quality\n    of binary classification problems.\n    '''\n    y_pred_pos = K.round(K.clip(y_pred, 0, 1))\n    y_pred_neg = 1 - y_pred_pos\n\n    y_pos = K.round(K.clip(y_true, 0, 1))\n    y_neg = 1 - y_pos\n\n    tp = K.sum(y_pos * y_pred_pos)\n    tn = K.sum(y_neg * y_pred_neg)\n\n    fp = K.sum(y_neg * y_pred_pos)\n    fn = K.sum(y_pos * y_pred_neg)\n\n    numerator = (tp * tn - fp * fn)\n    denominator = K.sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn))\n\n    return numerator / (denominator + K.epsilon())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"eda7ea366117d1ce8e5fce69e5bba333821d8b48"},"cell_type":"code","source":"# https://www.kaggle.com/suicaokhoailang/lstm-attention-baseline-0-652-lb\n\nclass Attention(Layer):\n    def __init__(self, step_dim,\n                 W_regularizer=None, b_regularizer=None,\n                 W_constraint=None, b_constraint=None,\n                 bias=True, **kwargs):\n        self.supports_masking = True\n        self.init = initializers.get('glorot_uniform')\n\n        self.W_regularizer = regularizers.get(W_regularizer)\n        self.b_regularizer = regularizers.get(b_regularizer)\n\n        self.W_constraint = constraints.get(W_constraint)\n        self.b_constraint = constraints.get(b_constraint)\n\n        self.bias = bias\n        self.step_dim = step_dim\n        self.features_dim = 0\n        super(Attention, self).__init__(**kwargs)\n\n    def build(self, input_shape):\n        assert len(input_shape) == 3\n\n        self.W = self.add_weight((input_shape[-1],),\n                                 initializer=self.init,\n                                 name='{}_W'.format(self.name),\n                                 regularizer=self.W_regularizer,\n                                 constraint=self.W_constraint)\n        self.features_dim = input_shape[-1]\n\n        if self.bias:\n            self.b = self.add_weight((input_shape[1],),\n                                     initializer='zero',\n                                     name='{}_b'.format(self.name),\n                                     regularizer=self.b_regularizer,\n                                     constraint=self.b_constraint)\n        else:\n            self.b = None\n\n        self.built = True\n\n    def compute_mask(self, input, input_mask=None):\n        return None\n\n    def call(self, x, mask=None):\n        features_dim = self.features_dim\n        step_dim = self.step_dim\n\n        eij = K.reshape(K.dot(K.reshape(x, (-1, features_dim)),\n                        K.reshape(self.W, (features_dim, 1))), (-1, step_dim))\n\n        if self.bias:\n            eij += self.b\n\n        eij = K.tanh(eij)\n\n        a = K.exp(eij)\n\n        if mask is not None:\n            a *= K.cast(mask, K.floatx())\n\n        a /= K.cast(K.sum(a, axis=1, keepdims=True) + K.epsilon(), K.floatx())\n\n        a = K.expand_dims(a)\n        weighted_input = x * a\n        return K.sum(weighted_input, axis=1)\n\n    def compute_output_shape(self, input_shape):\n        return input_shape[0],  self.features_dim","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"df_train = pd.read_csv('../input/metadata_train.csv')\ndf_train = df_train.set_index(['id_measurement', 'phase'])\ndf_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"26df6c7fbfecd537404866faec13d1238ae3ebc6"},"cell_type":"code","source":"max_num = 127\nmin_num = -128","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7b0717b14bcfcba1f48d33c8161ae51c778687af"},"cell_type":"code","source":"def min_max_transf(ts, min_data, max_data, range_needed=(-1,1)):\n    if min_data < 0:\n        ts_std = (ts + abs(min_data)) / (max_data + abs(min_data))\n    else:\n        ts_std = (ts - min_data) / (max_data - min_data)\n    if range_needed[0] < 0:    \n        return ts_std * (range_needed[1] + abs(range_needed[0])) + range_needed[0]\n    else:\n        return ts_std * (range_needed[1] - range_needed[0]) + range_needed[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c6137bbbe75c3a1509a5f98e08805dbbd492aa37"},"cell_type":"code","source":"def transform_ts(ts, n_dim=160, min_max=(-1,1)):\n    ts_std = min_max_transf(ts, min_data=min_num, max_data=max_num)\n    sample_size = 800000\n    bucket_size = int(sample_size / n_dim)\n    new_ts = []\n    for i in range(0, sample_size, bucket_size):\n        ts_range = ts_std[i:i + bucket_size]\n        mean = ts_range.mean()\n        std = ts_range.std()\n        std_top = mean + std\n        std_bot = mean - std\n        percentil_calc = np.percentile(ts_range, [0, 1, 25, 50, 75, 99, 100])\n        max_range = percentil_calc[-1] - percentil_calc[0]\n        covar = std / mean\n        asymmetry = mean - percentil_calc[4]\n        new_ts.append(np.concatenate([np.asarray([mean, std_top, std_bot, max_range, covar, asymmetry]),percentil_calc]))\n    return np.asarray(new_ts)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7460e718a605803f1d9e4fbec61750a0deb02a47"},"cell_type":"code","source":"def prep_data(start, end):\n    #praq_train = pq.read_pandas('../input/train.parquet').to_pandas()\n    praq_train = pq.read_pandas('../input/train.parquet', columns=[str(i) for i in range(start, end)]).to_pandas()\n    X = []\n    y = []\n    #for id_measurement in tqdm(df_train.index.levels[0].unique()):\n    for id_measurement in tqdm(df_train.index.levels[0].unique()[int(start/3):int(end/3)]):\n        X_signal = []\n        for phase in [0,1,2]:\n            signal_id, target = df_train.loc[id_measurement].loc[phase]\n            if phase == 0:\n                y.append(target)\n            X_signal.append(transform_ts(praq_train[str(signal_id)]))\n        X_signal = np.concatenate(X_signal, axis=1)\n        X.append(X_signal)\n    X = np.asarray(X)\n    y = np.asarray(y)\n    return X, y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"52dc826ab9ee1dd56c9fb29bd5c1b2d26b5928bf"},"cell_type":"code","source":"X = []\ny = []\ndef load_all():\n    total_size = len(df_train)\n    for ini, end in [(0, int(total_size/2)), (int(total_size/2), total_size)]:\n        X_temp, y_temp = prep_data(ini, end)\n        X.append(X_temp)\n        y.append(y_temp)\nload_all()\nX = np.concatenate(X)\ny = np.concatenate(y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"51ad0e25b00536de6170168499923d82ae1d735f"},"cell_type":"code","source":"print(X.shape, y.shape)\nnp.save(\"X.npy\",X)\nnp.save(\"y.npy\",y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"289bc7d1ab8048a60025801b457f8df1d848acbc"},"cell_type":"code","source":"def model_lstm(input_shape):\n    inp = Input(shape=(input_shape[1], input_shape[2],))\n    x = Bidirectional(CuDNNLSTM(128, return_sequences=True))(inp)\n    x = Bidirectional(CuDNNLSTM(64, return_sequences=True))(x)\n    x = Attention(input_shape[1])(x)\n    x = Dense(64, activation=\"relu\")(x)\n    x = Dense(1, activation=\"sigmoid\")(x)\n    model = Model(inputs=inp, outputs=x)\n    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[matthews_correlation])\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"59621793c58cd4771823cb6cedc6dd959473f53d"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8d6f4ca319c383b1b4f671a37c5a324136e7a466"},"cell_type":"code","source":"splits = list(StratifiedKFold(n_splits=N_SPLITS, shuffle=True, random_state=2019).split(X, y))\npreds_val = []\ny_val = []\nfor idx, (train_idx, val_idx) in enumerate(splits):\n    K.clear_session()\n    print(\"Beginning fold {}\".format(idx+1))\n    train_X, train_y, val_X, val_y = X[train_idx], y[train_idx], X[val_idx], y[val_idx]\n    model = model_lstm(train_X.shape)\n    ckpt = ModelCheckpoint('weights_{}.h5'.format(idx), save_best_only=True, save_weights_only=True, verbose=1, monitor='val_matthews_correlation', mode='max')\n    model.fit(train_X, train_y, batch_size=128, epochs=50, validation_data=[val_X, val_y], callbacks=[ckpt])\n    model.load_weights('weights_{}.h5'.format(idx))\n    preds_val.append(model.predict(val_X, batch_size=512))\n    y_val.append(val_y)\n\npreds_val = np.concatenate(preds_val)[...,0]\ny_val = np.concatenate(y_val)\npreds_val.shape, y_val.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d28151fd0be9fd9762f3f55e307d82f89bfbd291"},"cell_type":"code","source":"def threshold_search(y_true, y_proba):\n    best_threshold = 0\n    best_score = 0\n    for threshold in tqdm([i * 0.01 for i in range(100)]):\n        score = K.eval(matthews_correlation(y_true.astype(np.float64), (y_proba > threshold).astype(np.float64)))\n        if score > best_score:\n            best_threshold = threshold\n            best_score = score\n    search_result = {'threshold': best_threshold, 'matthews_correlation': best_score}\n    return search_result","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6fee7f722ed08bc1453a822a4371ed2d48e08abc"},"cell_type":"code","source":"best_threshold = threshold_search(y_val, preds_val)['threshold']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ae9bd3fa9d8c0781c0708846bb7f2a9f9e6cbd3c"},"cell_type":"code","source":"%%time\n# 25ms in Kernel\nmeta_test = pd.read_csv('../input/metadata_test.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3eb186d032f79c99ffba05dd1a7fabb77e13cec5"},"cell_type":"code","source":"meta_test = meta_test.set_index(['signal_id'])\nmeta_test.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6f8e94387f625bff0a9a6289e1ee038908bc5856"},"cell_type":"code","source":"%%time\n# About 10min in Kernel\nfirst_sig = meta_test.index[0]\nn_parts = 10\nmax_line = len(meta_test)\npart_size = int(max_line / n_parts)\nlast_part = max_line % n_parts\nprint(first_sig, n_parts, max_line, part_size, last_part, n_parts * part_size + last_part)\nstart_end = [[x, x+part_size] for x in range(first_sig, max_line + first_sig, part_size)]\nstart_end = start_end[:-1] + [[start_end[-1][0], start_end[-1][0] + last_part]]\nprint(start_end)\nX_test = []\nfor start, end in start_end:\n    subset_test = pq.read_pandas('../input/test.parquet', columns=[str(i) for i in range(start, end)]).to_pandas()\n    for i in tqdm(subset_test.columns):\n        id_measurement, phase = meta_test.loc[int(i)]\n        subset_test_col = subset_test[i]\n        subset_trans = transform_ts(subset_test_col)\n        X_test.append([i, id_measurement, phase, subset_trans])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"af9aa6b2b8f8a2beda1a02ff998e3072fcad8d06"},"cell_type":"code","source":"X_test_input = np.asarray([np.concatenate([X_test[i][3],X_test[i+1][3], X_test[i+2][3]], axis=1) for i in range(0,len(X_test), 3)])\nnp.save(\"X_test.npy\",X_test_input)\nX_test_input.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cfd265d3e07c4cc1679d2c4d55fe7de631c813e7"},"cell_type":"code","source":"submission = pd.read_csv('../input/sample_submission.csv')\nprint(len(submission))\nsubmission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2f7342296138f6bfd3e9cedd029e1035de3b98fc"},"cell_type":"code","source":"preds_test = []\nfor i in range(N_SPLITS):\n    model.load_weights('weights_{}.h5'.format(i))\n    pred = model.predict(X_test_input, batch_size=300, verbose=1)\n    pred_3 = []\n    for pred_scalar in pred:\n        for i in range(3):\n            pred_3.append(pred_scalar)\n    preds_test.append(pred_3)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9f76c471eaf983707d446c5081ab3d50c4e40ea5"},"cell_type":"code","source":"preds_test = (np.squeeze(np.mean(preds_test, axis=0)) > best_threshold).astype(np.int)\npreds_test.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b35723f85d494b4b6ec630dd7c79135a110a4062"},"cell_type":"code","source":"submission['target'] = preds_test\nsubmission.to_csv('submission.csv', index=False)\nsubmission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d7600d0093a9880003240ef9ce0a1f1303e4d982"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}