{"cells":[{"metadata":{"_uuid":"a2a0dd2217d7c5c1e97d6e9476c0a967fe8f55e4"},"cell_type":"markdown","source":"## Contents\n* [Loading and Cleaning Data](#Loading-and-Cleaning-Data)\n* [Plots](#Plots)\n* [Interactive Graphs](#Interactive-Graphs)"},{"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\nimport copy\nimport os\nimport json\nimport igraph\nimport plotly.plotly as py\nimport plotly.graph_objs as go\nimport networkx as nx\nfrom collections import Counter, defaultdict\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nsns.set_style('darkgrid')\n%matplotlib inline\nnp.warnings.filterwarnings('ignore')\n\nfrom plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot\ninit_notebook_mode(connected=True)\n\nnrows = None","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"769ce9727b2d7f3a65d6017b969e85babee14c87"},"cell_type":"markdown","source":"### Loading and Cleaning Data"},{"metadata":{"trusted":true,"_uuid":"c2e1222e419d115ae254f00469ee48dd82a0c897"},"cell_type":"code","source":"# just a list of trainable label codes\nclasses_trainable = pd.read_csv('../input/classes-trainable.csv', dtype=str)\nclasses_trainable = set(classes_trainable.label_code)\nprint(f'{len(classes_trainable)} trainable labels')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"c49bf6e1f57c88dac4bf5a12954a784a59665254"},"cell_type":"code","source":"class_descriptions = pd.read_csv('../input/class-descriptions.csv', dtype=str)\nlabel_code_to_description = dict(zip(class_descriptions.label_code, class_descriptions.description))\nprint(f'{len(label_code_to_description)} labels with descriptions')\nclass_descriptions.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7e12ed5f60ca6f54f6422b0c496baa847137921b"},"cell_type":"markdown","source":"A description does not always uniquely identify a label_code."},{"metadata":{"trusted":true,"_uuid":"35fc4795ad4d08ed25b9e8adfccb152f66f91962"},"cell_type":"code","source":"class_description_counts = class_descriptions.groupby('description').count().rename(columns={'label_code': 'count'})\nrepeated_descriptions = class_description_counts[(class_description_counts > 1).values].sort_values('count', ascending=False)\nprint(f'{len(repeated_descriptions)} descriptions have more than one associated label code')\nrepeated_descriptions.head(15)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3bff48eb389efcbe10fdda1e747ea709e0a658c2"},"cell_type":"markdown","source":"### Train Human labels\nThese are the image-level labels (no bounding box) annotated by humans with Confidence=1. Most of these labels are from annotators hired by Google ('verification') and the rest are from crowd-sourcing ('crowdsource-verification'). Read more details at [Overview of Open Images V4](https://storage.googleapis.com/openimages/web/factsfigures.html). One important note from that page is that false positives (class incorrectly labelled) are all but eliminated, but false negatives (class not labelled when it actually is in the image) are present."},{"metadata":{"trusted":true,"_uuid":"a04c3ba98f59891d6263ac3c5d1b5fc184d0c9f7"},"cell_type":"code","source":"train_human_labels = pd.read_csv('../input/train_human_labels.csv', dtype={'ImageID': str, 'Source': str, 'LabelName': str, 'Confidence': np.float64}, nrows=nrows)\nprint(f'{len(train_human_labels)} human-labeled labels on training images')\nprint(f'Sources: {set(train_human_labels.Source)}')\nprint(f'Number unique labels: {len(train_human_labels.LabelName.unique())}')\ntrain_human_labels['type'] = 'human'\ntrain_human_labels.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2b058825698c76a41225fd8dfab9d3fc2d87c7ea"},"cell_type":"markdown","source":"### Train Machine Labels\nThese are the image-level labels annotated by a model with varying confidence levels. More details at [Overview of Open Images V4](https://storage.googleapis.com/openimages/web/factsfigures.html).\n"},{"metadata":{"trusted":true,"_uuid":"7bf4233d4a0ea0c9b125215ce07ad8b2fd3e877a"},"cell_type":"code","source":"train_machine_labels = pd.read_csv('../input/train_machine_labels.csv', dtype={'ImageID': str, 'Source': 'category', 'LabelName': 'category', 'Confidence': np.float64}, nrows=nrows)\nprint(f'{len(train_machine_labels)} machine-labeled labels on training images')\nprint(f'Sources: {set(train_machine_labels.Source)}')\nprint(f'Number unique labels: {len(train_machine_labels.LabelName.unique())}')\ntrain_machine_labels['type'] = 'machine'\ntrain_machine_labels.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2eae70225c45343c10b841672e82f62d1ecf55dd"},"cell_type":"markdown","source":"### Bounding Boxes\n\nThese are the labels with bounding boxes with Confidence=1. There are only 599 label codes represented in the bounding boxes. Most of these have been added by professional annotators. Again, more details at [Overview of Open Images V4](https://storage.googleapis.com/openimages/web/factsfigures.html). I believe the 'xclick' boxes are \"manually drawn by  professional annotators at Google using the efficient extreme clicking interface\" (from provided link) and the 'activemil' is done somewhat automatically with human verification (from provided link).\n\n Attribute definitions from the [Open Images Website](https://storage.googleapis.com/openimages/web/download.html#attributes):\n> * IsOccluded: Indicates that the object is occluded by another object in the image.\n> * IsTruncated: Indicates that the object extends beyond the boundary of the image.\n> * IsGroupOf: Indicates that the box spans a group of objects (e.g., a bed of flowers or a crowd of people). We asked annotators to use this tag for cases with more than 5 instances which are heavily occluding each other and are physically touching.\n> * IsDepiction: Indicates that the object is a depiction (e.g., a cartoon or drawing of the object, not a real physical instance).\n> * IsInside: Indicates a picture taken from the inside of the object (e.g., a car interior or inside of a building).\n>\n> For each of them, value 1 indicates present, 0 not present, and -1 unknown."},{"metadata":{"trusted":true,"_uuid":"399e5ec16e2ee19ec29b4f30521d3d042ccc5a3d"},"cell_type":"code","source":"train_bounding_boxes = pd.read_csv('../input/train_bounding_boxes.csv', \n                                   dtype={\n                                       'ImageID': str,\n                                       'Source': 'category',\n                                       'LabelName': 'category',\n                                       'Confidence': np.int8,\n                                       'XMin': np.float32,\n                                       'XMax': np.float32,\n                                       'YMin': np.float32,\n                                       'YMax': np.float32,\n                                       'IsOccluded': np.int8,\n                                       'IsTruncated': np.int8,\n                                       'IsGroupOf': np.int8,\n                                       'IsDepiction': np.int8,\n                                       'IsInside': np.int8,\n                                   }, \n                                   nrows=nrows)\n\n# replace unknown placeholder -1 with nan\nattr_cols = ['IsOccluded', 'IsTruncated', 'IsGroupOf', 'IsDepiction', 'IsInside']\ntrain_bounding_boxes[attr_cols] = train_bounding_boxes[attr_cols].replace(to_replace=-1, value=np.nan)\n\nprint(f'{len(train_bounding_boxes)} bounding boxes on {len(set(train_bounding_boxes.ImageID))} training images')\nprint(f'Sources: {set(train_bounding_boxes.Source)}')\nprint(f'Number unique labels: {len(train_bounding_boxes.LabelName.unique())}')\ntrain_bounding_boxes['type'] = 'bbox'\ntrain_bounding_boxes.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5316f3b16598ee6bd613db18b56c3d5ac5ad7767"},"cell_type":"code","source":"train_labels = pd.concat([train_human_labels, train_machine_labels, train_bounding_boxes], axis='rows', ignore_index=True, sort=False).reset_index(drop=True)\ndel train_human_labels\ndel train_machine_labels\ndel train_bounding_boxes\n\n# get human readable label description\ntrain_labels['LabelDescription'] = train_labels['LabelName'].apply(lambda x: label_code_to_description.get(x, ''))\n\n# make a new col that has both label and description for easy identification while maintaining uniqueness\ntrain_labels['LabelAndDescription'] = train_labels['LabelName'].str.cat(train_labels['LabelDescription'], sep=' - ')\n\ndtypes = {\n    'ImageID': str,\n    'Source': str,\n    'LabelName': str,\n    'LabelDescription': str,\n    'LabelAndDescription': str,\n    'Confidence': np.float32,\n    'IsOccluded': np.float32,\n    'IsTruncated': np.float32,\n    'IsGroupOf': np.float32,\n    'IsDepiction': np.float32,\n    'IsInside': np.float32,\n}\ntrain_labels = train_labels.astype(dtypes)\n\nprint(f'{len(train_labels)} total labels on {len(train_labels.ImageID.unique())} training images')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8b31e404c4d66ec8bb29ad6608102fe0a7c976e0"},"cell_type":"code","source":"train_labels = train_labels.drop(['XMin', 'XMax', 'YMin', 'YMax'], axis='columns')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2d7b157e2390e9a03ab1260271660dee81cbdbf6","trusted":true},"cell_type":"code","source":"gc.collect()\ntrain_labels.head(1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"50ad772dc16ed180282b32cdb7dad7631891012e"},"cell_type":"code","source":"tuning_labels = pd.read_csv('../input/tuning_labels.csv', header=None, names=['ImageID', 'LabelNames'], dtype=str)\n\n# transforming list of label names into a row for each label name\ntuning_labels.index = tuning_labels['ImageID']\nlabels = tuning_labels.LabelNames.str.split(expand=True).stack()\nlabels.index = labels.index.droplevel(-1)\nlabels.name = \"LabelName\"\ntuning_labels = pd.concat([tuning_labels, labels], axis=1, join='inner')\n\ntuning_labels = tuning_labels.drop('LabelNames', axis='columns')\ntuning_labels = tuning_labels.reset_index(drop=True)\n\nprint(f'{len(tuning_labels)} tuning labels on {len(set(tuning_labels.ImageID))} stage 1 test images')\n\n# get human readable label description\ntuning_labels['LabelDescription'] = tuning_labels['LabelName'].apply(lambda x: label_code_to_description.get(x, ''))\n\n# make a new col that has both label and description for easy identification while maintaining uniqueness\ntuning_labels['LabelAndDescription'] = tuning_labels['LabelName'].str.cat(tuning_labels['LabelDescription'], sep=' - ')\n\ntuning_labels.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e48e32a33fef7904efd4324b325526871ce09c19"},"cell_type":"code","source":"labels_without_description = set(train_labels[train_labels.LabelDescription == '']['LabelName'])\nprint(f'Labels in train dataset with no description: {labels_without_description}')\nprint(f'Trainable classes without description: {labels_without_description.intersection(classes_trainable)}')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a0c2e096bf67d310a24131a3a3c9a3ed3aaf6518"},"cell_type":"code","source":"human_train_label_set = set(train_labels[train_labels['type'] == 'human'].LabelName)\nmachine_train_label_set = set(train_labels[train_labels['type'] == 'machine'].LabelName)\nbbox_train_label_set = set(train_labels[train_labels['type'] == 'machine'].LabelName)\nstage_1_tuning_label_set = set(tuning_labels.LabelName)\n\nprint(f'Human train labels: {len(human_train_label_set.intersection(classes_trainable))}/{len(human_train_label_set)} are \"trainable\"')\nprint(f'Machine train labels: {len(machine_train_label_set.intersection(classes_trainable))}/{len(machine_train_label_set)} are \"trainable\"')\nprint(f'Bbox train labels: {len(bbox_train_label_set.intersection(classes_trainable))}/{len(bbox_train_label_set)} are \"trainable\"')\nprint(f'Stage 1 tuning labels: {len(stage_1_tuning_label_set.intersection(classes_trainable))}/{len(stage_1_tuning_label_set)} are \"trainable\"')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6e5b168602faf40d4068c8bffee3cda9ebbd6748"},"cell_type":"markdown","source":"### Plots"},{"metadata":{"trusted":true,"_uuid":"bab9427e77a120fa90cf4b5bc3c5e8590a0f8734"},"cell_type":"code","source":"def plot_label_per_image_dist(df, title, bins=[300, 60], xmax=100):\n\n    fig, axes = plt.subplots(1, 2, figsize=(14, 8))\n    mean = df['LabelName_count'].mean()\n    median = df['LabelName_count'].median()\n    p = sns.distplot(df['LabelName_count'], bins=bins[0], kde=False, ax=axes[0])\n    _ = p.set_xlabel('Number of labels per ImageID')\n    _ = p.set_xlim((0,xmax))\n    _ = p.text(1, 1, f'mean: {mean:.2f}\\nmedian: {median:.2f}',  horizontalalignment='right', verticalalignment='top', transform=p.axes.transAxes)\n    \n    mean = df['LabelName_nunique'].mean()\n    median = df['LabelName_nunique'].median()\n    p = sns.distplot(df['LabelName_nunique'], bins=bins[1], kde=False, ax=axes[1])\n    _ = p.set_xlabel('Number of unique labels per ImageID')\n    _ = p.set_xlim((0,xmax))\n    _ = p.text(1, 1, f'mean: {mean:.2f}\\nmedian: {median:.2f}',  horizontalalignment='right', verticalalignment='top', transform=p.axes.transAxes)\n    \n    fig.suptitle(title, x=.5, y=1.01, fontsize=16)\n    fig.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ccbe7edcacfe9fe2489225a63e3fb7b800b45675"},"cell_type":"code","source":"aggs = {\n    'LabelName': ['count', 'nunique']\n}\ncounts = train_labels.groupby(['ImageID']).agg(aggs)\ncounts.columns = counts.columns.map('_'.join)\n\nplot_label_per_image_dist(counts, 'Labels and Unique Labels per Image in Entire Train Dataset')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"08928a050d52d35174d576b1eb35dca67b03cfab"},"cell_type":"code","source":"aggs = {\n    'LabelName': ['count', 'nunique']\n}\ncounts = tuning_labels.groupby(['ImageID']).agg(aggs)\ncounts.columns = counts.columns.map('_'.join)\n\nplot_label_per_image_dist(counts, 'Labels and Unique Labels per Image in Tuning Dataset', bins=[10, 10], xmax=10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a3c642d92f0608958d8e28e36d733bc71d108e7b"},"cell_type":"code","source":"def plot_label_frequency_grid(df, title):\n    fig, axes = plt.subplots(2, 2, figsize=(16, 16))\n\n    count_mean = df['ImageID_count'].mean()\n    count_median = df['ImageID_count'].median()\n    p = sns.barplot(y='LabelAndDescription', x='ImageID_count', data=df.sort_values('ImageID_count', ascending=False)[0:30], alpha=.7, ax=axes[0][0])\n    _ = p.set_xlabel('Number of instances of Label in Train Dataset')\n    _ = p.set_ylabel('Label And Description')\n    _ = p.text(1, 1, f'mean: {count_mean:.2f}\\nmedian: {count_median:.2f}',  horizontalalignment='right', verticalalignment='top', transform=p.axes.transAxes)\n    \n    nunique_mean = df['ImageID_nunique'].mean()\n    nunique_median = df['ImageID_nunique'].median()\n    p = sns.barplot(y='LabelAndDescription', x='ImageID_nunique', data=df.sort_values('ImageID_nunique', ascending=False)[0:30], alpha=.7, ax=axes[0][1])\n    _ = p.set_xlabel('Number of unique images with Label in Train Dataset')\n    _ = p.set_ylabel('Label And Description')\n    _ = p.text(1, 1, f'mean: {nunique_mean:.2f}\\nmedian: {nunique_median:.2f}',  horizontalalignment='right', verticalalignment='top', transform=p.axes.transAxes)\n\n    p = sns.distplot(df['ImageID_count'], bins=20, kde=False, ax=axes[1][0])\n    _ = p.set_yscale('log')\n    _ = p.set_ylabel('Count')\n    _ = p.set_xlabel('Number of instances of Label in Train Dataset')\n    _ = p.text(1, 1, f'mean: {count_mean:.2f}\\nmedian: {count_median:.2f}',  horizontalalignment='right', verticalalignment='top', transform=p.axes.transAxes)\n\n    p = sns.distplot(df['ImageID_nunique'], bins=20, kde=False, ax=axes[1][1])\n    _ = p.set_yscale('log')\n    _ = p.set_ylabel('Count')\n    _ = p.set_xlabel('Number of unique images with Label in Train Dataset')\n    _ = p.text(1, 1, f'mean: {nunique_mean:.2f}\\nmedian: {nunique_median:.2f}',  horizontalalignment='right', verticalalignment='top', transform=p.axes.transAxes)\n    \n    fig.suptitle(title, x=.5, y=1.01, fontsize=16)\n    fig.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cd5eca54cef26077a132ed00e78e22c43ff72e3f"},"cell_type":"code","source":"aggs = {\n    'ImageID': ['count', 'nunique']\n}\ncounts = train_labels.groupby(['LabelAndDescription']).agg(aggs)\ncounts.columns = counts.columns.map('_'.join)\ncounts = counts.reset_index(drop=False)\ncounts['LabelAndDescription'] = counts['LabelAndDescription'].astype(str)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fe7911779e9179cd017f504c25531e28c0cd4739"},"cell_type":"code","source":"plot_label_frequency_grid(counts, 'Frequencies of Labels in Entire Train Dataset')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f4c0e37ac57603b3b2531c2dc1b38ae1a8334133","scrolled":true},"cell_type":"code","source":"aggs = {\n    'ImageID': ['count', 'nunique']\n}\ntrainable_counts = train_labels[train_labels.LabelName.isin(classes_trainable)].groupby(['LabelAndDescription']).agg(aggs)\ntrainable_counts.columns = trainable_counts.columns.map('_'.join)\ntrainable_counts = trainable_counts.reset_index(drop=False)\ntrainable_counts['LabelAndDescription'] = trainable_counts['LabelAndDescription'].astype(str)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6cb2eb4b080d8d7c49f5f58a4da7585eb5ea5fec"},"cell_type":"code","source":"plot_label_frequency_grid(trainable_counts, 'Frequencies of Labels in \"Trainable\" Portion of Dataset')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5de20323cc405ea806b792ce9ed67cc68cd68f7b"},"cell_type":"code","source":"del counts\ndel trainable_counts\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5e7b2f5bf625ab7aeb8a711f5a06e910152f3ab0"},"cell_type":"code","source":"bbox_labels = train_labels[train_labels['type'] == 'bbox']\n\naggs = {\n    'ImageID': ['count', 'nunique'],\n    'IsOccluded': ['mean'],\n    'IsTruncated': ['mean'],\n    'IsGroupOf': ['mean'],\n    'IsDepiction': ['mean'],\n    'IsInside': ['mean'],\n}\nbbox_counts = bbox_labels.groupby(['LabelAndDescription']).agg(aggs)\nbbox_counts.columns = bbox_counts.columns.map('_'.join)\nbbox_counts = bbox_counts.reset_index(drop=False)\nbbox_counts['LabelAndDescription'] = bbox_counts['LabelAndDescription'].astype(str)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b42a20a140bf736cdd1b2192e34e866a168d7cd5"},"cell_type":"code","source":"plot_label_frequency_grid(bbox_counts, 'Frequencies of Labels in Bbox Train Dataset')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e927f71cf3555c77a25a96eb795c928d6e24045a"},"cell_type":"code","source":"aggs = {\n    'ImageID': ['count', 'nunique'],\n}\ntuning_counts = tuning_labels.groupby(['LabelAndDescription']).agg(aggs)\ntuning_counts.columns = tuning_counts.columns.map('_'.join)\ntuning_counts = tuning_counts.reset_index(drop=False)\ntuning_counts['LabelAndDescription'] = tuning_counts['LabelAndDescription'].astype(str)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c41766091161ae400b0548bb8dc6f5d32a567f46"},"cell_type":"code","source":"plot_label_frequency_grid(bbox_counts, 'Frequencies of Labels in Tuning Dataset')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ee57ff4fdce0327d7ff8c4057f7e9fd105b27f5b"},"cell_type":"code","source":"def plot_attributes(df, title, attribute):\n    fig, axes = plt.subplots(1, 2, figsize=(14, 7))\n\n    count_mean = df[attribute].mean()\n    count_median = df[attribute].median()\n    p = sns.barplot(y='LabelAndDescription', x=attribute, data=df.sort_values(attribute, ascending=False)[0:30], alpha=.7, ax=axes[0])\n    _ = p.set_xlabel('Number of instances of Label in Train Dataset')\n    _ = p.set_ylabel('Label And Description')\n    _ = p.text(1, 1, f'mean: {count_mean:.2f}\\nmedian: {count_median:.2f}',  horizontalalignment='right', verticalalignment='top', transform=p.axes.transAxes)\n\n    p = sns.distplot(df[attribute], bins=20, kde=False, ax=axes[1])\n    _ = p.set_yscale('log')\n    _ = p.set_ylabel('Count')\n    _ = p.text(1, 1, f'mean: {count_mean:.2f}\\nmedian: {count_median:.2f}',  horizontalalignment='right', verticalalignment='top', transform=p.axes.transAxes)\n    \n    fig.suptitle(title, x=.5, y=1.01, fontsize=16)\n    fig.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":false,"_uuid":"0930672d7d59f4428f98aa6d98fcacd5d84c4744"},"cell_type":"code","source":"attributes = ['IsOccluded', 'IsTruncated', 'IsGroupOf', 'IsDepiction', 'IsInside']\nattributes = [f'{x}_mean' for x in attributes]\nfor attribute in attributes:\n    plot_attributes(df=bbox_counts, title=attribute, attribute=attribute)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0039d1489757aec4d902110fdeac40ae5467b374","_kg_hide-output":true},"cell_type":"code","source":"# downloading the class hierarchy for the bbox classes from https://storage.googleapis.com/openimages/web/factsfigures.html\n!wget https://storage.googleapis.com/openimages/2018_04/bbox_labels_600_hierarchy.json","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d53a1d5f6639f84d59e5dbbe46268f96ee092678"},"cell_type":"code","source":"with open('./bbox_labels_600_hierarchy.json', 'r') as f_in:\n    class_hierarchy = json.loads(f_in.read())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1fad173126868350aeadbbf7547c2bfdec49748f","_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"class_hierarchy","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"9b6b158316ae062fc6bda237add7ca47a95dc952"},"cell_type":"code","source":"bbox_counts['LabelName'] = bbox_counts['LabelAndDescription'].apply(lambda x: x.split(' - ')[0])\nbbox_counts.index = bbox_counts['LabelName']\nbbox_counts['ImageID_count_log10'] = np.log10(bbox_counts['ImageID_count'])\nbbox_counts['ImageID_nunique_log10'] = np.log10(bbox_counts['ImageID_nunique'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"de261537f482aa2dcaa89245797df9d2a3c782f6"},"cell_type":"code","source":"bbox_counts.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1ba6ad0f84295410c30e2489f5e3e8c9622aadfc"},"cell_type":"code","source":"def get_label_features(df):\n    features = {}\n    record_dicts = df.to_dict(orient='records')\n    for record_dict in record_dicts:\n        features[record_dict.pop('LabelName')] = record_dict\n    return features","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"984ea079a2dce947befd0a20d204519cc1193099"},"cell_type":"code","source":"label_features = get_label_features(bbox_counts.drop(['LabelAndDescription'], axis='columns'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7325402cd41934a062aef563c50740e4c248a456"},"cell_type":"code","source":"# example of one item in the created dict\nnext(iter(label_features.items()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ead7a548a85ea44200aacfb95c213c9f809b04e9"},"cell_type":"code","source":"def make_graph(d, graph, prev_node_added=None, level=1, label_code_to_description=label_code_to_description, label_features=label_features):\n    if graph is None:\n        graph = nx.DiGraph()\n    for key, value in d.items():\n        if key == 'LabelName':\n            class_desc = label_code_to_description.get(value, None)\n            label_feats = label_features.get(value, None)\n            if label_feats is None:\n                sample_feats_dict = next(iter(label_features.values()))\n                label_feats = {k: 0 for k in sample_feats_dict.keys()}\n            graph.add_node(value, Description=label_code_to_description.get(value), Level=level, **label_feats)\n            if prev_node_added:\n                graph.add_edge(prev_node_added, value)\n            prev_node_added = value\n        elif key == 'Subcategory':# or key == 'Part':\n            for subcat in value:\n                graph = make_graph(subcat, graph, prev_node_added=prev_node_added, level=level + 1, label_code_to_description=label_code_to_description, label_features=label_features)\n    return graph\n\ndef add_adjacency_to_nodes(g):\n    # adjacent nodes will be a dict of nodes names of all children / outgoing edge nodes\n    for node_name, adjacent_nodes in g.adjacency():\n        g.node[node_name].update({'num_adjacent_nodes': len(adjacent_nodes)})\n    return g\n\ndef get_node_coords(g, layout_type):\n    ig = igraph.Graph(directed=True)\n    ig.add_vertices(list(g.nodes))\n    ig.add_edges(list(g.edges))\n    if layout_type == 'layout_reingold_tilford':\n        ig_layout = ig.layout_reingold_tilford(mode='OUT', root=[0])\n    elif layout_type == 'layout_fruchterman_reingold':\n        ig_layout = ig.layout_fruchterman_reingold()\n    elif layout_type == 'layout_kamada_kawai':\n        ig_layout = ig.layout_kamada_kawai()\n    else:\n        ig_layout = ig.layout_reingold_tilford_circular(mode='OUT', root=[0])\n    root_at_top_coords = [[coord[0], -coord[1]] for coord in ig_layout.coords]\n    coords = {vertex['name']: coord for vertex, coord in zip(igraph.VertexSeq(ig), root_at_top_coords)}\n    return coords","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d97d376c5dc100c5cb56ad32fff09110c7b3a32f"},"cell_type":"code","source":"def build_node_traces(keys):\n    node_traces = {}\n    for key in keys:\n        trace = go.Scatter(\n            x=[],\n            y=[],\n            text=[],\n            mode='markers',\n            hoverinfo='text',\n            marker=dict(\n                showscale=True,\n                colorscale='Viridis',\n                color=[],\n                size=10,\n                colorbar=dict(thickness=15, title=key, xanchor='left', titleside='right'),\n                line=dict(width=2)\n            ),\n            visible=False,\n        )\n        node_traces[key] = trace\n    return node_traces","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"181cc8909e187bb8e048b04b905557efb6c11018"},"cell_type":"code","source":"def plot_tree(graph, node_coords, title):\n    edge_trace = go.Scatter(\n        x=[],\n        y=[],\n        text=[],\n        line=dict(width=0.5,color='#888'),\n        hoverinfo='text',\n        mode='lines')\n\n    for edge in graph.edges():\n        x0, y0 = node_coords[edge[0]]\n        x1, y1 = node_coords[edge[1]]\n        edge_trace['x'] += tuple([x0, x1, None])\n        edge_trace['y'] += tuple([y0, y1, None])\n\n    sample_node_name = next(iter(g.nodes()))\n    sample_node = graph.node[sample_node_name]\n    nonlabel_keys = [x for x in sample_node.keys() if x != 'Description']\n    \n    # construct dict of traces for each attribute\n    node_traces = build_node_traces(nonlabel_keys)\n    \n    # add the position and data of each node to the node traces\n    for node in graph.nodes():\n        x, y = node_coords[node]\n        node_data = graph.node[node]\n        trace_txt = f'<br>Label: {node}<br>'\n        str_list = [f'{k}: {v}' if not isinstance(v, float) else f'{k}: {v:.3f}' for k,v in node_data.items()]\n        trace_txt += '<br>'.join(str_list)\n        \n        for trace_key, trace in node_traces.items():\n            # position\n            trace['x'] += tuple([x])\n            trace['y'] += tuple([y])\n            \n            # text and marker\n            trace['text']+=tuple([trace_txt])\n            trace['marker']['color']+=tuple([node_data[trace_key]])\n            \n    # construct buttons\n    buttons = {}\n    for idx, key in enumerate(nonlabel_keys):\n        # first visible trace will be the edge_trace which will constantly be visible\n        trace_visibilities = [True]\n        \n        # set all other node traces to not visible besides the current one\n        trace_visibilities += [False] * len(node_traces)\n        trace_visibilities[idx + 1] = True\n        \n        buttons[key] = dict(args=[{'visible': trace_visibilities}], label=key, method='update')\n    \n    # construct menu\n    active_button = 1\n    updatemenus = list([\n        dict(\n            active=active_button, \n            buttons=list(list(buttons.values())),\n            direction='down',\n            showactive=True,\n            pad={'r': 10, 't': 10},\n            x=0.1,\n            xanchor='left',\n            y=1.05,\n            yanchor='top' \n        ), \n    ])\n    node_traces[nonlabel_keys[active_button]]['visible'] = True\n    \n    layout = go.Layout(\n        title=title,\n        titlefont=dict(size=14),\n        showlegend=False,\n        hovermode='closest',\n        margin=dict(b=20,l=5,r=5,t=40),\n        annotations=[\n            dict(\n                text=\"Colormap Features\",\n                showarrow=False,\n                xref=\"paper\", \n                yref=\"paper\",\n                x=0.1,\n                y=1.08\n            )],\n        xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),\n        yaxis=dict(showgrid=False, zeroline=False, showticklabels=False),\n        updatemenus=updatemenus,\n    )\n    \n    fig = go.Figure(data=[edge_trace] + [node_traces[x] for x in nonlabel_keys], layout=layout)\n\n    iplot(fig, filename='class_hierarchy_graph')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e3e42a1309bd26489e915312ae678e461921eb12"},"cell_type":"code","source":"label_code_to_description.update({'/m/0bl9f': 'Entity'})\ng = make_graph(class_hierarchy, graph=None, prev_node_added=None, label_code_to_description=label_code_to_description, label_features=label_features)\ng = add_adjacency_to_nodes(g)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e98af9430ae1fc15d46823660231ba2a6eb870dd"},"cell_type":"markdown","source":"### Interactive Graphs"},{"metadata":{"trusted":true,"_uuid":"ff029ef67d1ba73abc01d5fcf5a310dba2c5d5e5"},"cell_type":"code","source":"p = get_node_coords(g, layout_type='layout_fruchterman_reingold')\nplot_tree(graph=g, node_coords=p, title='Bbox Class Hierarchy with Features from Bbox Train Dataset')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8f9e4122d3eb6e0813f66828e7da47d4de81fb50","scrolled":false},"cell_type":"code","source":"# tree-like layout\np = get_node_coords(g, layout_type='layout_reingold_tilford')\nplot_tree(graph=g, node_coords=p, title='Bbox Class Hierarchy with Features from Bbox Train Dataset')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a046ab8642f5f1a0e48767252b2d9221a87c8a1e"},"cell_type":"code","source":"p = get_node_coords(g, layout_type='layout_kamada_kawai')\nplot_tree(graph=g, node_coords=p, title='Bbox Class Hierarchy with Features from Bbox Train Dataset')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f7e658fa7bebb81bfbe9e28eda85e1f226bdfcfd"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f3793bfe46ce2ab515a54e4fe3d6b915c464fbe8"},"cell_type":"code","source":"tuning_counts['LabelName'] = tuning_counts['LabelAndDescription'].apply(lambda x: x.split(' - ')[0])\ntuning_counts.index = tuning_counts['LabelName']\ntuning_counts['ImageID_count_log10'] = np.log10(tuning_counts['ImageID_count'])\ntuning_counts['ImageID_nunique_log10'] = np.log10(tuning_counts['ImageID_nunique'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2077f8861c46df56d4cd96920dadbd7c09347973"},"cell_type":"code","source":"label_features = get_label_features(tuning_counts.drop(['LabelAndDescription'], axis='columns'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2e81d525dafa9ea7fdefcfc3969ae0405586adf0"},"cell_type":"code","source":"label_code_to_description.update({'/m/0bl9f': 'Entity'})\ng = make_graph(class_hierarchy, graph=None, prev_node_added=None, label_code_to_description=label_code_to_description, label_features=label_features)\ng = add_adjacency_to_nodes(g)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"873c02699d2003af6a0d3d36f586d0c2fab9288e"},"cell_type":"code","source":"p = get_node_coords(g, layout_type='layout_fruchterman_reingold')\nplot_tree(graph=g, node_coords=p, title='Bbox Class Hierarchy with Features from Tuning Dataset')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ecff7e184b468da4e4b4905e32db72fe1db0cb5b"},"cell_type":"code","source":"p = get_node_coords(g, layout_type='layout_kamada_kawai')\nplot_tree(graph=g, node_coords=p, title='Bbox Class Hierarchy with Features from Tuning Dataset')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cea804da7e0c75f1fbbcd5402661cd708e8f10a3"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"aec8bf472b8af11fa10847c352b92e6039531b54"},"cell_type":"code","source":"stage_1_attribs = pd.read_csv('../input/stage_1_attributions.csv', dtype=str)\nstage_1_attribs.head()\nprint(f\"{stage_1_attribs.image_id} image_ids with {} unique sources\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"55675772c5a63b28a3ba09ddc2fb5a5b6e7cb585"},"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}