{"cells":[{"metadata":{"_cell_guid":"f5930998-1ceb-4f1d-8a53-ea01bc335fae","_uuid":"c5b213f2a6863d7afad8ebdf3bf7a34d981ec35c"},"cell_type":"markdown","source":"# Starter DBSCAN, Validation, and Creating a Submission\n\nIn this kernel, I used a starter DBSCAN (density not tuned and basic preprocessing) to cluster a single event from the train set and to cluster all events from the test set. I also show how to validate predictions using the trackml library and how to create a valid submission.\n\nUpdate: Sorted the test events when creating a submission (required for a valid submission)"},{"metadata":{"_cell_guid":"b9855ddd-8dc0-4aa9-bd89-76378eb6308e","_uuid":"cc5ae125d35120cf8bc8e1c0bb153184495d7767"},"cell_type":"markdown","source":"## Table of Contents\n- Import libraries\n- Starter DBSCAN clustering and validation\n- Clustering the test set\n- Creating a submission"},{"metadata":{"_cell_guid":"33d3a2ae-0ac5-4a3c-9eb3-09378729c763","_uuid":"a44f353354b2611cbc01f9f08a2d319d7f81629e"},"cell_type":"markdown","source":"## Import libraries\nLearned how to import trackml from: https://www.kaggle.com/wesamelshamy/trackml-problem-explanation-and-data-exploration"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","collapsed":true,"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_kg_hide-input":true,"trusted":false},"cell_type":"code","source":"import os\n\nimport numpy as np\nimport pandas as pd\n\nfrom trackml.dataset import load_event\nfrom trackml.randomize import shuffle_hits\nfrom trackml.score import score_event\n\nfrom sklearn import metrics\nfrom sklearn.cluster import DBSCAN\nfrom sklearn.preprocessing import MaxAbsScaler","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"d487cda4-df92-4f87-9918-cb6426af542a","_uuid":"ebf53d24a43ce5836dea6a0952cae5197ce787df"},"cell_type":"markdown","source":"## Load a single event from train set"},{"metadata":{"_uuid":"f5141d0a2d6128ae931484ba257385ae77670b2c","_cell_guid":"2b2fd527-0836-45fc-bc60-5d913ecb57f3","collapsed":true,"_kg_hide-output":false,"_kg_hide-input":false,"trusted":false},"cell_type":"code","source":"hits, cells, particles, truth = load_event('../input/train_1/event000001000')\nhits.head()","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"fbf5e859-c71f-4050-a0ca-b820e53851e0","_uuid":"01c8a188dda88317d1c239a0b29a2707cc37561e"},"cell_type":"markdown","source":"## Starter DBSCAN clustering and validation\n### Scale the data"},{"metadata":{"_cell_guid":"9adfa61a-3212-4a76-a051-4c561b42e451","collapsed":true,"_uuid":"e769319ee231ce15ffe864a19299a11b630582c5","trusted":false},"cell_type":"code","source":"X = hits[['x', 'y', 'z']]\nscaler = MaxAbsScaler().fit(X)\nX = scaler.transform(X)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"142027d6-295d-4e37-95aa-362fda6765d7","_uuid":"676def632f8955c342f486fd2604a8a0f0726b5e"},"cell_type":"markdown","source":"### Cluster the hits"},{"metadata":{"_cell_guid":"4904a088-fe72-49b4-9dbc-c56f52bd061b","collapsed":true,"_uuid":"7f566135a79647886184c4a949df8c12c7ef536c","trusted":false},"cell_type":"code","source":"eps = 0.002\nmin_samp = 2\ndb = DBSCAN(eps=eps, min_samples=min_samp, metric='euclidean').fit(X)\nlabels = db.labels_","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"dc9efe84-198d-43dc-bcab-69a54c7aa4a3","_uuid":"e50f91906e570af033bb05615a48fb81bc808163"},"cell_type":"markdown","source":"### Validate the clustering\nMy **LB score of 0.1535** is very consistent with my current best **validation score of ~0.15** using a few events."},{"metadata":{"_cell_guid":"b246e065-d665-454c-a9a0-61ad551e1f78","collapsed":true,"_uuid":"6ba66a8f61ca95252463adb76ced3d03c46b3986","trusted":false},"cell_type":"code","source":"clustering = pd.DataFrame()\nclustering['hit_id'] = truth['hit_id']\nclustering['track_id'] = labels\n\nscore = score_event(truth, clustering)\nprint(score)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"dc98898f-c02c-4ca9-a7e6-a37b75dce8bc","_uuid":"38a030e8eddb03ec3dc298bd69395430345a53e3"},"cell_type":"markdown","source":"### Other clustering metrics\nHomogeneity and Completeness are actually high when ignoring rejected samples."},{"metadata":{"_cell_guid":"d80fb7de-0f16-4e35-a06f-1046867bdab1","collapsed":true,"_uuid":"ff0b7e45e72f0d82911e1d770f9532f0e5e4e943","_kg_hide-input":true,"trusted":false},"cell_type":"code","source":"labels_true = truth['particle_id']\nn_clusters = len(set(labels)) - (1 if -1 in labels else 0)\n\nprint('CLUSTERING RESULTS:')\nprint('Estimated number of clusters: %d' % n_clusters)\nprint(\"Homogeneity: %0.3f\" % metrics.homogeneity_score(labels_true, labels))\nprint(\"Completeness: %0.3f\" % metrics.completeness_score(labels_true, labels))\nprint(\"Adjusted Rand Index: %0.3f\" % metrics.adjusted_rand_score(labels_true, labels))\nrej_perc = list(labels).count(-1) / float(hits.shape[0]) * 100\nrej_perc = round(rej_perc, 2)\nprint (\"Rejected samples %:\", str(rej_perc) + '%')\nrejected_count = list(labels).count(-1)\nprint (\"Rejected samples:\", rejected_count)\nprint (\"Total samples:\", hits.shape[0])\nprint (\"Clustered samples:\", hits.shape[0] - list(labels).count(-1), '\\n')\n\nprint ('WITHOUT REJECTED SAMPLES:')\nlabels_true_wr = labels_true[labels != -1]\nlabels_wr = labels[labels != -1]\nprint(\"Homogeneity: %0.3f\" % metrics.homogeneity_score(labels_true_wr, labels_wr))\nprint((\"Completeness: %0.3f\" % metrics.completeness_score(labels_true_wr, labels_wr)), '\\n')","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"fd5798bb-7051-4c0b-932d-fd8f296e9dac","_uuid":"04181cffee5a4dd9c55d2cafe137f5ce83018c62"},"cell_type":"markdown","source":"## Clustering the test set"},{"metadata":{"_cell_guid":"041a6dd8-a5e9-4a4a-9e73-908d58fbd1d1","collapsed":true,"_uuid":"85976a261ff10d6706c7b94aace3ae3854258f1d","trusted":false},"cell_type":"code","source":"def cluster_event(event_filename):\n    # function for clustering hits in a given event file\n    \n    print('clustering {}...'.format(event_filename))\n    \n    # load event\n    event_name = event_filename.split('-')[0]\n    test_hits, test_cells = load_event('../input/test/{}'.format(event_name), parts=['hits', 'cells'])\n    \n    # scale hits\n    X_test = test_hits[['x', 'y', 'z']]\n    scaler = MaxAbsScaler().fit(X_test)\n    X_test = scaler.transform(X_test)\n    \n    # cluster hits\n    eps = 0.002\n    min_samp = 2\n    db = DBSCAN(eps=eps, min_samples=min_samp, metric='euclidean').fit(X_test)\n    labels = db.labels_\n    \n    # format output\n    event = pd.DataFrame()\n    event_num = int(event_name.split('event')[-1])\n    event['event_id'] = [event_num] * len(test_hits['hit_id'])\n    event['hit_id'] = test_hits['hit_id']\n    # apparently, track_id values can't be negative when i tried submitting\n    # add 1 to labels values because rejected samples are labeled -1\n    event['track_id'] = labels + 1\n    \n    return event","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"aaa1048c-f310-4f7b-94b5-18cbc091f650","_uuid":"1243afa8c471773df3e90da60ac81d89ea2d57c9"},"cell_type":"markdown","source":"## Creating a submission\n### Cluster all events and append results to DataFrame\nThe events must be sorted."},{"metadata":{"_uuid":"97696911df3e1c32f8e0e00e6ca2af60f6392e2b","_cell_guid":"2786668b-6822-4974-a9d0-26ca6a5f017a","collapsed":true,"scrolled":true,"_kg_hide-output":true,"trusted":false},"cell_type":"code","source":"submission = pd.DataFrame()\nfor event_filename in sorted(os.listdir(\"../input/test\")):\n    if '-hits.csv' in event_filename:\n        clustered_event = cluster_event(event_filename)\n        submission = pd.concat([submission, clustered_event])","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"5b63df98-8016-44c8-b74a-58e07b8c3efc","_uuid":"ae1761f8d89d99c24bcf83d092b67cffd4e63ad0"},"cell_type":"markdown","source":"### Write output to csv\nNote that I **removed negative values from the track_id column** in the above function. Negative values in the track_id column are not accepted."},{"metadata":{"_cell_guid":"79697261-0387-4fef-9d57-47db1b1d7976","collapsed":true,"_uuid":"7b921945c7139a35e06d04cc5cb7bb73e818b097","trusted":false},"cell_type":"code","source":"submission.to_csv('dbcan_init.csv', index=False)","execution_count":null,"outputs":[]}],"metadata":{"language_info":{"name":"python","version":"3.6.5","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"}},"nbformat":4,"nbformat_minor":1}