{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# import dependencies\nimport os\nimport numpy as np\nimport pandas as pd\nimport sklearn\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom plotly.subplots import make_subplots\nimport plotly.graph_objects as go\nimport plotly.express as px\nimport folium\nfrom folium import Marker,GeoJson,Choropleth, Circle\nfrom folium.plugins import HeatMap, MarkerCluster\nimport librosa.display\nfrom IPython.display import Audio\n\npd.set_option('display.max_columns', 50)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data loading and basic understanding"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# import data\ndf_train = pd.read_csv(\"../input/birdsong-recognition/train.csv\")\ndf_train.head","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train.info()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Number of birds (classes) in the data"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train['ebird_code'].nunique()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Check the class distribution"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train['species'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### From the above values we can see that the data is highly imbalanced. An important aspect to consider while creating a good cross validation technique."},{"metadata":{},"cell_type":"markdown","source":"## Visualise the time period of audio recording"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train['year'] = df_train['date'].apply(lambda x: x.split('-')[0])\ndf_train['month'] = df_train['date'].apply(lambda x: x.split('-')[1])\ngroup_year = df_train.groupby(['year']).size().reset_index(name='counts')\ngroup_year = group_year.iloc[3:]\ngroup_month = df_train.groupby(['month']).size().reset_index(name='counts')\n\n\n\nfig = make_subplots(rows=2, cols=1, subplot_titles = ('Number of recordings w.r.t year', 'Number of recordings w.r.t month'))\n\nfig.append_trace(go.Bar(\n    x=group_year['year'],\n    y=group_year['counts'],\n    #tickmode='linear'\n), row=1, col=1)\n\nfig.append_trace(go.Bar(\n    x=group_month['month'],\n    y=group_month['counts'],\n), row=2, col=1)\n\n\n\nfig.update_layout(height=1000, width=700, showlegend=False,  xaxis = dict(\n        tickmode = 'linear',\n    ), xaxis2 = dict(tickmode='linear'))\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Distribution of Sampling rate & Channel of audio files"},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = make_subplots(rows=1, cols=2, specs=[[{\"type\": \"pie\"}, {\"type\": \"pie\"}]], subplot_titles = ('Distribution of Channels', 'Distribution of Sampling rate'))\n\ngroup_ch = df_train.groupby(['channels']).size().reset_index(name='counts')\nfig.append_trace(go.Pie(\n    labels=group_ch['channels'],\n    values=group_ch['counts'],\n), row=1, col=1)\n\ngroup_sr = df_train.groupby(['sampling_rate']).size().reset_index(name='counts')\nfig.append_trace(go.Pie(\n    labels=group_sr['sampling_rate'],\n    values=group_sr['counts'],\n), row=1, col=2)\n\n\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Location of recordings"},{"metadata":{"trusted":true},"cell_type":"code","source":"\nmap = folium.Map(location=[54, 15], tiles='cartodbpositron', zoom_start=5)\ndf_train = df_train[df_train[\"latitude\"] != \"Not specified\"]\n\n#drop nan values and convert latitude and longitude to float\ndf_no_nan = df_train.dropna(subset=['latitude','longitude'], how='any')\ndf_no_nan.latitude.astype(float)\ndf_no_nan.longitude.astype(float)\n\nmap_cluster = MarkerCluster()\n\n# Add points to the map\nfor idx, row in df_no_nan.iterrows():\n    map_cluster.add_child(Marker([row['latitude'], row['longitude']]))\n\nmap.add_child(map_cluster)\n\n#Display map\nmap\n\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Let's play some audio files"},{"metadata":{"trusted":true},"cell_type":"code","source":"audio_path = '../input/birdsong-recognition/train_audio/aldfly/XC134874.mp3'\nx, sr = librosa.load(audio_path)\nAudio(x, rate=sr)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"audio_path = '../input/birdsong-recognition/train_audio/amepip/XC111040.mp3'\nx, sr = librosa.load(audio_path)\nAudio(x, rate=sr)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"audio_path = '../input/birdsong-recognition/train_audio/banswa/XC138517.mp3'\nx, sr = librosa.load(audio_path)\nAudio(x, rate=sr)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"audio_path = '../input/birdsong-recognition/train_audio/bkhgro/XC109305.mp3'\nx, sr = librosa.load(audio_path)\nAudio(x, rate=sr)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Visualisation of audio files"},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(4, figsize = (20, 9))\nfig.suptitle('Waveplots', fontsize=16)\naudio_path1 = '../input/birdsong-recognition/train_audio/aldfly/XC134874.mp3'\naudio_path2 = '../input/birdsong-recognition/train_audio/amepip/XC111040.mp3'\naudio_path3 = '../input/birdsong-recognition/train_audio/banswa/XC138517.mp3'\naudio_path4 = '../input/birdsong-recognition/train_audio/bkhgro/XC109305.mp3'\n\ny1, sr1 = librosa.load(audio_path1)\ny2, sr2 = librosa.load(audio_path2)\ny3, sr3 = librosa.load(audio_path3)\ny4, sr4 = librosa.load(audio_path4)\n\nlibrosa.display.waveplot(y=y1, sr=sr1, color = \"#3371FF\", ax=ax[0])\nlibrosa.display.waveplot(y=y2 , sr=sr2, color = \"#F7A81E\", ax=ax[1])\nlibrosa.display.waveplot(y=y3 , sr=sr3, color = \"#2BF71E\", ax=ax[2])\nlibrosa.display.waveplot(y=y4 , sr=sr4, color = \"#F71E6D\", ax=ax[3])\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Spectrogram"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Visualize an STFT power spectrum\n\naudio_path = '../input/birdsong-recognition/train_audio/aldfly/XC134874.mp3'\ny, sr = librosa.load(audio_path)\nplt.figure(figsize=(12, 8))\nD = librosa.amplitude_to_db(librosa.stft(y))\nplt.subplot(4, 2, 1)\nlibrosa.display.specshow(D, y_axis='linear')\nplt.colorbar(format='%+2.0f dB')\nplt.title('Linear-frequency power spectrogram')\n\n# logarithmic scale\n\nplt.subplot(4, 2, 2)\nlibrosa.display.specshow(D, y_axis='log')\nplt.colorbar(format='%+2.0f dB')\nplt.title('Log-frequency power spectrogram')\n\n#CQT scale\n\nCQT = librosa.amplitude_to_db(librosa.cqt(y, sr=sr), ref=np.max)\nplt.subplot(4, 2, 3)\nlibrosa.display.specshow(CQT, y_axis='cqt_hz')\nplt.colorbar(format='%+2.0f dB')\nplt.title('Constant-Q power spectrogram (Hz)')\n\nCQT = librosa.amplitude_to_db(librosa.cqt(y, sr=sr), ref=np.max)\nplt.subplot(4, 2, 4)\nlibrosa.display.specshow(CQT, y_axis='cqt_note')\nplt.colorbar(format='%+2.0f dB')\nplt.title('Constant-Q power spectrogram (note)')\n\n#Chromagram\nC = librosa.feature.chroma_cqt(y=y, sr=sr)\nplt.subplot(4, 2, 5)\nlibrosa.display.specshow(C, y_axis='chroma')\nplt.colorbar()\nplt.title('Chromagram')\n\n# Log power spectrogram\nplt.subplot(4, 2, 6)\nlibrosa.display.specshow(D, x_axis='time', y_axis='log')\nplt.colorbar(format='%+2.0f dB')\nplt.title('Log power spectrogram')\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Feature Extraction"},{"metadata":{},"cell_type":"markdown","source":"### Zero Crossing Rate\n> The rate at which the signal changes from positive to zero to negative or from negative to zero to positive"},{"metadata":{"trusted":true},"cell_type":"code","source":"# let's zoom in \nn0 = 7000\nn1 = 7100\nplt.figure(figsize=(14, 5))\nplt.plot(y[n0:n1])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"zero_crossings = librosa.zero_crossings(y[n0:n1], pad=False)\nzero_crossings.shape","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Using Sum to find the total number of zero crossings"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(sum(zero_crossings))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**zero_crossing_rate** to find the zero_crossing_rate over time"},{"metadata":{"trusted":true},"cell_type":"code","source":"zcrs = librosa.feature.zero_crossing_rate(y)\nprint(zcrs.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Plot the zero-crossing rate"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(14, 5))\nplt.plot(zcrs[0])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Spectral Centroid\n> The 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":{"trusted":true},"cell_type":"code","source":"spectral_centroid = librosa.feature.spectral_centroid(y, sr=sr)[0]\nspectral_centroid.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(14, 5))\nplt.plot(spectral_centroid.T, label='Spectral centroid')\nplt.ylabel('Hz')\nplt.xticks([])\nplt.xlim([0, spectral_centroid.shape[-1]])\nplt.legend()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Spectral Rolloff\n> Spectral rolloff is the frequency below which a specified percentage of the total spectral energy lies."},{"metadata":{"trusted":true},"cell_type":"code","source":"#  time variable for visualization\nframes = range(len(spectral_centroid))\nt = librosa.frames_to_time(frames)\n\n# helper function to normalize the spectral centroid for visualization\n\ndef normalize(y, axis=0):\n    return sklearn.preprocessing.minmax_scale(y, axis=axis)\n\nspectral_rolloff = librosa.feature.spectral_rolloff(y+0.01, sr=sr)[0]\nlibrosa.display.waveplot(y, sr=sr, alpha=0.4)\nplt.plot(t, normalize(spectral_rolloff), color='r')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Remove silence from audio file"},{"metadata":{"trusted":true},"cell_type":"code","source":"audio_path = '../input/birdsong-recognition/train_audio/amecro/XC114552.mp3'\ny, sr = librosa.load(audio_path)\nAudio(y, rate=sr)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We will use **librosa.effects.split**  to split an audio signal into non-silent intervals"},{"metadata":{"trusted":true},"cell_type":"code","source":"db = librosa.core.amplitude_to_db(y)\nmean_db = np.abs(db).mean()\nstd_db = db.std()\nx_split = librosa.effects.split(y=y, top_db = mean_db - std_db)\nsilence_removed = []\nfor i in x_split:\n    silence_removed.extend(y[i[0]:i[1]])\nsilence_removed = np.array(silence_removed)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now let's listen to audio after removing the silence"},{"metadata":{"trusted":true},"cell_type":"code","source":"Audio(silence_removed, rate=sr)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}