{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":11801926,"sourceType":"datasetVersion","datasetId":7411564},{"sourceId":391177,"sourceType":"modelInstanceVersion","isSourceIdPinned":false,"modelInstanceId":322106,"modelId":342774}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport librosa\nfrom pathlib import Path\nfrom ast import literal_eval\n\n# --- Config ---\nSAMPLE_RATE = 32000\nN_FFT = 1024\nHOP_LENGTH = 512\nMAX_FREQ = 16000\nBIN_SIZE = 5\nNUM_BINS = MAX_FREQ // BIN_SIZE\nMAX_FILES_PER_SPECIES = 100  # Limit for each species\n\n# --- Target Species List ---\nTARGET_SPECIES = ['grekis', 'compau', 'trokin']  # Extend this list as needed\nAUDIO_DIR = Path(\"/kaggle/input/birdclef-2025/train_audio\")\n\n# --- Load Metadata ---\ndf = pd.read_csv(\"/kaggle/input/birdclef-2025/train.csv\")\n\n# --- Parse secondary labels safely ---\ndef parse_labels(s):\n    try:\n        return literal_eval(s) if pd.notna(s) else []\n    except:\n        return []\n\ndf[\"secondary_labels\"] = df[\"secondary_labels\"].apply(parse_labels)\n\n# --- Feature Extraction Function ---\ndef improved_audio_to_binary_vector(path):\n    y, sr = librosa.load(path, sr=SAMPLE_RATE)\n    y_harmonic, _ = librosa.effects.hpss(y)\n    S = np.abs(librosa.stft(y_harmonic, n_fft=N_FFT, hop_length=HOP_LENGTH))\n    freqs = librosa.fft_frequencies(sr=sr, n_fft=N_FFT)\n    freq_mask = freqs <= MAX_FREQ\n    S = S[freq_mask, :]\n    freqs = freqs[freq_mask]\n\n    energy_time_avg = np.mean(S, axis=1)\n    log_energy = librosa.amplitude_to_db(energy_time_avg, ref=np.max)\n\n    thresholds = np.zeros_like(log_energy)\n    for fmin, fmax in [(0, 2000), (2000, 6000), (6000, MAX_FREQ)]:\n        band_mask = (freqs >= fmin) & (freqs < fmax)\n        if np.sum(band_mask) == 0:\n            continue\n        band_energy = log_energy[band_mask]\n        q75 = np.percentile(band_energy, 75)\n        q25 = np.percentile(band_energy, 25)\n        thresholds[band_mask] = q75 + 0.5 * (q75 - q25)\n\n    binary_vec = np.zeros(NUM_BINS, dtype=int)\n    for i, f in enumerate(freqs):\n        bin_idx = int(f // BIN_SIZE)\n        if log_energy[i] > thresholds[i]:\n            if np.sum(S[i, :] > thresholds[i]) >= 3:\n                binary_vec[bin_idx] = 1\n\n    return binary_vec\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-14T00:09:44.507789Z","iopub.execute_input":"2025-05-14T00:09:44.508189Z","iopub.status.idle":"2025-05-14T00:09:45.036370Z","shell.execute_reply.started":"2025-05-14T00:09:44.508135Z","shell.execute_reply":"2025-05-14T00:09:45.035556Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from xgboost import XGBClassifier\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.linear_model import LogisticRegression","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-13T23:59:34.650887Z","iopub.execute_input":"2025-05-13T23:59:34.651247Z","iopub.status.idle":"2025-05-13T23:59:34.656239Z","shell.execute_reply.started":"2025-05-13T23:59:34.651224Z","shell.execute_reply":"2025-05-13T23:59:34.655097Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.metrics import classification_report\nfrom sklearn.preprocessing import LabelEncoder\nfrom pathlib import Path\n\n# # --- Assuming you have these functions and variables defined ---\n# SAMPLE_RATE = 32000  # Example sample rate\n# NUM_BINS = 1600  # Number of frequency bins (adjust if necessary)\n# num_positive = 100  # Number of positive samples (can be dynamically set)\n# target_species = ['grekis', 'compau', 'nocowl']  # List of target species\n# species_code = \"grekis\"  # Example species for processing negative samples\n\n# --- Load Positive Data ---\ndf_positive = pd.read_json(\"/kaggle/input/data-foyie/multi_species_metadata_vectors.json\", lines=True)\n\n# --- Load Negative Data ---\ndf_negative = pd.read_json(\"/kaggle/input/data-foyie/neg_multi_species_metadata_vectors.json\", lines=True)\n\n# --- Combine Positive and Negative Data ---\ndf_all = pd.concat([df_positive, df_negative], ignore_index=True)\n\n# --- Prepare Feature (X) and Label (y) ---\nX = np.array([np.array(vec) for vec in df_all['vector']])\ny = []\n\n# Label encoding: 0 for negative, 1, 2, 3 for each species\nlabel_mapping = {\"negative\": 0, \"grekis\": 1, \"compau\": 2, \"trokin\": 3}\n\n# Add species labels to the target vector\nfor idx, row in df_all.iterrows():\n    if row['species'] == 'negative':\n        y.append(0)\n    elif row['species'] == 'grekis':\n        y.append(1)\n    elif row['species'] == 'compau':\n        y.append(2)\n    elif row['species'] == 'trokin':\n        y.append(3)\n\ny = np.array(y)\n\n# --- Split Data into Training and Testing Sets ---\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n\n# --- Train a Random Forest Classifier ---\nclassifier = RandomForestClassifier(n_estimators=100, random_state=42)\n# classifier=LogisticRegression()\nclassifier.fit(X_train, y_train)\n\n# --- Evaluate the Model ---\ny_pred = classifier.predict(X_test)\n\n# --- Display Classification Report ---\nprint(classification_report(y_test, y_pred, target_names=['negative', 'grekis', 'compau', 'nocowl']))\n\n# --- Save the Model for Later Use ---\nimport joblib\njoblib.dump(classifier, \"bird_species_classifier.pkl\")\nprint(\"Model saved as 'bird_species_classifier.pkl'\")\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-14T00:00:38.936450Z","iopub.execute_input":"2025-05-14T00:00:38.936745Z","iopub.status.idle":"2025-05-14T00:00:40.915520Z","shell.execute_reply.started":"2025-05-14T00:00:38.936725Z","shell.execute_reply":"2025-05-14T00:00:40.914756Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport librosa\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nfrom joblib import load","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-14T00:01:30.814316Z","iopub.execute_input":"2025-05-14T00:01:30.814621Z","iopub.status.idle":"2025-05-14T00:01:30.824101Z","shell.execute_reply.started":"2025-05-14T00:01:30.814599Z","shell.execute_reply":"2025-05-14T00:01:30.823218Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# # --- Feature Extraction Function (Same as Training) ---\n# def extract_binary_features_from_chunk(chunk, percentile=76.7):\n#     S = librosa.stft(chunk, n_fft=1024, hop_length=512)\n#     S_power = np.abs(S)**2\n#     S_db = librosa.power_to_db(S_power, ref=np.max)\n#     freqs = librosa.fft_frequencies(sr=32000, n_fft=1024)\n#     bin_edges = np.linspace(0, 16000, 3201)\n#     binary_vector = np.zeros(3200, dtype=int)\n#     energy_per_freq = S_db.max(axis=1)\n#     adaptive_threshold = np.percentile(energy_per_freq, percentile)\n\n#     for j in range(3200):\n#         f_start = bin_edges[j]\n#         f_end = bin_edges[j + 1]\n#         bin_mask = (freqs >= f_start) & (freqs < f_end)\n#         if np.any(bin_mask):\n#             max_energy = np.max(energy_per_freq[bin_mask])\n#             if max_energy > adaptive_threshold:\n#                 binary_vector[j] = 1\n#     return binary_vector\n    \n# # --- Generate Predictions ---\n# AUDIO_BASE_TEST = '/kaggle/input/birdclef-2025/test_soundscapes/'\n# class_labels = sorted(os.listdir('/kaggle/input/birdclef-2025/train_audio/'))\n\n# print(\"\\n🔵 Predicting on test soundscapes...\")\n# submission_rows = []\n\n# test_soundscapes = [os.path.join(AUDIO_BASE_TEST, f) \n#                     for f in sorted(os.listdir(AUDIO_BASE_TEST)) \n#                     if f.endswith('.ogg')]\n\n# for soundscape_path in tqdm(test_soundscapes, desc=\"Processing Soundscapes\"):\n#     try:\n#         sig, sr = librosa.load(soundscape_path, sr=32000)\n#     except Exception as e:\n#         print(f\"❌ Error reading {soundscape_path}: {e}\")\n#         continue\n\n#     samples_per_chunk = 32000 * 5  # 5-second chunks\n\n#     for i in range(0, len(sig), samples_per_chunk):\n#         chunk = sig[i:i+samples_per_chunk]\n#         if len(chunk) < samples_per_chunk:\n#             continue  # Skip incomplete chunks\n\n#         try:\n#             # Step 1: Extract features\n#             vec = extract_binary_features_from_chunk(chunk, percentile=76.7)\n            \n#             # Step 2: Scale features (critical for XGBoost!)\n#             vec_scaled = scaler.transform([vec])  # Use the same scaler as training\n            \n#             # Step 3: Predict probability for grekis\n#             prob = classifier.predict_proba(vec_scaled)[0][1]  # Use XGBoost\n            \n#             # Step 4: Build submission row\n#             row_id = f\"{os.path.splitext(os.path.basename(soundscape_path))[0]}_{(i//samples_per_chunk +1)*5}\"\n#             row = [row_id] + [0.001] * len(class_labels)  # Default 0.001 for non-target\n#             row[class_labels.index('grekis') + 1] = prob  # Set grekis probability\n            \n#             submission_rows.append(row)\n#         except Exception as e:\n#             print(f\"❌ Error processing {soundscape_path} chunk {i}: {e}\")\n\n# # Create submission file\n# submission_df = pd.DataFrame(submission_rows, columns=['row_id'] + class_labels)\n# submission_df.to_csv('submission.csv', index=False)\n# print(\"✅ Final submission.csv created!\")\n\n# # Preview\n# submission_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-14T01:16:55.449609Z","iopub.execute_input":"2025-05-14T01:16:55.449965Z","iopub.status.idle":"2025-05-14T01:16:55.455954Z","shell.execute_reply.started":"2025-05-14T01:16:55.449918Z","shell.execute_reply":"2025-05-14T01:16:55.454969Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import os\n# import pandas as pd\n# import numpy as np\n# import librosa\n# import joblib\n# from pathlib import Path\n\n# # --- Config ---\n# SAMPLE_RATE = 32000\n# N_FFT = 1024\n# HOP_LENGTH = 512\n# MAX_FREQ = 16000\n# BIN_SIZE = 5\n# NUM_BINS = MAX_FREQ // BIN_SIZE\n# TARGET_SPECIES = ['grekis', 'compau', 'trokin']  # Example\n\n# # --- Load Model ---\n# # classifier = joblib.load(\"bird_species_classifier.pkl\")\n\n# # --- Feature Extraction Function ---\n# def improved_audio_to_binary_vector(path):\n#     y, sr = librosa.load(path, sr=SAMPLE_RATE)\n#     y_harmonic, _ = librosa.effects.hpss(y)\n#     S = np.abs(librosa.stft(y_harmonic, n_fft=N_FFT, hop_length=HOP_LENGTH))\n#     freqs = librosa.fft_frequencies(sr=sr, n_fft=N_FFT)\n#     freq_mask = freqs <= MAX_FREQ\n#     S = S[freq_mask, :]\n#     freqs = freqs[freq_mask]\n\n#     energy_time_avg = np.mean(S, axis=1)\n#     log_energy = librosa.amplitude_to_db(energy_time_avg, ref=np.max)\n\n#     thresholds = np.zeros_like(log_energy)\n#     for fmin, fmax in [(0, 2000), (2000, 6000), (6000, MAX_FREQ)]:\n#         band_mask = (freqs >= fmin) & (freqs < fmax)\n#         if np.sum(band_mask) == 0:\n#             continue\n#         band_energy = log_energy[band_mask]\n#         q75 = np.percentile(band_energy, 75)\n#         q25 = np.percentile(band_energy, 25)\n#         thresholds[band_mask] = q75 + 0.5 * (q75 - q25)\n\n#     binary_vec = np.zeros(NUM_BINS, dtype=int)\n#     for i, f in enumerate(freqs):\n#         bin_idx = int(f // BIN_SIZE)\n#         if log_energy[i] > thresholds[i]:\n#             if np.sum(S[i, :] > thresholds[i]) >= 3:\n#                 binary_vec[bin_idx] = 1\n\n#     return binary_vec\n\n# # --- Prediction on Test Soundscapes ---\n# test_dir = Path(\"/kaggle/input/birdclef-2025/test_soundscapes\")\n# submission_rows = []\n\n# for filename in os.listdir(test_dir):\n#     if not filename.endswith(\".ogg\"):\n#         continue\n\n#     filepath = test_dir / filename\n#     file_id = filename.replace(\".ogg\", \"\")\n\n#     try:\n#         y, sr = librosa.load(filepath, sr=SAMPLE_RATE)\n#         for start in range(0, 60, 5):\n#             end = start + 5\n#             y_clip = y[start * sr:end * sr]\n\n#             if len(y_clip) < sr * 5:\n#                 y_clip = np.pad(y_clip, (0, sr * 5 - len(y_clip)))\n\n#             clip_path = f\"/tmp/{file_id}_{end}.ogg\"\n#             librosa.output.write_wav(clip_path, y_clip, sr)\n\n#             vec = improved_audio_to_binary_vector(clip_path).reshape(1, -1)\n#             probs = classifier.predict_proba(vec)[0]\n\n#             row_id = f\"{file_id}_{end}\"\n#             row = {\"row_id\": row_id}\n\n#             for i, species in enumerate(TARGET_SPECIES):\n#                 row[species] = probs[i + 1] if len(probs) > i + 1 else 0.0\n\n#             submission_rows.append(row)\n\n#     except Exception as e:\n#         print(f\"❌ Error processing {filename}: {e}\")\n\n# # --- Create Submission DataFrame ---\n# submission_df = pd.DataFrame(submission_rows)\n\n# # Ensure all required columns are present\n# expected_cols = [\"row_id\"] + TARGET_SPECIES\n# for col in expected_cols:\n#     if col not in submission_df.columns:\n#         submission_df[col] = 0.0\n\n# # submission_df = submission_df[expected_cols]\n\n# # # Check if DataFrame is empty\n# # if submission_df.empty:\n# #     raise ValueError(\"❌ No predictions were added. Check test files and processing.\")\n\n# # Create submission file\n# # submission_df = pd.DataFrame(submission_rows, columns=['row_id'] + class_labels)\n# submission_df.to_csv('submission.csv', index=False)\n# print(\"✅ Final submission.csv created!\")\n\n# # Preview\n# submission_df.head()\n# # # --- Save Submission ---\n# # submission_df.to_csv(\"submission.csv\", index=False)\n# # print(\"✅ Submission file saved: submission.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-14T01:16:55.959257Z","iopub.execute_input":"2025-05-14T01:16:55.959555Z","iopub.status.idle":"2025-05-14T01:16:55.965809Z","shell.execute_reply.started":"2025-05-14T01:16:55.959535Z","shell.execute_reply":"2025-05-14T01:16:55.964825Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport librosa\nimport numpy as np\nimport pandas as pd\nimport joblib\n\n# --- Paths ---\nAUDIO_BASE_TEST = '/kaggle/input/birdclef-2025/test_soundscapes/'\nTRAIN_AUDIO_DIR = '/kaggle/input/birdclef-2025/train_audio/'\n\n# --- Load trained model ---\n# clf_rf = joblib.load(\"/kaggle/input/my-models/bird_species_classifier.pkl\")  # update if needed\n\n# --- Target species as per your training ---\ntarget_species = ['grekis', 'compau', 'trokin']  # class 1, 2, 3 in your model\nlabel_mapping = {0: \"negative\", 1: \"grekis\", 2: \"compau\", 3: \"trokin\"}\n\n# --- All 2025 class labels from train_audio folder (required for submission) ---\nclass_labels = sorted(os.listdir(TRAIN_AUDIO_DIR))  # ~206 total classes\n\n# --- Prepare submission rows ---\nsubmission_rows = []\n\n# --- Process test soundscapes ---\ntest_files = sorted(f for f in os.listdir(AUDIO_BASE_TEST) if f.endswith(\".ogg\"))\n\nfor filename in test_files:\n    path = os.path.join(AUDIO_BASE_TEST, filename)\n    try:\n        y, sr = librosa.load(path, sr=32000)\n        samples_per_chunk = sr * 5\n\n        for i in range(0, len(y), samples_per_chunk):\n            chunk = y[i:i+samples_per_chunk]\n            if len(chunk) < samples_per_chunk:\n                continue\n\n            # Feature extraction\n            S = librosa.stft(chunk, n_fft=1024, hop_length=512)\n            S_power = np.abs(S)**2\n            S_db = librosa.power_to_db(S_power, ref=np.max)\n            freqs = librosa.fft_frequencies(sr=sr, n_fft=1024)\n\n            bin_edges = np.linspace(0, 16000, 3201)\n            binary_vector = np.zeros(3200, dtype=int)\n            energy_per_freq = S_db.max(axis=1)\n            adaptive_threshold = np.percentile(energy_per_freq, 76.7)\n\n            for j in range(3200):\n                f_start = bin_edges[j]\n                f_end = bin_edges[j+1]\n                bin_mask = (freqs >= f_start) & (freqs < f_end)\n                if np.any(bin_mask):\n                    max_energy = np.max(energy_per_freq[bin_mask])\n                    if max_energy > adaptive_threshold:\n                        binary_vector[j] = 1\n\n            # Predict multi-class probabilities\n            probs = classifier.predict_proba(binary_vector.reshape(1, -1))[0]  # shape: (4,)\n\n            # Row ID format\n            chunk_end = (i // samples_per_chunk + 1) * 5\n            row_id = f\"{filename.replace('.ogg', '')}_{chunk_end}\"\n\n            # Build submission row\n            row = [row_id]\n            for label in class_labels:\n                if label in target_species:\n                    class_index = list(label_mapping.keys())[list(label_mapping.values()).index(label)]\n                    row.append(probs[class_index])\n                else:\n                    row.append(0.001)\n\n            submission_rows.append(row)\n\n    except Exception as e:\n        print(f\"❌ Error processing {filename}: {e}\")\n\n# --- Create submission DataFrame ---\nsubmission_df = pd.DataFrame(submission_rows, columns=[\"row_id\"] + class_labels)\n\n# --- Save submission file ---\nsubmission_df.to_csv(\"submission.csv\", index=False)\nprint(\"✅ Saved final submission as submission.csv\")\nsubmission_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-14T01:16:56.675816Z","iopub.execute_input":"2025-05-14T01:16:56.676109Z","iopub.status.idle":"2025-05-14T01:16:56.701937Z","shell.execute_reply.started":"2025-05-14T01:16:56.676091Z","shell.execute_reply":"2025-05-14T01:16:56.701214Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}