{"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":"import numpy as np\nimport pandas as pd\nimport os\nimport matplotlib.pyplot as plt\nimport soundfile as sf\nimport librosa\nimport librosa.display\nimport IPython.display as display\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport IPython.display as ipd\nimport librosa\nimport librosa.display\nimport os\nfrom tqdm import tqdm\nimport sklearn\nimport seaborn as sns\nimport plotly.express as px\n\n\nimport geopandas as gpd\nfrom shapely.geometry import Point, Polygon\n\nfrom sklearn.model_selection import train_test_split\n\nfrom keras.utils import Sequence\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Dropout, Flatten, Conv1D, MaxPool1D, BatchNormalization\nfrom keras.optimizers import RMSprop,Adam\nfrom keras.applications import VGG19, VGG16, ResNet50\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path = '/kaggle/input/birdclef-2021/'\nos.listdir(path)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_ogg_file(path, file):\n    \"\"\" Read ogg audio file and return numpay array and samplerate\"\"\"\n    \n    data, samplerate = sf.read(path+file)\n    return data, samplerate\n\n\ndef plot_audio_file(data, samplerate):\n    \"\"\" Plot the audio data\"\"\"\n    \n    sr = samplerate\n    fig = plt.figure(figsize=(8, 4))\n    x = range(len(data))\n    y = data\n    plt.plot(x, y)\n    plt.plot(x, y, color='red')\n    plt.legend(loc='upper center')\n    plt.grid()\n    \n    \ndef plot_spectrogram(data, samplerate):\n    \"\"\" Plot spectrogram with mel scaling \"\"\"\n    \n    sr = samplerate\n    spectrogram = librosa.feature.melspectrogram(data, sr=sr)\n    log_spectrogram = librosa.power_to_db(spectrogram, ref=np.max)\n    librosa.display.specshow(log_spectrogram, sr=sr, x_axis='time', y_axis='mel')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_labels = pd.read_csv(path + 'train_soundscape_labels.csv')\ntrain_meta = pd.read_csv(path + 'train_metadata.csv')\ntest_data = pd.read_csv(path + 'test.csv')\nsamp_subm = pd.read_csv(path + 'sample_submission.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Number train label samples:', len(train_labels))\nprint('Number train meta samples:', len(train_meta))\nprint('Number train short folder:', len(os.listdir(path+'train_short_audio')))\nprint('Number train audios:', len(os.listdir(path+'train_soundscapes')))\nprint('Number test samples:', len(test_data))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.listdir(path + 'train_short_audio/caltow')[:2]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_labels.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_meta.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Data Size","metadata":{}},{"cell_type":"code","source":"print(f\"Training Dataset Shape: {train_meta.shape}\")\nprint(f\"Training Dataset Labels Shape: {train_labels.shape}\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Column-wise unique values","metadata":{}},{"cell_type":"code","source":"print(\"Data: train\")\nprint(\"-----------\")\nfor col in train_meta.columns:\n    print(col + \":\" + str(len(train_meta[col].unique())))\n\nprint(\"\\nData: train_labels\")\nprint(\"-----------\")\nfor col in train_labels.columns:\n    print(col + \":\" + str(len(train_labels[col].unique())))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Time of the Recording","metadata":{}},{"cell_type":"code","source":"train_meta['year'] = train_meta['date'].apply(lambda x: x.split(\"-\")[0])\ntrain_meta['month'] = train_meta['date'].apply(lambda x: x.split(\"-\")[1])\nplt.figure(figsize=(16, 6))\nax = sns.countplot(train_meta['year'].sort_values(ascending=False), palette=\"hls\")\n\nplt.title(\"Audio Files Registration per Year Made\", fontsize=16)\nplt.xticks(rotation=70, fontsize=13)\nplt.yticks(fontsize=13)\nplt.ylabel(\"Frequency\", fontsize=14)\nplt.xlabel(\"\");","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(16, 6))\nax = sns.countplot(train_meta['month'].sort_values(ascending=False), palette=\"hls\")\n\nplt.title(\"Audio Files Registration per Month Made\", fontsize=16)\nplt.xticks(fontsize=13)\nplt.yticks(fontsize=13)\nplt.ylabel(\"Frequency\", fontsize=14)\nplt.xlabel(\"\");","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"row = 1000\ntrain_meta.iloc[row]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"label = train_meta.loc[row, 'primary_label']\nfilename = train_meta.loc[row, 'filename']\n\n# Check if the file is in the folder\nfilename in os.listdir(path+'train_short_audio/' + label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Visualizing the audio","metadata":{}},{"cell_type":"code","source":"filename = f'../input/birdclef-2021/train_short_audio/{label}/{filename}'\nfilename","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(18, 5))\n\n# by default librosa.load returns a sample rate of 22050\n# librosa converts input to mono, hence always \ndata, sample_rate = librosa.load(filename)\nlibrosa.display.waveplot(data, sr=sample_rate)\nprint(\"Sample Rate: \", sample_rate)\nipd.Audio(filename)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Spectrogram\nA spectrogram is a visual representation of the spectrum of frequencies of a signal as it varies with time.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(18, 5))\nX = librosa.stft(data)\nXdb = librosa.amplitude_to_db(abs(X))\nlibrosa.display.specshow(Xdb, sr=sample_rate, x_axis='time', y_axis='hz')\nplt.colorbar();","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Spectral Centroid\nThe spectral centroid is a measure used in digital signal processing to characterise a spectrum. It indicates where the center of mass of the spectrum is located. ","metadata":{}},{"cell_type":"code","source":"spectral_centroids = librosa.feature.spectral_centroid(data, sr=sample_rate)[0]\nplt.figure(figsize=(25, 9))\nframes = range(len(spectral_centroids))\nt = librosa.frames_to_time(frames)\n\n# Normalising the spectral centroid for visualisation\ndef normalize(x, axis=0):\n    return sklearn.preprocessing.minmax_scale(x, axis=axis)\n\n#Plotting the Spectral Centroid along the waveform\nlibrosa.display.waveplot(data, sr=sample_rate, alpha=0.4)\nplt.plot(t, normalize(spectral_centroids), color='b');","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Spectral Rolloff\nIt is a measure of the shape of the signal. It represents the frequency at which high frequencies decline to 0.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(25, 9))\nspectral_rolloff = librosa.feature.spectral_rolloff(data+0.01, sr=sample_rate)[0]\nlibrosa.display.waveplot(data, sr=sample_rate, alpha=0.4)\nplt.plot(t, normalize(spectral_rolloff), color='r');","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Spectral bandwidth\nThe spectral bandwidth is defined as the width of the band of light at one-half the peak maximum (or full width at half maximum [FWHM]) and is represented by the two vertical red lines and λSB on the wavelength axis.","metadata":{}},{"cell_type":"code","source":"spectral_bandwidth_2 = librosa.feature.spectral_bandwidth(data+0.01, sr=sample_rate)[0]\nspectral_bandwidth_3 = librosa.feature.spectral_bandwidth(data+0.01, sr=sample_rate, p=3)[0]\nspectral_bandwidth_4 = librosa.feature.spectral_bandwidth(data+0.01, sr=sample_rate, p=4)[0]\nplt.figure(figsize=(25, 9))\nlibrosa.display.waveplot(data, sr=sample_rate, alpha=0.4)\nplt.plot(t, normalize(spectral_bandwidth_2), color='r')\nplt.plot(t, normalize(spectral_bandwidth_3), color='g')\nplt.plot(t, normalize(spectral_bandwidth_4), color='y')\nplt.legend(('p = 2', 'p = 3', 'p = 4'));  # p: order of spectral bandwidth","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Zero-Crosing Rate\nThe zero-crossing rate (ZCR) is the rate at which a signal changes from positive to zero to negative or from negative to zero to positive.","metadata":{}},{"cell_type":"code","source":"#Plot the signal:\nplt.figure(figsize=(25, 9))\n# librosa.display.waveplot(data, sr=sample_rate)\n# Zooming in\nn0 = 9000\nn1 = 9100\n\nplt.plot(data[n0:n1])\nplt.grid()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"zero_crossings = librosa.zero_crossings(data[n0:n1], pad=False)\nprint(sum(zero_crossings))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Mel-Frequency Cepstral Coefficients (MFCCs)\nThe Mel frequency cepstral coefficients (MFCCs) of a signal are a small set of features (usually about 10–20) which concisely describe the overall shape of a spectral envelope.","metadata":{}},{"cell_type":"code","source":"mfccs = librosa.feature.mfcc(data, sr=sample_rate)\n\n#Displaying  the MFCCs:\nplt.figure(figsize=(15, 7))\nlibrosa.display.specshow(mfccs, sr=sample_rate, x_axis='time')\nplt.colorbar();","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Chrome features\nA chroma feature or vector is typically a 12-element feature vector indicating how much energy of each pitch class, {C, C#, D, D#, E, …, B}, is present in the signal.","metadata":{}},{"cell_type":"code","source":"hop_length=512\nchromagram = librosa.feature.chroma_stft(data, sr=sample_rate, hop_length=hop_length)\nplt.figure(figsize=(20, 8))\nlibrosa.display.specshow(chromagram, x_axis='time', y_axis='chroma', hop_length=hop_length, cmap='coolwarm')\nplt.colorbar();","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"There are total {} species\".format(train_meta['primary_label'].nunique()))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Top 100","metadata":{}},{"cell_type":"code","source":"def plotbar(series, pal):\n    plt.figure(figsize=(20, 9))\n    chart = sns.barplot(x=series.index, y=series.values, edgecolor=(0,0,0), linewidth=2, palette=(pal))\n    chart.set_xticklabels(chart.get_xticklabels(), rotation=45)\n    \n    \nspecies = train_meta['primary_label'].value_counts()[:100]\nplotbar(species, \"Blues_r\") # series, palette","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.set(rc={'figure.figsize':(20,6)})\nsns.countplot(x='rating', data=train_meta, edgecolor=(0,0,0), linewidth=2, palette=('cubehelix'));","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are only few files with low ratings","metadata":{}},{"cell_type":"code","source":"authors = train_meta['author'].value_counts()[:10]\nplotbar(authors, \"YlOrBr_r\") # series, palette","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Richard E. Webster is author having maximum file entries.","metadata":{}},{"cell_type":"markdown","source":"## Top 100 training samples per species","metadata":{}},{"cell_type":"code","source":"print(\"Common Name\")\ncommon = train_meta['common_name'].value_counts()[:100]\nplotbar(authors, \"light:b_r\") # series, palette","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Scientific Name- Top-50\")\nscien = train_meta['scientific_name'].value_counts()[:50]\nplotbar(scien, \"Greens_r\") # series, palette","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(18, 5))\n\n# by default librosa.load returns a sample rate of 22050\n# librosa converts input to mono, hence always \nsig, sample_rate = librosa.load(filename)\nlibrosa.display.waveplot(data, sr=sample_rate)\nprint(\"Sample Rate: \", sample_rate)\nipd.Audio(filename)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"In the past that convolutional neural networks (CNN) perform particularly well for sound classification. But CNN need 2D inputs. Luckily, we can transform an audio signal into a 2D representation: a so-called spectrogram.","metadata":{}},{"cell_type":"code","source":"# First, compute the spectrogram using the \"short-time Fourier transform\" (stft)\nspec = librosa.stft(sig)\n\n# Scale the amplitudes according to the decibel scale\nspec_db = librosa.amplitude_to_db(spec, ref=np.max)\n\n# Plot the spectrogram\nplt.figure(figsize=(15, 5))\nlibrosa.display.specshow(spec_db, \n                         sr=32000, \n                         x_axis='time', \n                         y_axis='hz', \n                         cmap=plt.get_cmap('viridis'));","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('SPEC SHAPE:', spec_db.shape)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## EDA","metadata":{}},{"cell_type":"code","source":"train_labels['audio_id'].unique()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_labels.groupby(by=['audio_id']).count()['birds'][:4]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('original label:', train_labels.loc[458, 'birds'])\nprint('split into list:', train_labels.loc[458, 'birds'].split(' '))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = []\nfor row in train_labels.index:\n    labels.extend(train_labels.loc[row, 'birds'].split(' '))\nlabels = list(set(labels))\n\nprint('Number of unique bird labels:', len(labels))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_labels_train = pd.DataFrame(index=train_labels.index, columns=labels)\nfor row in train_labels.index:\n    birds = train_labels.loc[row, 'birds'].split(' ')\n    for bird in birds:\n        df_labels_train.loc[row, bird] = 1\ndf_labels_train.fillna(0, inplace=True)\n\n# We set a dummy value for the target label in the test data because we will need for the Data Generator\ntest_data['birds'] = 'nocall'\n\ndf_labels_test = pd.DataFrame(index=test_data.index, columns=labels)\nfor row in test_data.index:\n    birds = test_data.loc[row, 'birds'].split(' ')\n    for bird in birds:\n        df_labels_test.loc[row, bird] = 1\ndf_labels_test.fillna(0, inplace=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_labels_train.sum().sort_values(ascending=False)[:10]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_labels = pd.concat([train_labels, df_labels_train], axis=1)\ntest_data = pd.concat([test_data, df_labels_test], axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"file = os.listdir(path + 'train_soundscapes')[0]\nfile","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data, samplerate = read_ogg_file(path + 'train_soundscapes/', file)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"audio_id = file.split('_')[0]\nsite = file.split('_')[1]\nprint('audio_id:', audio_id, ', site:', site)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_labels[(train_labels['audio_id']==int(audio_id)) & (train_labels['site']==site) & (train_labels['birds']!='nocall')]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_data = data[int(455/5)*160000:int(460/5)*160000]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(14, 5))\nlibrosa.display.waveplot(sub_data, sr=samplerate)\nplt.grid()\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display.Audio(sub_data, rate=samplerate)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_lenght = 160000\naudio_lenght = 5\nnum_labels = len(labels)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size = 16","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"list_IDs_train, list_IDs_val = train_test_split(list(train_labels.index), test_size=0.33, random_state=2021)\nlist_IDs_test = list(samp_subm.index)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DataGenerator(Sequence):\n    def __init__(self, path, list_IDs, data, batch_size):\n        self.path = path\n        self.list_IDs = list_IDs\n        self.data = data\n        self.batch_size = batch_size\n        self.indexes = np.arange(len(self.list_IDs))\n        \n    def __len__(self):\n        len_ = int(len(self.list_IDs)/self.batch_size)\n        if len_ * self.batch_size < len(self.list_IDs):\n            len_ += 1\n        return len_\n    \n    def __getitem__(self, index):\n        indexes = self.indexes[index * self.batch_size: (index+1) * self.batch_size]\n        list_IDs_temp = [self.list_IDs[k] for k in indexes]\n        X, y = self.__data_generation(list_IDs_temp)\n        X = X.reshape((self.batch_size, 100, 1600//2))\n        return X, y\n    \n    def __data_generation(self, list_IDs_temp):\n        X = np.zeros((self.batch_size, data_lenght//2))\n        y = np.zeros((self.batch_size, num_labels))\n        for i, ID in enumerate(list_IDs_temp):\n            prefix = str(self.data.loc[ID, 'audio_id']) + '_' + self.data.loc[ID, 'site']\n            file_list = [s for s in os.listdir(self.path) if prefix in s]\n            if len(file_list) == 0:\n                # Dummy for missing test audio files\n                audio_file_fft = np.zeros((data_lenght//2))\n            else:\n                file = file_list[0]#[s for s in os.listdir(self.path) if prefix in s][0]\n                audio_file, audio_sr = read_ogg_file(self.path, file)\n                audio_file = audio_file[\n                    int((self.data.loc[ID, 'seconds']-5)/audio_lenght)*data_lenght:\n                    int(self.data.loc[ID, 'seconds']/audio_lenght)*data_lenght\n                ]\n                audio_file_fft = np.abs(np.fft.fft(audio_file)[: len(audio_file)//2])\n                # scale data\n                audio_file_fft = (audio_file_fft-audio_file_fft.mean())/audio_file_fft.std()\n            X[i, ] = audio_file_fft\n            y[i, ] = self.data.loc[ID, self.data.columns[5:]].values\n        return X, y","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_generator = DataGenerator(path+'train_soundscapes/', list_IDs_train, train_labels, batch_size)\nval_generator = DataGenerator(path+'train_soundscapes/', list_IDs_val, train_labels, batch_size)\ntest_generator = DataGenerator(path+'test_soundscapes/', list_IDs_test, test_data, batch_size)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs = 2\nlr = 1e-3","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_labels","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for batch in train_generator:\n    print(batch[0][0][0].shape)\n    print(batch[1][0].shape)\n    break","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model 1 - 1D CNN Neural Network","metadata":{}},{"cell_type":"code","source":"model = Sequential()\nmodel.add(Conv1D(128, input_shape=batch, 1600//2,), kernel_size=5, strides=4, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPool1D(pool_size=(4)))\nmodel.add(Conv1D(64, kernel_size=3, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(Flatten())\nmodel.add(Dense(256, activation='relu'))\nmodel.add(Dense(num_labels, activation='sigmoid'))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer = Adam(lr=lr),\n              loss='binary_crossentropy',\n              metrics=['binary_accuracy'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# history = model.fit_generator(generator=train_generator,\n#                               validation_data=val_generator,\n#                               epochs=epochs,\n#                               workers=4)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.models import load_model\n\n# model.save('model_1d_conv.h5')\nmodel = load_model('../input/bird-model-conv1d/model_1d_conv.h5')\nmodel.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = model.predict_generator(test_generator, verbose=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_test = np.where(y_pred > 0.5, 1, 0)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for row in samp_subm.index:\n    string = ''\n    for col in range(len(y_test[row])):\n        if y_test[row][col] == 1:\n            if string == '':\n                string += labels[col]\n            else:\n                string += ' ' + labels[col]\n    if string == '':\n        string = 'nocall'\n    samp_subm.loc[row, 'birds'] = string","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output = samp_subm\noutput.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}