{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import gc\nimport numpy as np \nimport pandas as pd\nfrom sklearn.model_selection import KFold\nimport matplotlib.pyplot as plt\nplt.style.use('fivethirtyeight') \n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"data = pd.concat([\n       pd.read_csv(\"../input/pageviews/pageviews.csv\", parse_dates=[\"FEC_EVENT\"], usecols=[\"USER_ID\", \"FEC_EVENT\", \"PAGE\"]),\n       pd.read_csv(\"../input/pageviews_complemento/pageviews_complemento.csv\", parse_dates=[\"FEC_EVENT\"], usecols=[\"USER_ID\", \"FEC_EVENT\", \"PAGE\"])\n])\n\ndata[\"day\"] = data.FEC_EVENT.dt.dayofyear - 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_prev = pd.read_csv(\"../input/conversiones/conversiones.csv\")\ny_train = pd.Series(0, index=sorted(data.USER_ID.unique()))\ny_train.loc[y_prev[y_prev.mes >= 10].USER_ID.unique()] = 1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Construcción de la sequencia de datos"},{"metadata":{"trusted":true},"cell_type":"code","source":"data.shape, data.PAGE.nunique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# pages = data[data.FEC_EVENT.dt.month < 10].groupby(\"PAGE\").USER_ID.unique()\n# pages = pages.index[pages.apply(lambda x: y_train.loc[x].mean() / y_train.mean() - 1).abs() > 0.05]\n# data = data[data.PAGE.isin(pages)]\n# data.shape, data.PAGE.nunique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# pages = data.PAGE.value_counts()\n# pages = pages.index[pages < pages.iloc[int(pages.shape[0] * 0.1)]]\n# data = data[data.PAGE.isin(pages)]\n# data.shape, data.PAGE.nunique()                     ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# data[\"PAGE\"] = pd.factorize(data.PAGE)[0]\nnpages = data.PAGE.max() + 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = 60","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def dataPrep(X, nusers, history, npages):\n    data = X.copy()\n    data[\"day\"] = data.day - data.day.max() + history - 1\n    data = data[data.day >= 0]\n    data = data.groupby([\"USER_ID\", \"day\", \"PAGE\"]).size().rename(\"cantidad\").reset_index().set_index(\"USER_ID\")\n    data = data.astype(np.int32)\n    res = np.zeros((nusers, history, npages), dtype=np.float32)\n    for user in range(nusers):\n        if user in data.index:\n            d = data.loc[user]\n            res[user, d.day, d.PAGE] = d.cantidad\n            res[user] /= (res[user].sum(axis=1) + 1e-16)[: , None]\n    return res","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"try:\n    del X_train, X_test\n    gc.collect()\nexcept: pass\n\nX_train = dataPrep(data[data.FEC_EVENT.dt.month < 10], data.USER_ID.max() + 1, history, npages)\nX_test = dataPrep(data, data.USER_ID.max() + 1, history, npages)\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.models import Model, Sequential\nfrom keras.layers import Input, Dense, CuDNNLSTM, add, concatenate, Dropout, Multiply, multiply\nfrom keras.callbacks import EarlyStopping","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras import backend as K\nfrom keras.engine.topology import Layer\nfrom keras import initializers, regularizers, constraints\n\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":{"trusted":true},"cell_type":"code","source":"from keras.models import Model\nfrom keras.layers import Dense, Embedding, Input\nfrom keras.layers import CuDNNLSTM, Bidirectional, Dropout\n\nimport tensorflow as tf\nfrom sklearn.metrics import roc_auc_score\n\ndef auroc(y_true, y_pred):\n    return tf.py_func(roc_auc_score, (y_true, y_pred), tf.double)\n\ndef BidLstm(lstm_size=64):\n    inp = Input(shape=(history, npages))\n    x = Bidirectional(CuDNNLSTM(lstm_size, return_sequences=True))(inp)\n    x = Attention(history)(x)\n    x = Dense(lstm_size * 2, activation=\"relu\")(x)\n    x = Dropout(0.25)(x)\n    x = Dense(1, activation=\"sigmoid\")(x)\n    model = Model(inputs=inp, outputs=x)\n    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[auroc])\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = BidLstm()\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":" model.fit(X_train, y_train, batch_size=320, epochs=1000, verbose=1,\n              validation_split=0.1,\n              callbacks=[EarlyStopping(monitor='val_auroc', patience=10,\n                                       verbose=1, mode='max', restore_best_weights=True)])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_probs = []\nfor i in range(10):\n    model = model = BidLstm()\n    model.fit(X_train, y_train, batch_size=320, epochs=1000, verbose=1,\n              validation_split=0.1,\n              callbacks=[EarlyStopping(monitor='val_auroc', patience=10,\n                                       verbose=1, mode='max', restore_best_weights=True)])\n    \n    test_probs.append(pd.Series(model.predict(X_test)[:, -1], name=\"fold_\" + str(i)))\n\ntest_probs = pd.concat(test_probs, axis=1).mean(axis=1)\ntest_probs.index.name=\"USER_ID\"\ntest_probs.name=\"SCORE\"\n\ntest_probs.to_csv(\"rnn_benchmark.zip\", header=True, compression=\"zip\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"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.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}