{"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":"from pathlib import Path\nfrom multiprocessing import Pool\nimport multiprocessing\n\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom mpl_toolkits.axes_grid1 import ImageGrid\nfrom PIL import Image, ImageStat\nfrom tqdm.notebook import tqdm\nimport seaborn as sns","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T23:28:04.397689Z","iopub.execute_input":"2022-03-07T23:28:04.399830Z","iopub.status.idle":"2022-03-07T23:28:05.625531Z","shell.execute_reply.started":"2022-03-07T23:28:04.399722Z","shell.execute_reply":"2022-03-07T23:28:05.624543Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"![Happywhale](https://happywhale.com/assets/images/home/antarctica.jpg)","metadata":{}},{"cell_type":"markdown","source":"# Intro 🎥\n\nIn this competition, we're trying to develop a model to match individual whales and dolphins from photographs.\n\nThe competition's data is provided by [Happywhale](https://happywhale.com). An organisation that uses photographs from the public to track marine life and understand the oceans.\n\nThere have been 2 previous Happywhale competitions, so there's no doubt going to be somethings to learn from them:\n\n* https://www.kaggle.com/c/humpback-whale-identification\n* https://www.kaggle.com/c/whale-categorization-playground\n\nIn this notebook, I explore the dataset provided by Happywhale.","metadata":{}},{"cell_type":"markdown","source":"# Top Solutions from Previous Competitions 🏆\n\nThe top solution from previous competitions are as follows:\n\n* [1st solution(classification) && code](https://www.kaggle.com/c/humpback-whale-identification/discussion/82366)\n* [2nd place code, end to end whale Identification model](https://www.kaggle.com/c/humpback-whale-identification/discussion/83885)\n* [3rd place solution with code: ArcFace](https://www.kaggle.com/c/humpback-whale-identification/discussion/82484)\n* [4th Place Solution: SIFT + Siamese](https://www.kaggle.com/c/humpback-whale-identification/discussion/82356)\n* [5th solution blog post + code](https://www.kaggle.com/c/humpback-whale-identification/discussion/82369)","metadata":{}},{"cell_type":"markdown","source":"<a id=\"load-dataset\"></a>\n\n# Load and Preprocess Dataset ⌛","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv('../input/happy-whale-and-dolphin/train.csv')\ntest_df = pd.read_csv('../input/happy-whale-and-dolphin/sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:16:57.971041Z","iopub.execute_input":"2022-03-07T13:16:57.971366Z","iopub.status.idle":"2022-03-07T13:16:58.079193Z","shell.execute_reply.started":"2022-03-07T13:16:57.971332Z","shell.execute_reply":"2022-03-07T13:16:58.077957Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SAMPLE = None","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:16:58.081731Z","iopub.execute_input":"2022-03-07T13:16:58.082052Z","iopub.status.idle":"2022-03-07T13:16:58.090178Z","shell.execute_reply.started":"2022-03-07T13:16:58.082012Z","shell.execute_reply":"2022-03-07T13:16:58.089132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if SAMPLE:\n    train_df = train_df.sample(SAMPLE)\n    test_df =  test_df.sample(SAMPLE)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:16:58.091578Z","iopub.execute_input":"2022-03-07T13:16:58.091867Z","iopub.status.idle":"2022-03-07T13:16:58.105794Z","shell.execute_reply.started":"2022-03-07T13:16:58.091836Z","shell.execute_reply":"2022-03-07T13:16:58.104663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:16:58.107611Z","iopub.execute_input":"2022-03-07T13:16:58.108635Z","iopub.status.idle":"2022-03-07T13:16:58.123319Z","shell.execute_reply.started":"2022-03-07T13:16:58.108577Z","shell.execute_reply":"2022-03-07T13:16:58.12258Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I'm going to calculate a bunch of stats about the images which will make the analysis quick later on.\n\nThe preprocessing is saved to a file so we can load it again later.","metadata":{}},{"cell_type":"code","source":"from multiprocessing import Pool\nfrom functools import partial\n\ndef _do_image(image_id, dataset):\n    image_path = Path(f'../input/happy-whale-and-dolphin/{dataset}_images')/image_id\n\n    image = Image.open(image_path)\n\n    width, height = image.size\n    mode = image.mode\n    stat = ImageStat.Stat(image)\n    min_max_channels = image.getextrema()\n\n    if len(min_max_channels) == 2:\n        min_0, max_0 = min_max_channels[0], min_max_channels[1]\n        min_1 = max_1 = min_2 = max_2 = 0\n        avg_0, avg_1, avg_2 = stat.mean[0], stat.mean[0], stat.mean[0]\n        std_0, std_1, std_2 = stat.stddev[0], stat.stddev[0], stat.stddev[0]\n    else:\n        min_0, max_0 = min_max_channels[0][0], min_max_channels[0][1]\n        min_1, max_1 = min_max_channels[1][0], min_max_channels[1][1]\n        min_2, max_2 = min_max_channels[2][0], min_max_channels[2][1]\n        avg_0, avg_1, avg_2 = stat.mean\n        std_0, std_1, std_2 = stat.stddev\n\n    area = (width * height) / 1_000_000\n    mean = (avg_0 + avg_1 + avg_2) / 3\n    \n    return (\n        image_id, width, height, area, mean, mode,\n        min_0, max_0, min_1, max_1, min_2, max_2,\n        avg_0, avg_1, avg_2, std_0, std_1, std_2\n    )\n\ndef get_image_stats(image_ids, dataset):\n    with Pool(multiprocessing.cpu_count()) as p:\n        func = partial(_do_image, dataset=dataset)\n        output = list(tqdm(p.imap(func, image_ids), total=len(image_ids)))\n\n    df = pd.DataFrame(output, columns=[\n        'image', 'width', 'height', 'area', 'mean_px', 'mode',\n        'min_px_0', 'max_px_0', 'min_px_1', 'max_px_1', 'min_px_2', 'max_px_2',\n        'avg_px_0', 'avg_px_1', 'avg_px_2', 'std_px_0', 'std_px_1', 'std_px_2'\n    ])\n    \n    return df","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:16:58.126813Z","iopub.execute_input":"2022-03-07T13:16:58.127564Z","iopub.status.idle":"2022-03-07T13:16:58.142547Z","shell.execute_reply.started":"2022-03-07T13:16:58.127517Z","shell.execute_reply":"2022-03-07T13:16:58.141877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_image_stats = get_image_stats(train_df.image, 'train')\ntest_image_stats = get_image_stats(test_df.image, 'test')","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:16:58.144099Z","iopub.execute_input":"2022-03-07T13:16:58.144692Z","iopub.status.idle":"2022-03-07T13:18:44.075875Z","shell.execute_reply.started":"2022-03-07T13:16:58.144648Z","shell.execute_reply":"2022-03-07T13:18:44.074743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df_stats = train_df.merge(train_image_stats, on='image')\ntest_df_stats = test_df.merge(test_image_stats, on='image')","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:07.198468Z","iopub.execute_input":"2022-03-07T13:19:07.198773Z","iopub.status.idle":"2022-03-07T13:19:07.216247Z","shell.execute_reply.started":"2022-03-07T13:19:07.198734Z","shell.execute_reply":"2022-03-07T13:19:07.215482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df_stats.to_csv('train_stats.csv', index=False)\ntest_df_stats.to_csv('test_stats.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:07.509179Z","iopub.execute_input":"2022-03-07T13:19:07.509962Z","iopub.status.idle":"2022-03-07T13:19:07.566024Z","shell.execute_reply.started":"2022-03-07T13:19:07.509918Z","shell.execute_reply":"2022-03-07T13:19:07.565134Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df_stats.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:07.681596Z","iopub.execute_input":"2022-03-07T13:19:07.682184Z","iopub.status.idle":"2022-03-07T13:19:07.702249Z","shell.execute_reply.started":"2022-03-07T13:19:07.682146Z","shell.execute_reply":"2022-03-07T13:19:07.701594Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"dataset-size\"></a>\n\n# Dataset Sizes 📏","metadata":{}},{"cell_type":"code","source":"size_df = pd.DataFrame([(len(train_df_stats), 'train'), (len(test_df_stats), 'test')], columns=['size', 'dataset'])\nax = sns.barplot(x=size_df.dataset, y=size_df['size'])\nax.bar_label(ax.containers[0])\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:19:07.970893Z","iopub.execute_input":"2022-03-07T13:19:07.971905Z","iopub.status.idle":"2022-03-07T13:19:08.1412Z","shell.execute_reply.started":"2022-03-07T13:19:07.971863Z","shell.execute_reply":"2022-03-07T13:19:08.140178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Train set size: {len(train_df_stats)}, Test set size: {len(test_df_stats)}')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:19:08.142784Z","iopub.execute_input":"2022-03-07T13:19:08.143036Z","iopub.status.idle":"2022-03-07T13:19:08.148085Z","shell.execute_reply.started":"2022-03-07T13:19:08.143005Z","shell.execute_reply":"2022-03-07T13:19:08.147154Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Metadata Columns 🏛️","metadata":{}},{"cell_type":"code","source":"train_df.columns","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:19:08.464034Z","iopub.execute_input":"2022-03-07T13:19:08.465003Z","iopub.status.idle":"2022-03-07T13:19:08.471095Z","shell.execute_reply.started":"2022-03-07T13:19:08.46496Z","shell.execute_reply":"2022-03-07T13:19:08.470329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"species-column\"></a>\n\n# Species Column Stats 🐋","metadata":{}},{"cell_type":"markdown","source":"## Unique species before cleaning","metadata":{}},{"cell_type":"code","source":"train_df_stats.species.unique()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:19:09.83865Z","iopub.execute_input":"2022-03-07T13:19:09.839722Z","iopub.status.idle":"2022-03-07T13:19:09.846511Z","shell.execute_reply.started":"2022-03-07T13:19:09.839666Z","shell.execute_reply":"2022-03-07T13:19:09.845927Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df_stats.species.nunique()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:19:10.008221Z","iopub.execute_input":"2022-03-07T13:19:10.008564Z","iopub.status.idle":"2022-03-07T13:19:10.015167Z","shell.execute_reply.started":"2022-03-07T13:19:10.008524Z","shell.execute_reply":"2022-03-07T13:19:10.01433Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"specie-label-cleaning\"></a>\n\n## Specie label cleaning","metadata":{}},{"cell_type":"markdown","source":"[This](https://www.kaggle.com/kwentar/what-about-species) notebook has researched the labels that appear to be misspelled. So I'll use the good work to clean up the species labels.","metadata":{}},{"cell_type":"code","source":"train_df_stats.species.replace({\n    \"globis\": \"short_finned_pilot_whale\",\n    \"pilot_whale\": \"short_finned_pilot_whale\",\n    \"kiler_whale\": \"killer_whale\",\n    \"bottlenose_dolpin\": \"bottlenose_dolphin\",\n    \"beluga\": \"beluga_whale\"\n}, inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:10.724273Z","iopub.execute_input":"2022-03-07T13:19:10.724599Z","iopub.status.idle":"2022-03-07T13:19:10.731258Z","shell.execute_reply.started":"2022-03-07T13:19:10.724564Z","shell.execute_reply":"2022-03-07T13:19:10.73065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Unique species after cleaning","metadata":{}},{"cell_type":"code","source":"train_df_stats.species.nunique()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:11.507111Z","iopub.execute_input":"2022-03-07T13:19:11.507831Z","iopub.status.idle":"2022-03-07T13:19:11.514633Z","shell.execute_reply.started":"2022-03-07T13:19:11.507791Z","shell.execute_reply":"2022-03-07T13:19:11.513797Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"<a id=\"species-per-class\"></a>\n\n## Species Per Class","metadata":{}},{"cell_type":"markdown","source":"In another notebook, I train a 94% accurate model to predict the test set species distribution.","metadata":{}},{"cell_type":"code","source":"test_species = pd.read_csv('../input/happywhale-what-species-are-in-the-test-set/test_species.csv')","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:12.999502Z","iopub.execute_input":"2022-03-07T13:19:12.99983Z","iopub.status.idle":"2022-03-07T13:19:13.036368Z","shell.execute_reply.started":"2022-03-07T13:19:12.999793Z","shell.execute_reply":"2022-03-07T13:19:13.035506Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_species.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:13.153012Z","iopub.execute_input":"2022-03-07T13:19:13.153311Z","iopub.status.idle":"2022-03-07T13:19:13.164187Z","shell.execute_reply.started":"2022-03-07T13:19:13.153278Z","shell.execute_reply":"2022-03-07T13:19:13.163425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_val_count = train_df_stats.species.value_counts()\ntest_val_count = test_species.species_pred.value_counts()\n\nfig, (ax, ax2) = plt.subplots(ncols=2, figsize=(15,8))\n\nchart = sns.barplot(x=train_val_count.index, y=train_val_count.values, ax=ax)\nax.set_title('Train species dist')\nax.set_xticklabels(ax.get_xticklabels(), rotation=90)\nchart = sns.barplot(x=test_val_count.index, y=test_val_count.values, ax=ax2)\nax2.set_title('Test species dist (estimate)')\nax2.set_xticklabels(ax2.get_xticklabels(), rotation=90)\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:19:13.298013Z","iopub.execute_input":"2022-03-07T13:19:13.298826Z","iopub.status.idle":"2022-03-07T13:19:14.146867Z","shell.execute_reply.started":"2022-03-07T13:19:13.298781Z","shell.execute_reply":"2022-03-07T13:19:14.145992Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I'll add a column that tells us whether it's a whale or dolphin.\n\nIt seems that the species is suffixed with the base breed.","metadata":{}},{"cell_type":"markdown","source":"<a id=\"base-specie-label\"></a>\n\n### Add base species label","metadata":{}},{"cell_type":"code","source":"train_df_stats['base_species'] = np.where(train_df.species.str.endswith('dolphin'), 'dolphin', 'whale')","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-03-07T13:19:14.491073Z","iopub.execute_input":"2022-03-07T13:19:14.491736Z","iopub.status.idle":"2022-03-07T13:19:14.498095Z","shell.execute_reply.started":"2022-03-07T13:19:14.491701Z","shell.execute_reply":"2022-03-07T13:19:14.497375Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df_stats[train_df_stats['base_species'] == 'whale'].species.unique()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:14.637896Z","iopub.execute_input":"2022-03-07T13:19:14.638361Z","iopub.status.idle":"2022-03-07T13:19:14.64776Z","shell.execute_reply.started":"2022-03-07T13:19:14.638312Z","shell.execute_reply":"2022-03-07T13:19:14.646893Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df_stats[train_df_stats['base_species'] == 'dolphin'].species.unique()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:14.787811Z","iopub.execute_input":"2022-03-07T13:19:14.788587Z","iopub.status.idle":"2022-03-07T13:19:14.795789Z","shell.execute_reply.started":"2022-03-07T13:19:14.788551Z","shell.execute_reply":"2022-03-07T13:19:14.795098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Apparently False Killer Whale and Killer Whale are actually considered dolphins!\n\nhttps://en.wikipedia.org/wiki/Orca\nhttps://en.wikipedia.org/wiki/False_killer_whale\n\nFor now, I will leave them in the whale class. They certainly look like Whales to me!","metadata":{}},{"cell_type":"markdown","source":"<a id=\"dolphins-vs-whales\"></a>\n\n## How Many Dolphins vs Whales?","metadata":{}},{"cell_type":"code","source":"whale_count = np.sum(train_df_stats.base_species == 'whale')\ndolphin_count = np.sum(train_df_stats.base_species == 'dolphin')\n\ncount_df = pd.DataFrame([(whale_count, 'whale'), (dolphin_count, 'dolphin')], columns=['number', 'species'])\nax = sns.barplot(x=count_df.species, y=count_df.number)\nax.bar_label(ax.containers[0])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:25:36.90009Z","iopub.execute_input":"2022-03-07T13:25:36.900551Z","iopub.status.idle":"2022-03-07T13:25:37.100332Z","shell.execute_reply.started":"2022-03-07T13:25:36.900504Z","shell.execute_reply":"2022-03-07T13:25:37.099214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"how-many-unique\"></a>\n\n# Individual Id Column Stats 😎\n\n## How many unique?","metadata":{}},{"cell_type":"code","source":"train_df_stats.individual_id.nunique()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:17.926098Z","iopub.execute_input":"2022-03-07T13:19:17.927045Z","iopub.status.idle":"2022-03-07T13:19:17.935408Z","shell.execute_reply.started":"2022-03-07T13:19:17.926982Z","shell.execute_reply":"2022-03-07T13:19:17.934533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"how-many-individual-whales-vs-dolphins\"></a>\n## How many unique whales vs dolphins?","metadata":{}},{"cell_type":"code","source":"nunique_whales = train_df_stats[train_df_stats.base_species == 'whale'].individual_id.nunique()\nnunique_dolphins = train_df_stats[train_df_stats.base_species == 'dolphin'].individual_id.nunique()\n\nunique_df = pd.DataFrame([(nunique_whales, 'whale'), (nunique_dolphins, 'dolphin')], columns=['unique_number', 'species'])\nax = sns.barplot(x=unique_df.species, y=unique_df.unique_number)\nax.bar_label(ax.containers[0])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:19:50.034361Z","iopub.execute_input":"2022-03-07T13:19:50.035383Z","iopub.status.idle":"2022-03-07T13:19:50.214308Z","shell.execute_reply.started":"2022-03-07T13:19:50.035329Z","shell.execute_reply":"2022-03-07T13:19:50.213489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"unique-id-distribution\"></a>\n\n## Photos per individual id?","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots()\nmost_common = train_df_stats.individual_id.sample(1000).value_counts()[:125]\nmost_common.plot(kind='bar', figsize=(20,8), title='Individual ids', ax=ax)\nax.set_xticklabels([i[:5]+'...' for i in most_common.index])\nplt.show()\n\nid_counts = pd.DataFrame(train_df_stats.individual_id.value_counts())","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:20:33.995271Z","iopub.execute_input":"2022-03-07T13:20:33.996076Z","iopub.status.idle":"2022-03-07T13:20:35.719472Z","shell.execute_reply.started":"2022-03-07T13:20:33.996032Z","shell.execute_reply":"2022-03-07T13:20:35.718528Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Clearly there's a bunch of examples of whales/dolphins with only one example. Let's find those.","metadata":{}},{"cell_type":"markdown","source":"<a id=\"unique-id-only-one\"></a>\n\n## How many id examples have only one example in the train set?","metadata":{}},{"cell_type":"code","source":"len(id_counts[id_counts.individual_id == 1])","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:21:49.399998Z","iopub.execute_input":"2022-03-07T13:21:49.400314Z","iopub.status.idle":"2022-03-07T13:21:49.408191Z","shell.execute_reply.started":"2022-03-07T13:21:49.400283Z","shell.execute_reply":"2022-03-07T13:21:49.407522Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Seems like a lot!","metadata":{}},{"cell_type":"markdown","source":"<a id=\"visualise-examples-of-species\"></a>\n\n# Visualise Images 📷","metadata":{}},{"cell_type":"code","source":"def image_grid(images, nrows_ncols, title=None, figsize=(16, 5)):\n    fig = plt.figure(figsize=figsize)\n    if title:\n        plt.title(title)\n\n    grid = ImageGrid(fig, 111, nrows_ncols=nrows_ncols, axes_pad=0.1)\n\n    for ax, im in zip(grid, images):\n        ax.imshow(im)\n\n    plt.show()\n\n\ndef load_images(image_ids, resize=(128, 128)):\n    output = []\n    for i in image_ids:\n        img = Image.open(Path('../input/happy-whale-and-dolphin/train_images')/i)\n        if resize:\n            img = img.resize(resize)\n            \n        output.append(img)\n        \n    return output\n\nimage_ids = list(train_df_stats.sample(15).image)\nimages = load_images(image_ids)\nimage_grid(images, nrows_ncols=(3, 5), figsize=(20, 15))","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:23:02.205941Z","iopub.execute_input":"2022-03-07T13:23:02.206347Z","iopub.status.idle":"2022-03-07T13:23:06.469548Z","shell.execute_reply.started":"2022-03-07T13:23:02.206316Z","shell.execute_reply":"2022-03-07T13:23:06.468832Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Whales","metadata":{}},{"cell_type":"code","source":"whale_ids = list(train_df_stats.query('base_species == \"whale\"').sample(10).image)\nwhale_images = load_images(whale_ids)\nimage_grid(whale_images, nrows_ncols=(2, 5), figsize=(18, 8), title='Whale images')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:06.470945Z","iopub.execute_input":"2022-03-07T13:23:06.471286Z","iopub.status.idle":"2022-03-07T13:23:08.912119Z","shell.execute_reply.started":"2022-03-07T13:23:06.471257Z","shell.execute_reply":"2022-03-07T13:23:08.911203Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dolphins","metadata":{}},{"cell_type":"code","source":"dolphin_ids = list(train_df_stats.query('base_species == \"dolphin\"').sample(10).image)\ndolphin_images = load_images(dolphin_ids)\nimage_grid(dolphin_images, nrows_ncols=(2, 5), figsize=(18, 8), title='Dolphin images')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:08.913246Z","iopub.execute_input":"2022-03-07T13:23:08.913484Z","iopub.status.idle":"2022-03-07T13:23:11.711871Z","shell.execute_reply.started":"2022-03-07T13:23:08.913443Z","shell.execute_reply":"2022-03-07T13:23:11.710914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Examples of Top 5 Species","metadata":{}},{"cell_type":"markdown","source":"## Beluga Whale","metadata":{}},{"cell_type":"code","source":"image_ids = list(train_df_stats.query('species == \"beluga_whale\"').sample(10).image)\nimages = load_images(image_ids)\nimage_grid(images, nrows_ncols=(2, 5), figsize=(18, 8), title='Beluga images')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:11.713746Z","iopub.execute_input":"2022-03-07T13:23:11.71399Z","iopub.status.idle":"2022-03-07T13:23:13.555385Z","shell.execute_reply.started":"2022-03-07T13:23:11.71396Z","shell.execute_reply":"2022-03-07T13:23:13.554615Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Bottlenose Dolphin","metadata":{}},{"cell_type":"code","source":"image_ids = list(train_df_stats.query('species == \"bottlenose_dolphin\"').sample(10).image)\nimages = load_images(image_ids)\nimage_grid(images, nrows_ncols=(2, 5), figsize=(18, 8), title='Bottlenose Dolphin images')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:13.556677Z","iopub.execute_input":"2022-03-07T13:23:13.557497Z","iopub.status.idle":"2022-03-07T13:23:17.043117Z","shell.execute_reply.started":"2022-03-07T13:23:13.557424Z","shell.execute_reply":"2022-03-07T13:23:17.042299Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Humpback Whale","metadata":{}},{"cell_type":"code","source":"image_ids = list(train_df_stats.query('species == \"humpback_whale\"').sample(10).image)\nimages = load_images(image_ids)\nimage_grid(images, nrows_ncols=(2, 5), figsize=(18, 8), title='Humpback Whale images')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:17.044421Z","iopub.execute_input":"2022-03-07T13:23:17.045179Z","iopub.status.idle":"2022-03-07T13:23:19.76594Z","shell.execute_reply.started":"2022-03-07T13:23:17.045141Z","shell.execute_reply":"2022-03-07T13:23:19.764931Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Blue Whale","metadata":{}},{"cell_type":"code","source":"image_ids = list(train_df_stats.query('species == \"blue_whale\"').sample(10).image)\nimages = load_images(image_ids)\nimage_grid(images, nrows_ncols=(2, 5), figsize=(18, 8), title='Blue Whale images')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:19.767635Z","iopub.execute_input":"2022-03-07T13:23:19.767931Z","iopub.status.idle":"2022-03-07T13:23:22.188828Z","shell.execute_reply.started":"2022-03-07T13:23:19.767889Z","shell.execute_reply":"2022-03-07T13:23:22.187955Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The labels here seem like they might be a leak. Something to investigate!","metadata":{}},{"cell_type":"markdown","source":"## Killerwhale","metadata":{}},{"cell_type":"code","source":"image_ids = list(train_df_stats.query('species == \"killer_whale\"').sample(10).image)\nimages = load_images(image_ids)\nimage_grid(images, nrows_ncols=(2, 5), figsize=(18, 8), title='Killer Whale images')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:22.190032Z","iopub.execute_input":"2022-03-07T13:23:22.190351Z","iopub.status.idle":"2022-03-07T13:23:25.877064Z","shell.execute_reply.started":"2022-03-07T13:23:22.190313Z","shell.execute_reply":"2022-03-07T13:23:25.876197Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## One Off Whales","metadata":{}},{"cell_type":"code","source":"ind_id_set = set(id_counts[id_counts.individual_id == 1].index)\nwhale_ids = list(train_df_stats[train_df_stats.individual_id.isin(ind_id_set)].sample(10).image)\nwhale_images = load_images(whale_ids)\nimage_grid(whale_images, nrows_ncols=(2, 5), figsize=(18, 8))","metadata":{"execution":{"iopub.status.busy":"2022-03-07T13:23:25.878201Z","iopub.execute_input":"2022-03-07T13:23:25.878437Z","iopub.status.idle":"2022-03-07T13:23:27.955644Z","shell.execute_reply.started":"2022-03-07T13:23:25.878407Z","shell.execute_reply":"2022-03-07T13:23:27.954941Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"My takeaways from that:\n  * The dataset is mostly fin images.\n  * There appear to be a lot of black and white images.\n  * Some of the images have text that should be investigated for leaks.","metadata":{}},{"cell_type":"markdown","source":"<a id=\"how-big\"></a>\n\n# Image Size Stats ⚖️","metadata":{}},{"cell_type":"markdown","source":"## Train vs Test Distribution","metadata":{}},{"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 5))\nfig.suptitle('Image sizes across datasets')\nax1.hist(train_df_stats.width, alpha=0.5, label='Train')\nax1.hist(test_df_stats.width, alpha=0.5, label='Test')\nax1.set_title('Width')\nax1.legend(loc='upper left')\n\nax2.hist(train_df_stats.height, alpha=0.5, label='Train')\nax2.hist(test_df_stats.height, alpha=0.5, label='Test')\nax2.set_title('Height')\nax2.legend(loc='upper left')\n\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:28.13735Z","iopub.execute_input":"2022-03-07T13:23:28.137594Z","iopub.status.idle":"2022-03-07T13:23:28.548005Z","shell.execute_reply.started":"2022-03-07T13:23:28.137564Z","shell.execute_reply":"2022-03-07T13:23:28.547036Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Both datasets appear to have quite evenly distributed image sizes.","metadata":{}},{"cell_type":"markdown","source":"## Images Size Distribution Per Species\n\nThe idea of this plot came from [this notebook](https://www.kaggle.com/andradaolteanu/whales-dolphins-effnet-embedding-cos-distance).","metadata":{}},{"cell_type":"markdown","source":"### Width by Species","metadata":{}},{"cell_type":"code","source":"data = train_df_stats[[\"species\", \"width\"]]\n\nplt.figure(figsize=(15, 5))\nsns.violinplot(data=data, x=\"species\", y=\"width\", cut=0)\nax = plt.gca()\nax.set_xlabel(\"\")\nax.set_ylabel(\"Width\", size = 13, weight='bold')\nax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right')\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:28.549514Z","iopub.execute_input":"2022-03-07T13:23:28.549903Z","iopub.status.idle":"2022-03-07T13:23:29.275793Z","shell.execute_reply.started":"2022-03-07T13:23:28.549857Z","shell.execute_reply":"2022-03-07T13:23:29.274871Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Height by Species","metadata":{}},{"cell_type":"code","source":"data = train_df_stats[[\"species\", \"height\"]]\n\nplt.figure(figsize=(15, 5))\nsns.violinplot(data=data, x=\"species\", y=\"height\", cut=0)\nax = plt.gca()\nax.set_title(\"Height\", size = 15, weight='bold')\nax.set_xlabel(\"\")\nax.set_ylabel(\"Height\", size = 13, weight='bold')\nax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right')\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:29.277217Z","iopub.execute_input":"2022-03-07T13:23:29.277965Z","iopub.status.idle":"2022-03-07T13:23:30.190345Z","shell.execute_reply.started":"2022-03-07T13:23:29.277917Z","shell.execute_reply":"2022-03-07T13:23:30.189475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Largest and Smallest Examples 🤏","metadata":{"execution":{"iopub.status.busy":"2022-02-20T06:00:14.399942Z","iopub.execute_input":"2022-02-20T06:00:14.401045Z","iopub.status.idle":"2022-02-20T06:00:14.406172Z","shell.execute_reply.started":"2022-02-20T06:00:14.400981Z","shell.execute_reply":"2022-02-20T06:00:14.40535Z"}}},{"cell_type":"markdown","source":"## Largest","metadata":{}},{"cell_type":"code","source":"large_images = train_df_stats[['image', 'species', 'width', 'height', 'area']].sort_values(by='area', ascending=False).head(10)\nlarge_images","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:30.191698Z","iopub.execute_input":"2022-03-07T13:23:30.192005Z","iopub.status.idle":"2022-03-07T13:23:30.209064Z","shell.execute_reply.started":"2022-03-07T13:23:30.191972Z","shell.execute_reply":"2022-03-07T13:23:30.208423Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_ids = list(large_images.image)\nimages = load_images(image_ids, resize=False)\nimage_grid(images, nrows_ncols=(2, 5), figsize=(40, 18))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:30.209966Z","iopub.execute_input":"2022-03-07T13:23:30.210489Z","iopub.status.idle":"2022-03-07T13:23:43.317047Z","shell.execute_reply.started":"2022-03-07T13:23:30.210446Z","shell.execute_reply":"2022-03-07T13:23:43.316338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Smallest\n\nThere appears to be a few really tiny images! Let's see those.","metadata":{}},{"cell_type":"code","source":"tiny_images = train_df_stats[['image', 'species', 'width', 'height', 'area']].sort_values(by='area').head(10)\ntiny_images","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:43.318125Z","iopub.execute_input":"2022-03-07T13:23:43.319077Z","iopub.status.idle":"2022-03-07T13:23:43.334919Z","shell.execute_reply.started":"2022-03-07T13:23:43.319041Z","shell.execute_reply":"2022-03-07T13:23:43.333972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"whale_ids = list(tiny_images.image)\nwhale_images = load_images(whale_ids, resize=False)\nimage_grid(whale_images, nrows_ncols=(2, 5), figsize=(40, 18))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:43.336274Z","iopub.execute_input":"2022-03-07T13:23:43.337027Z","iopub.status.idle":"2022-03-07T13:23:45.178605Z","shell.execute_reply.started":"2022-03-07T13:23:43.336981Z","shell.execute_reply":"2022-03-07T13:23:45.177751Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There appears to be a few grayscale images. Let's see how many.","metadata":{}},{"cell_type":"markdown","source":"<a id=\"rgb-vs-grayscale\"></a>\n\n# RGB vs Grayscale? 🎨 ","metadata":{}},{"cell_type":"code","source":"val_count = train_df_stats['mode'].value_counts()\nplt.figure(figsize=(15,8))\nplt.title('RGB vs Grayscale')\nax = sns.barplot(y=val_count.values, x=val_count.index)\nax.bar_label(ax.containers[0])\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:45.179952Z","iopub.execute_input":"2022-03-07T13:23:45.180163Z","iopub.status.idle":"2022-03-07T13:23:45.362751Z","shell.execute_reply.started":"2022-03-07T13:23:45.180136Z","shell.execute_reply":"2022-03-07T13:23:45.361877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Greyscale Examples ⚪","metadata":{}},{"cell_type":"code","source":"grey = train_df_stats[train_df_stats['mode'] != 'RGB']\nimage_ids = list(grey.image)\nimages = load_images(image_ids, resize=False)\nimage_grid(images, nrows_ncols=(4, 5), figsize=(40, 18))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:45.363966Z","iopub.execute_input":"2022-03-07T13:23:45.364203Z","iopub.status.idle":"2022-03-07T13:23:49.221294Z","shell.execute_reply.started":"2022-03-07T13:23:45.364173Z","shell.execute_reply":"2022-03-07T13:23:49.220589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Grayscale Examples by Species","metadata":{}},{"cell_type":"code","source":"grey.species.value_counts().plot.bar(title='Species with grayscale examples')\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:49.222239Z","iopub.execute_input":"2022-03-07T13:23:49.222931Z","iopub.status.idle":"2022-03-07T13:23:49.407778Z","shell.execute_reply.started":"2022-03-07T13:23:49.222897Z","shell.execute_reply":"2022-03-07T13:23:49.406803Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"avg-pixels\"></a>\n# Pixel Brightness 🔆","metadata":{}},{"cell_type":"markdown","source":"## Per Set Distribution","metadata":{}},{"cell_type":"code","source":"train_color_only = train_df_stats[train_df_stats['mode'] == 'RGB']\ntest_color_only = test_df_stats[test_df_stats['mode'] == 'RGB']","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:49.408935Z","iopub.execute_input":"2022-03-07T13:23:49.409147Z","iopub.status.idle":"2022-03-07T13:23:49.41684Z","shell.execute_reply.started":"2022-03-07T13:23:49.409121Z","shell.execute_reply":"2022-03-07T13:23:49.415863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 5))\nfig.suptitle('Avg pixel sizes across channels')\n\nax1.hist(train_color_only.avg_px_0, alpha=0.5, label='R', color='r')\nax1.hist(train_color_only.avg_px_1, alpha=0.5, label='G', color='g')\nax1.hist(train_color_only.avg_px_2, alpha=0.5, label='B', color='b')\nax1.set_title('Train')\nax1.legend(loc='upper left')\n\nax2.hist(test_color_only.avg_px_0, alpha=0.5, label='R', color='r')\nax2.hist(test_color_only.avg_px_1, alpha=0.5, label='G', color='g')\nax2.hist(test_color_only.avg_px_2, alpha=0.5, label='B', color='b')\nax2.set_title('Test')\nax2.legend(loc='upper left')\n\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:49.418523Z","iopub.execute_input":"2022-03-07T13:23:49.418742Z","iopub.status.idle":"2022-03-07T13:23:49.848409Z","shell.execute_reply.started":"2022-03-07T13:23:49.418715Z","shell.execute_reply":"2022-03-07T13:23:49.847532Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Darkest Images ⚫","metadata":{}},{"cell_type":"code","source":"filtered = train_df_stats.sort_values(by='mean_px', ascending=True).head(15)\nimage_ids = list(filtered.image)\nimages = load_images(image_ids, resize=False)\nimage_grid(images, nrows_ncols=(2, 5), figsize=(18, 40))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:49.84979Z","iopub.execute_input":"2022-03-07T13:23:49.850026Z","iopub.status.idle":"2022-03-07T13:23:55.441242Z","shell.execute_reply.started":"2022-03-07T13:23:49.849998Z","shell.execute_reply":"2022-03-07T13:23:55.440633Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Lightest Images 💡","metadata":{}},{"cell_type":"code","source":"filtered = train_df_stats.sort_values(by='mean_px', ascending=False).head(15)\nimage_ids = list(filtered.image)\nimages = load_images(image_ids, resize=False)\nimage_grid(images, nrows_ncols=(2, 5), figsize=(18, 40))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-07T13:23:55.442504Z","iopub.execute_input":"2022-03-07T13:23:55.44288Z","iopub.status.idle":"2022-03-07T13:24:03.474121Z","shell.execute_reply.started":"2022-03-07T13:23:55.442832Z","shell.execute_reply":"2022-03-07T13:24:03.472881Z"},"trusted":true},"execution_count":null,"outputs":[]}]}