{"cells":[{"metadata":{"_uuid":"f9a0f27d-eb65-491b-9a5b-eb243d516080","_cell_guid":"306820aa-8fca-4b96-b5b1-a26d5a34a6ad","trusted":true},"cell_type":"code","source":"import os\nimport pandas as pd\nimport matplotlib\n\npd.set_option('display.max_columns', None)\npd.set_option('display.expand_frame_repr', False)\n\n# Check whether the script is running locally or as a Kaggle notebook and define paths accordingly\nif os.getcwd() == \"/kaggle/working\":\n    TRAIN_CSV_PATH = \"../input/rfcx-species-audio-detection/\"\nelse:\n    TRAIN_CSV_PATH = \"data/rfcx-species-audio-detection/\"\n    matplotlib.use(\"QT5Agg\")\nTRAIN_TP_CSV_PATH = os.path.join(TRAIN_CSV_PATH, \"train_tp.csv\")\nTRAIN_FP_CSV_PATH = os.path.join(TRAIN_CSV_PATH, \"train_fp.csv\")\n\n# Build the overall train_df based on the TP/FP CSV files\ntrain_tp_df = pd.read_csv(TRAIN_TP_CSV_PATH)\ntrain_tp_df[\"is_tp\"] = True\ntrain_fp_df = pd.read_csv(TRAIN_FP_CSV_PATH)\ntrain_fp_df[\"is_tp\"] = False\ntrain_df = pd.concat([train_tp_df, train_fp_df], axis=0, ignore_index=True)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**What is the dataframe structure?**"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_df.info())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**How training instances are distributed over species_id and songtype_id? Is the dataset balanced?**"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_df.groupby([\"species_id\", \"songtype_id\"])[\"is_tp\"].describe())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"For what concerns the distribution of the labels over the values of (species_id, songtype_id), the dataset looks balanced: there are about 350 instances for each (species_id, songtype_id). For each (species_id, songtype_id), only about 50 out of about 350 are of TP type; hence, for each (species_id, songtype_id) there are approximately 6x FP instances than TP: the baseline accuracy for a \"Zero Rule\" classifier would be about 85.7%\n\n**How many species are associated to two song-types (values 1 and 4)? How are they distributed statistically?**"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Song-type ID values for each species ID\")\nprint(train_df.groupby(\"species_id\")[\"songtype_id\"].unique())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Species ID 17 and 23 have records with both song-type values (1 and 4); in order to use properly FP information also for these species, classes 17 and 23 should become 4 classes, given by (species_id, songtype_id), namely: (17, 1), (17, 4), (23, 1), (23, 4).\n\n**Is it relevant for training the time and frequency location of each label?**"},{"metadata":{"trusted":true},"cell_type":"code","source":"tp_fp_discordance_df = train_df.groupby([\"recording_id\", \"species_id\", \"songtype_id\"]).apply(\n    lambda df: df[\"is_tp\"].nunique() != 1).sort_values()\nprint(tp_fp_discordance_df)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The last two rows of the data-frame above (records a2441a74b and 178b835e3) have both TP and FP annotations for the same (species_id, songtype_id) in different time frames:\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_df[(train_df[\"recording_id\"] == \"a2441a74b\")])\nprint(train_df[(train_df[\"recording_id\"] == \"178b835e3\")])\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Hence, if all the TP & FP labels were associated to the whole spectrogram, it would be (in these few cases) completely incorrect. Possible actions are:\n1. remove punctually these labels from the dataset, in order to ignore them;\n2. setup the pipeline to select only [t_min, t_max] slices of the spectrogram to feed the training process."},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_df.groupby([\"species_id\", \"songtype_id\"])[[\"f_min\", \"f_max\"]].nunique())\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"For some (species_id, songtype_id) values, there are only single values of f_min and f_max. In other cases, e.g. for (species_id, songtype_id) = (14, 1) there are up to 3 f_min and f_max values:\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_df[train_df[\"species_id\"] == 14].head(5))\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**What is the distribution of the labelled time interval duration values? What is their minimum/maximum?**\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"t_deltas = (train_df[\"t_max\"]-train_df[\"t_min\"])\nprint(t_deltas.describe())\nt_deltas.hist(bins=20)\nprint(\"Percentage of time deltas less than 4.5 s: {:.1f}%\".format(\n    t_deltas[t_deltas < 4.5].count()/t_deltas.count()*100))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"All labelled time intervals have durations between about 2.6 s and 7.9 s; anyway, only about 1/10th lasts more than 4.5 s\n\n\n**What are minimum and maximum values of f_min and f_max respectively?**"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Minimum value of f_min: {:0.1f} Hz\".format(train_df[\"f_min\"].min()))\nprint(\"Maximum value of f_max: {:0.1f} Hz\".format(train_df[\"f_max\"].max()))","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}