{"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":"!pip install nb_black > /dev/null","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import json\nfrom os.path import basename\n\nfrom collections import defaultdict, Counter\nfrom glob import glob\n\nimport librosa\nimport librosa.display\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nfrom sklearn.preprocessing import MultiLabelBinarizer\n\nplt.style.use(\"ggplot\")\n\n%load_ext lab_black\n%load_ext autoreload\n%autoreload 2","metadata":{"execution":{"iopub.status.busy":"2022-04-22T11:03:05.032072Z","iopub.execute_input":"2022-04-22T11:03:05.032432Z","iopub.status.idle":"2022-04-22T11:03:06.345939Z","shell.execute_reply.started":"2022-04-22T11:03:05.032374Z","shell.execute_reply":"2022-04-22T11:03:06.345049Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def split(s, sep):\n    return s.split(sep) if s != \"\" else []","metadata":{"execution":{"iopub.status.busy":"2022-04-22T11:03:06.351811Z","iopub.execute_input":"2022-04-22T11:03:06.352104Z","iopub.status.idle":"2022-04-22T11:03:06.398690Z","shell.execute_reply.started":"2022-04-22T11:03:06.352063Z","shell.execute_reply":"2022-04-22T11:03:06.397891Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_soundscape_labels = pd.read_csv(\n    \"../input/birdclef-2021/train_soundscape_labels.csv\"\n)\ntrain_soundscape_labels[\"recording_id\"] = train_soundscape_labels.row_id.apply(\n    lambda x: int(x.split(\"_\")[0])\n)\ntrain_soundscape_labels[\"end_sec\"] = train_soundscape_labels.row_id.apply(\n    lambda x: int(x.split(\"_\")[2])\n)\ntrain_soundscape_labels[\"bird_call\"] = train_soundscape_labels.birds.apply(\n    lambda x: False if x == \"nocall\" else True\n)\ntrain_soundscape_labels[\"birds\"] = train_soundscape_labels.birds.apply(\n    lambda x: \"\" if x == \"nocall\" else x\n)\ntrain_soundscape_labels[\"birds\"] = train_soundscape_labels.birds.apply(\n    lambda x: json.dumps(split(x, \" \"))\n)\ntrain_soundscape_labels[\"bird_count\"] = train_soundscape_labels.birds.apply(\n    lambda x: len(eval(x))\n)\ntrain_soundscape_labels[\"birds\"] = train_soundscape_labels.birds.apply(\n    lambda x: eval(x)\n)\ntrain_soundscape_labels_org = train_soundscape_labels.copy()","metadata":{"execution":{"iopub.status.busy":"2022-04-22T11:03:25.433895Z","iopub.execute_input":"2022-04-22T11:03:25.434511Z","iopub.status.idle":"2022-04-22T11:03:25.550430Z","shell.execute_reply.started":"2022-04-22T11:03:25.434469Z","shell.execute_reply":"2022-04-22T11:03:25.549600Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Add filename to metadata","metadata":{}},{"cell_type":"code","source":"df = train_soundscape_labels_org.copy()\ndf[\"key\"] = df.recording_id.astype(str) + \"_\" + df.site\ndf[\"file_glob\"] = df.key + \"_*.ogg\"\n\nsiteaudio2filename = {}\n\nfor file_glob in df.file_glob.unique():\n    audio_path = glob(f\"../input/birdclef-2021/train_soundscapes/{file_glob}\")[0]\n    siteaudio2filename[file_glob[:-6]] = basename(audio_path)\n\ndf[\"filename\"] = df.key.apply(lambda key: siteaudio2filename[key])\ndf = df.drop([\"file_glob\"], axis=1)\n\ntrain_soundscape_labels = df.copy()\ntrain_soundscape_labels.to_csv(\"train_soundscape_labels_v2.csv\", index=False)\npd.read_csv(\"train_soundscape_labels_v2.csv\")","metadata":{"execution":{"iopub.status.busy":"2022-04-22T11:03:26.484439Z","iopub.execute_input":"2022-04-22T11:03:26.484723Z","iopub.status.idle":"2022-04-22T11:03:26.610547Z","shell.execute_reply.started":"2022-04-22T11:03:26.484695Z","shell.execute_reply":"2022-04-22T11:03:26.609654Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Speies appeared in each soundscapes","metadata":{}},{"cell_type":"code","source":"data = {\n    \"recording_id\": [],\n    \"species\": [],\n    \"site\": [],\n}\ngrp = train_soundscape_labels.groupby(\"recording_id\")\nfor i, (recording_id, df) in enumerate(grp):\n    species = list(set(df.birds.sum()))\n    data[\"recording_id\"].append(recording_id)\n    data[\"species\"].append(species)\n    data[\"site\"].append(df.site.max())\npd.DataFrame(data).sort_values(\"site\")","metadata":{"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Heat map of bird call","metadata":{}},{"cell_type":"code","source":"class cfg:\n    sample_rate = 32_000\n    n_fft = 2048\n    hop_length = 512\n    n_mels = 128\n    fmin = 0\n    fmax = 16_000\n    random_seed = -1","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def audio2img(audio_path, cfg, compression=\"pcen\"):\n    audio, _ = librosa.core.load(audio_path, sr=cfg.sample_rate, mono=True)\n    spec = librosa.feature.melspectrogram(\n        y=audio,\n        sr=cfg.sample_rate,\n        n_fft=cfg.n_fft,\n        hop_length=cfg.hop_length,\n        n_mels=cfg.n_mels,\n        fmin=cfg.fmin,\n        fmax=cfg.fmax,\n        power=2,\n    )\n    if compression == \"pcen\":\n        spec = librosa.pcen(\n            spec * (2**31),\n            time_constant=0.06,\n            eps=1e-6,\n            gain=0.8,\n            power=0.25,\n            bias=10,\n            sr=cfg.sample_rate,\n            hop_length=cfg.hop_length,\n        )\n    elif compression == \"log\":\n        spec = librosa.power_to_db(spec, ref=np.max)\n\n    return spec\n\n\ndef show_spec(spec, cfg, fig, ax):\n    mesh = librosa.display.specshow(\n        spec,\n        hop_length=cfg.hop_length,\n        sr=cfg.sample_rate,\n        fmin=cfg.fmin,\n        fmax=cfg.fmax,\n        x_axis=\"time\",\n        y_axis=\"mel\",\n        ax=ax,\n    )\n    fig.colorbar(mesh, ax=ax, format=\"%+2.0f dB\", location=\"right\")\n\n\ndef normalize_spec(spec, factor=1.5):\n    mean, std = spec.mean(), spec.std()\n    spec = spec.clip(mean - std * factor, mean + std * factor)\n    mean, std = spec.mean(), spec.std()\n    spec = (spec - mean) / std\n    return spec\n\n\ndef plot_spec(audio_path, cfg, g):\n    spec = audio2img(audio_path, cfg)\n    spec = normalize_spec(spec)\n\n    g.imshow(\n        spec[::-1, ...],  # frequency is reversed order\n        aspect=g.get_aspect(),\n        extent=g.get_xlim() + g.get_ylim(),\n        zorder=1,\n        cmap=\"magma\",\n    )","metadata":{"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_heatmap(df, ax):\n    mlb = MultiLabelBinarizer()\n    if df.bird_count.sum() != 0:\n        hmap = pd.DataFrame(mlb.fit_transform(df.birds), columns=mlb.classes_).T\n    else:\n        hmap = pd.DataFrame({\"no call\": [0] * 120}).T\n    g = sns.heatmap(\n        hmap,\n        cbar=False,\n        ax=ax,\n        cmap=\"plasma\",\n        linecolor=\"gray\",\n        lw=1,\n        zorder=2,\n        alpha=0.2,\n    )\n    return g\n\n\ndef plot_heatmap_of_soundscape(df):\n    df = df.copy()\n    grp = df.groupby(\"recording_id\")\n    n_soundscapes = len(grp)\n    fig, axes = plt.subplots(\n        n_soundscapes, 1, figsize=(16, n_soundscapes * 2), sharex=True, sharey=False\n    )\n    for i, (recording_id, df) in enumerate(grp):\n        ax = axes[i]\n        site = df.site.max()\n        audio_path = glob(\n            f\"../input/birdclef-2021/train_soundscapes/{recording_id}_{site}_*\"\n        )[0]\n\n        g = plot_heatmap(df, ax)\n        plot_spec(audio_path, cfg, g)\n\n        ax.set(title=f\"site:{site}, recording_id:{recording_id}\", xticks=[])\n    plt.tight_layout()","metadata":{"_kg_hide-input":true,"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Separate soundscape per site","metadata":{}},{"cell_type":"code","source":"df = train_soundscape_labels.copy()\nsites = df.site.unique()\nsite_dfs = [df.query(\"site == @site\") for site in sites]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_heatmap_of_soundscape(site_dfs[0])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_heatmap_of_soundscape(site_dfs[1])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"unique_species = set()\nfor item in train_soundscape_labels.itertuples():\n    for s in item.birds:\n        unique_species.add(s)\n\nprint(f\"total: {len(unique_species)} species\")\nprint(f\"species: [{', '.join(unique_species)}]\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.countplot(x=\"site\", data=train_soundscape_labels)\nCounter(train_soundscape_labels.site)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.countplot(x=\"bird_call\", data=train_soundscape_labels)\nCounter(train_soundscape_labels.bird_call)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.countplot(x=\"bird_count\", data=train_soundscape_labels)\nCounter(train_soundscape_labels.bird_count)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}