{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Coleridge Initiative - String Literals\n\nThe is a fairly naive approach to solving this problem.\n\n- loop over `train.csv`\n    - perform basic string cleaning (lowercase + remove non-alphanumeric)\n    - create a lookup table for each possible description string (`pub_title`, `dataset_title`, `dataset_label`)\n    - map it back to the expected `cleaned_label` string\n- brute force search the test dataset for any string literals found in `train.csv` \n    - if multiple matches are found, then pick the one with the most matches\n    \n    \n![](https://i.imgflip.com/536dod.jpg)"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np \nimport pandas as pd\nimport simplejson\nimport re\nimport pydash\nimport sys\nimport os\nfrom collections import defaultdict\nfrom typing import *\nfrom joblib import Parallel, delayed\nfrom glob import glob","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv('../input/coleridgeinitiative-show-us-the-data/train.csv')\ntrain_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Extract String Literals\n\nLets create a lookup table for all possible strings used to describe each dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"def clean_text(text: str) -> str:               return re.sub('[^A-Za-z0-9]+', ' ', str(text).lower()).strip()\ndef clean_texts(texts: List[str]) -> List[str]: return [ clean_text(text) for text in texts ] ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def generate_lookup(df):\n    lookup = defaultdict(set)\n    for _, row in df.iterrows():\n        label = clean_text(row['dataset_title'])  # was: row['cleaned_label']\n        lookup[ label ] |= set(clean_texts([ \n            row['dataset_label'], \n            row['dataset_title'], \n            row['pub_title'],\n            # row['cleaned_label'], \n    ]))\n    return lookup\n\nnext(iter(generate_lookup(train_df).items()))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train Dataset Validation\n\nThis validates that this algoritm works on the training dataset, and produces a 100% score"},{"metadata":{"trusted":true},"cell_type":"code","source":"def read_json(index: str, test_train=\"test\") -> Dict:\n    filename = f\"../input/coleridgeinitiative-show-us-the-data/{test_train}/{index}.json\"\n    with open(filename) as f:\n        json = simplejson.load(f)\n    return json\n        \ndef json2text(index: str, test_train=\"test\") -> str:\n    json  = read_json(index, test_train)\n    texts = [\n        row[\"section_title\"] + \" \" + row[\"text\"] \n        for row in json\n    ]\n    texts = clean_texts(texts)\n    text  = \" \".join(texts)\n    return text\n\n\ndef extract_label(text: str, lookup: Dict[str, Set[str]]) -> str:\n    labels = []\n    for label, values in lookup.items():\n        for value in values:\n            if value in text:                \n                labels += [ clean_text(value) ]\n            \n    label = \"|\".join(set(labels))  # multi label support\n    # label = Counter(labels).most_common(1)[0][0] if len(labels) else \"\"  # single most-popular label\n    # print('extract_label', labels, '->', label)\n    return label","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\ndef train_accuracy(df, limit=sys.maxsize) -> float:\n    limit   = 100 if os.environ.get('KAGGLE_KERNEL_RUN_TYPE', 'Localhost') == 'Interactive' else limit\n    lookup  = generate_lookup(df)\n    labels  = Parallel(-1)(\n        delayed(extract_label)(json2text(index, \"train\"), lookup)\n        for index in df['Id'][:limit]\n    )\n    correct   = 0\n    expecteds = df['cleaned_label'][:limit]\n    for label, expected in zip(labels, expecteds):\n        expected_set = set(expected.split(\"|\"))\n        label_set    = set(label.split(\"|\"))\n        matches      = expected_set & label_set\n        correct     += len(matches) / len(label_set)\n\n    # correct = np.count_nonzero( np.array(labels) == expecteds )\n    total   = len(expecteds)\n    return correct / total\n\ntrain_accuracy(train_df, 100)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"def generate_submission():\n    submission_df = pd.read_csv('../input/coleridgeinitiative-show-us-the-data/sample_submission.csv', index_col=0)\n    lookup  = generate_lookup(train_df)\n    indexes = submission_df.index\n    labels  = Parallel(-1)(\n        delayed(extract_label)(json2text(index, \"test\"), lookup)\n        for index in indexes\n    )\n    submission_df['PredictionString'] = labels\n    return submission_df\n\nsubmission_df = generate_submission()\nsubmission_df.to_csv('submission.csv')\n!head submission.csv\nsubmission_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Further Reading\n\nIf you learnt something from this notebook, or would like to fork, then please leave an upvote! Thank you.\n\n\n#### Coleridge - Huggingface Question Answering\n\nThis is not exactly what the competition metric is asking for, but is an interesting experiment nonetheless.\n\nI've taken the Huggingface Question Answering pre-trained model, and asked it to predict which dataset is referenced (as opposed to the text mentioning it).\n\n- https://www.kaggle.com/jamesmcguigan/coleridge-huggingface-question-answering\n"}],"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":4,"nbformat_minor":4}