{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport torch \nfrom torch import nn, optim\nimport random\nfrom sklearn.metrics import roc_auc_score","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load Data","metadata":{}},{"cell_type":"code","source":"random.seed(5566)\nnum_lines = 40428968\nsample_size = 100000\nskip = sorted(random.sample(range(1, num_lines), num_lines-sample_size))\ndf = pd.read_csv(\"../input/avazu-ctr-prediction/train.gz\", header=0, skiprows=skip)\ndf = df.dropna()\n\neval_ratio = 0.1\nidx = list(range(len(df)))\nrandom.seed(1)\nrandom.shuffle(idx)\ntrain_idx = idx[int(len(df)*eval_ratio):]\neval_idx = idx[:int(len(df)*eval_ratio)]\ntrain_df = df.iloc[train_idx]\neval_df = df.iloc[eval_idx]\n\n#test_df = pd.read_csv(\"../input/avazu-ctr-prediction/test.gz\", header=0, skiprows=skip)\n#test_df = test_df.dropna()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for name in train_df.columns:\n    print(\"%s: %s\" % (name, len(train_df[name].unique())))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Feature Engineering","metadata":{}},{"cell_type":"code","source":"keep_features = ['hour', 'C1', 'banner_pos', 'site_category', 'app_domain', 'app_category', \n                 'device_type', 'device_conn_type', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21']\nC1_values = train_df.C1.unique()\nC1_map = {}\ndef get_maps(names):\n    \"\"\"return a dict of feature names and value maps\"\"\"\n    result = {}\n    for name in names:\n        dic = {}\n        values = train_df[name].unique()\n        for v in values:\n            dic[v] = len(dic)\n        result[name] = dic\n    return result\n\nmaps = get_maps(keep_features)\n\ndef trans_feature_by_name(x, name):\n    if name == \"hour\":\n        return int(str(x)[-2:])\n    elif x in maps[name]:\n        return maps[name][x]\n    else:\n        return len(maps[name])\n\nfor name in keep_features:\n    train_df[name+\"_trans\"] = train_df[name].map(lambda x: trans_feature_by_name(x, name))\n    eval_df[name+\"_trans\"] = eval_df[name].map(lambda x: trans_feature_by_name(x, name))\ntrans_features = [name+\"_trans\" for name in keep_features]\n\ntrain_features_matrix = train_df[trans_features]\ntrain_labels = train_df[\"click\"]\n\neval_features_matrix = eval_df[trans_features]\neval_labels = eval_df[\"click\"]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Build Model","metadata":{}},{"cell_type":"code","source":"class CustomModel(nn.Module):\n    def __init__(self, embed_info):\n        super().__init__()\n        self.feature_names = []\n        for name, n, dim in embed_info:\n            setattr(self, \"layer_\"+name, nn.Embedding(n, dim))\n            self.feature_names.append(name)\n        self.linear1 = nn.Linear(sum([v for _, _, v in embed_info]), 125)\n        self.linear2 = nn.Linear(125, 1)\n        self.sigmoid = nn.Sigmoid()\n    def forward(self, features):\n        embeds = []\n        for name in self.feature_names:\n            embed = getattr(self, \"layer_\" + name)(torch.tensor(features[name]))\n            embeds.append(embed)\n        embeds_cat = torch.cat(embeds, axis=-1)\n        out = self.linear1(embeds_cat)\n        out = self.linear2(out)\n        probs = self.sigmoid(out)\n        return torch.flatten(probs)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train Model","metadata":{}},{"cell_type":"code","source":"BS=256\nlr=1e-3\nepochs=5\nembed_info = [('hour_trans', 24, 6), ('C1_trans', 8, 3), ('banner_pos_trans', 8, 3), ('site_category_trans', 20, 6), \n              ('app_domain_trans', 124, 30), ('app_category_trans', 25, 7), \n                 ('device_type_trans', 6, 3), ('device_conn_type_trans', 5, 3), ('C15_trans', 9, 4),\n              ('C16_trans', 10, 4), ('C17_trans', 409, 50), ('C18_trans', 5, 3), ('C19_trans', 67, 15), ('C20_trans', 158, 35), ('C21_trans', 61, 20)]\nmodel = CustomModel(embed_info)\nloss_fn = nn.BCELoss()\nopt = optim.Adam(model.parameters(), lr=lr)\nbest = 0\nfor e in range(1, epochs+1):\n    print(\"epoch \" + str(e) + \": \")\n    model.train()\n    for i in range(int(len(train_features_matrix)/BS)):\n        output = model(train_features_matrix.iloc[i*BS:(i+1)*BS].to_dict('list'))\n        target = train_labels[i*BS:(i+1)*BS]\n        loss = loss_fn(output, torch.tensor(target.values, dtype=torch.float32))\n        loss.backward()\n        opt.step()\n    model.eval()\n    probs = model(eval_features_matrix.to_dict('list'))\n    score = roc_auc_score(eval_labels, probs.detach().numpy())\n    score = round(score, 4)\n    if score > best:\n        print(\"find better score: %s, old score: %s\" % (score, best))\n        best = score\n    else:\n        print(\"current score: %s, best score: %s\" % (score, best))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}