{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Mel Spectrogram Data Processing for INGV\n\nGiven that the dataset is time-series data, where each column represents the seismic sensor readings, we have found that representing it as a wave and using STFT to convert them into spectrograms."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# IMPORTS\n\nimport numpy as np\nimport pandas as pd\nimport librosa\nimport librosa.display\nfrom scipy import signal\nfrom scipy.fft import fft, ifft\nfrom scipy import stats\nfrom tqdm.auto import *\nfrom collections import defaultdict\ntqdm.get_lock().locks = []\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train = pd.read_csv('/kaggle/input/predict-volcanic-eruptions-ingv-oe/train.csv')\ntest = pd.read_csv('/kaggle/input/predict-volcanic-eruptions-ingv-oe/sample_submission.csv')\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Read a sample dataset\ntrain_segment_id_0 = train['segment_id'][0]\ntrain_dataset_0 = pd.read_csv(f'/kaggle/input/predict-volcanic-eruptions-ingv-oe/train/{train_segment_id_0}.csv', memory_map=True)\ntrain_dataset_0.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Spectrogram Generation\nLet's now define a function to generate Mel Spectrograms and tweak some params"},{"metadata":{"trusted":true},"cell_type":"code","source":"def mel_spectrogram(sensor, sr):\n    # n_mels and hop_length designed to give spectrograms of size 256x256\n    spec = librosa.feature.melspectrogram(y=sensor, sr=sr, n_mels=256, hop_length=60001//256+1)\n    return librosa.power_to_db(spec)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Generate 3 sample spectrograms for visualisation purposes\nspec12000 = mel_spectrogram(train_dataset_0['sensor_1'].values, 12000)\nspec48000 = mel_spectrogram(train_dataset_0['sensor_1'].values, 48000)\nspec96000 = mel_spectrogram(train_dataset_0['sensor_1'].values, 96000)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"librosa.display.specshow(spec12000, y_axis='mel', fmax=8000, x_axis='time')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"librosa.display.specshow(spec48000, y_axis='mel', fmax=8000, x_axis='time')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"librosa.display.specshow(spec96000, y_axis='mel', fmax=8000, x_axis='time')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As seen, increasing the sample rate (12000Hz -> **48000Hz**) stretches the lower frequencies, which we hypothesise hold more info (from visual observation).  \nFurther increasing the value past 60k will result in insufficient samples for the STFT as can be seen in the 96000Hz spectrogram."},{"metadata":{},"cell_type":"markdown","source":"## Process all train and test datasets\nBy writing a simple function, we can iterate through the whole train and test dataset to process all data.  \nIn this case, we output each set of spectrograms (10 sensors per dataset) as uint8 arrays stored in compressed `npz` format."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create output directories\n!mkdir train test","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Redefine spectrogram function with chosen sample rate\ndef spectrogram(sensor):\n    spec = librosa.feature.melspectrogram(y=sensor, sr=48000, n_mels=256, hop_length=60001//256+1)\n    return librosa.power_to_db(spec)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def generate_spectrograms_for_df(df, dataset):\n    # Enumerate across all datasets\n    for i, segment_id in enumerate(df['segment_id'].values):\n        sensors = pd.read_csv(f'/kaggle/input/predict-volcanic-eruptions-ingv-oe/{dataset}/{segment_id}.csv', memory_map=True)\n        sensors.fillna(0, inplace=True)\n        \n        signals = []\n        for i in range(10):\n            name = f'sensor_{i+1}'\n            sensor = sensors[name].values\n            signals.append(spectrogram(sensor))\n        \n        # Cast to uint8 to save memory\n        signals = np.array(signals, dtype='uint8')\n\n        np.savez_compressed(f'{dataset}/{segment_id}-spec.npz', signals)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"generate_spectrograms_for_df(train, 'train')\ngenerate_spectrograms_for_df(test, 'test')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Loading Data\nTo load data for training, you can use the following code:"},{"metadata":{"trusted":true},"cell_type":"code","source":"segment_id = 1136037770\nspectrogram = np.load(f'train/{segment_id}-spec.npz')['arr_0'].astype('float32')","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}