{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.11.11"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 🐦 BirdCLEF 2025 - Comprehensive Exploratory Data Analysis\n\n## Overview\nThis notebook provides a detailed exploration of the BirdCLEF 2025 dataset, including:\n- 📊 Dataset structure and statistics\n- 🐦 Species diversity analysis\n- 🌍 Geographic distribution patterns\n- 🔊 Audio characteristics analysis\n- 💡 Key insights and modeling recommendations\n\n---","metadata":{}},{"cell_type":"code","source":"# Import Required Libraries\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport geopandas as gpd\nimport os\nimport librosa\nimport torchaudio\nimport torch\nfrom tqdm import tqdm\nimport random\nimport warnings\n\nwarnings.filterwarnings('ignore')\n\n# Set style for better visualizations\nplt.style.use('default')\nsns.set_palette(\"husl\")\n\nprint(\"📊 BirdCLEF 2025 Dataset Analysis\")\nprint(\"=\"*50)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:33.653107Z","iopub.execute_input":"2025-05-22T20:23:33.653394Z","iopub.status.idle":"2025-05-22T20:23:43.851353Z","shell.execute_reply.started":"2025-05-22T20:23:33.653356Z","shell.execute_reply":"2025-05-22T20:23:43.850622Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🔍 1. Dataset Loading and Overview","metadata":{}},{"cell_type":"code","source":"# Load the main datasets\ntrain = pd.read_csv('/kaggle/input/birdclef-2025/train.csv')\ntaxonomy = pd.read_csv('/kaggle/input/birdclef-2025/taxonomy.csv')\n\nprint(f\"✅ Training data loaded: {train.shape[0]:,} records, {train.shape[1]} columns\")\nprint(f\"✅ Taxonomy data loaded: {taxonomy.shape[0]:,} species, {taxonomy.shape[1]} columns\")\n\n# Display basic information\nprint(\"\\n📋 DATASET STRUCTURE\")\nprint(\"-\" * 30)\nprint(\"Training Data Columns:\", list(train.columns))\nprint(\"Taxonomy Data Columns:\", list(taxonomy.columns))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:43.852934Z","iopub.execute_input":"2025-05-22T20:23:43.853315Z","iopub.status.idle":"2025-05-22T20:23:44.078816Z","shell.execute_reply.started":"2025-05-22T20:23:43.853294Z","shell.execute_reply":"2025-05-22T20:23:44.077939Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Display first few rows\nprint(\"🔍 Training Data Sample:\")\ndisplay(train.head())\n\nprint(\"\\n🔍 Taxonomy Data Sample:\")\ndisplay(taxonomy.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:44.079857Z","iopub.execute_input":"2025-05-22T20:23:44.080263Z","iopub.status.idle":"2025-05-22T20:23:44.118212Z","shell.execute_reply.started":"2025-05-22T20:23:44.080233Z","shell.execute_reply":"2025-05-22T20:23:44.117372Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Check for missing values\nprint(\"❌ MISSING VALUES CHECK\")\nprint(\"-\" * 30)\nprint(\"Training Data:\")\nprint(train.isnull().sum())\nprint(\"\\nTaxonomy Data:\")\nprint(taxonomy.isnull().sum())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:44.119268Z","iopub.execute_input":"2025-05-22T20:23:44.119969Z","iopub.status.idle":"2025-05-22T20:23:44.145153Z","shell.execute_reply.started":"2025-05-22T20:23:44.119937Z","shell.execute_reply":"2025-05-22T20:23:44.144320Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🐦 2. Species Diversity Analysis","metadata":{}},{"cell_type":"code","source":"# Merge datasets for comprehensive analysis\nmerged_df = pd.merge(train, taxonomy, on=\"primary_label\", how=\"left\")\n\n# Basic statistics\ntotal_recordings = len(merged_df)\nunique_species = train[\"primary_label\"].nunique()\nunique_classes = taxonomy[\"class_name\"].nunique()\n\nprint(\"🐦 SPECIES DIVERSITY ANALYSIS\")\nprint(\"=\"*40)\nprint(f\"📊 Total Recordings: {total_recordings:,}\")\nprint(f\"🔢 Unique Species: {unique_species}\")\nprint(f\"📂 Unique Classes: {unique_classes}\")\n\n# Class distribution\nclass_counts = merged_df[\"class_name\"].value_counts()\nprint(f\"\\n📈 RECORDINGS PER CLASS:\")\nfor class_name, count in class_counts.items():\n    percentage = (count / total_recordings) * 100\n    print(f\"  {class_name}: {count:,} ({percentage:.1f}%)\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:44.146078Z","iopub.execute_input":"2025-05-22T20:23:44.146420Z","iopub.status.idle":"2025-05-22T20:23:44.192868Z","shell.execute_reply.started":"2025-05-22T20:23:44.146391Z","shell.execute_reply":"2025-05-22T20:23:44.192040Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 📊 3. Comprehensive Visualizations Dashboard","metadata":{}},{"cell_type":"code","source":"# Create a comprehensive figure with multiple subplots\nfig = plt.figure(figsize=(20, 15))\n\n# 1. Class Distribution\nax1 = plt.subplot(3, 3, 1)\nclass_counts.plot(kind='bar', color=['#2E86AB', '#A23B72', '#F18F01', '#C73E1D'])\nplt.title('🔢 Recordings per Class', fontsize=14, fontweight='bold')\nplt.xlabel('Class Name')\nplt.ylabel('Number of Recordings')\nplt.xticks(rotation=45)\nplt.grid(axis='y', alpha=0.3)\n\n# 2. Species per Class\nax2 = plt.subplot(3, 3, 2)\nspecies_per_class = merged_df.groupby(\"class_name\")[\"primary_label\"].nunique()\nspecies_per_class.plot(kind='bar', color=['#2E86AB', '#A23B72', '#F18F01', '#C73E1D'])\nplt.title('🐦 Unique Species per Class', fontsize=14, fontweight='bold')\nplt.xlabel('Class Name')\nplt.ylabel('Number of Species')\nplt.xticks(rotation=45)\nplt.grid(axis='y', alpha=0.3)\n\n# 3. Collection Source Distribution\nax3 = plt.subplot(3, 3, 3)\ncollection_counts = merged_df['collection'].value_counts()\ncolors = ['#FF6B6B', '#4ECDC4', '#45B7D1']\nplt.pie(collection_counts.values, labels=collection_counts.index, autopct='%1.1f%%', colors=colors)\nplt.title('📚 Data Sources Distribution', fontsize=14, fontweight='bold')\n\n# 4. Rating Distribution (XC only)\nax4 = plt.subplot(3, 3, 4)\nxc_data = merged_df[merged_df['collection'] == 'XC']\nxc_ratings = xc_data[xc_data['rating'] > 0]['rating']\nplt.hist(xc_ratings, bins=20, color='#FF6B6B', alpha=0.7, edgecolor='black')\nplt.title('⭐ Rating Distribution (XC Collection)', fontsize=14, fontweight='bold')\nplt.xlabel('Rating')\nplt.ylabel('Frequency')\nplt.grid(axis='y', alpha=0.3)\n\n# 5. Top 20 Species by Recording Count\nax5 = plt.subplot(3, 3, 5)\ntop_species = train.groupby('primary_label')['filename'].count().sort_values(ascending=False).head(20)\ntop_species.plot(kind='barh', color='#4ECDC4')\nplt.title('🏆 Top 20 Species by Recording Count', fontsize=14, fontweight='bold')\nplt.xlabel('Number of Recordings')\n\n# 6. Long Tail Distribution\nax6 = plt.subplot(3, 3, 6)\nspecies_counts = train.groupby('primary_label')['filename'].count().sort_values(ascending=False)\nplt.loglog(range(1, len(species_counts) + 1), species_counts.values, 'bo-', alpha=0.7)\nplt.title('📈 Long Tail Distribution (Log Scale)', fontsize=14, fontweight='bold')\nplt.xlabel('Species Rank')\nplt.ylabel('Number of Recordings')\nplt.grid(True, alpha=0.3)\n\n# 7. Geographical Distribution\nax7 = plt.subplot(3, 3, (7, 8))\n# Sample data for faster plotting\nsample_size = min(5000, len(merged_df))\ngeo_sample = merged_df.sample(n=sample_size, random_state=42)\n\nscatter = plt.scatter(geo_sample['longitude'], geo_sample['latitude'], \n                     c=pd.Categorical(geo_sample['class_name']).codes, \n                     cmap='viridis', alpha=0.6, s=10)\nplt.title('🌍 Global Distribution of Recordings', fontsize=14, fontweight='bold')\nplt.xlabel('Longitude')\nplt.ylabel('Latitude')\nplt.grid(True, alpha=0.3)\n\n# Add colorbar\ncbar = plt.colorbar(scatter)\ncbar.set_label('Class Type')\n\n# 8. Average Rating by Class\nax8 = plt.subplot(3, 3, 9)\navg_rating_by_class = merged_df[merged_df['rating'] > 0].groupby('class_name')['rating'].mean()\navg_rating_by_class.plot(kind='bar', color=['#2E86AB', '#A23B72', '#F18F01', '#C73E1D'])\nplt.title('⭐ Average Rating by Class', fontsize=14, fontweight='bold')\nplt.xlabel('Class Name')\nplt.ylabel('Average Rating')\nplt.xticks(rotation=45)\nplt.grid(axis='y', alpha=0.3)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:44.193880Z","iopub.execute_input":"2025-05-22T20:23:44.194160Z","iopub.status.idle":"2025-05-22T20:23:46.530863Z","shell.execute_reply.started":"2025-05-22T20:23:44.194141Z","shell.execute_reply":"2025-05-22T20:23:46.529833Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🔬 4. Detailed Class Analysis","metadata":{}},{"cell_type":"code","source":"classes = ['Aves', 'Amphibia', 'Mammalia', 'Insecta']\nclass_colors = ['#2E86AB', '#A23B72', '#F18F01', '#C73E1D']\n\nfig, axes = plt.subplots(2, 2, figsize=(16, 12))\naxes = axes.ravel()\n\nfor i, class_name in enumerate(classes):\n    class_data = merged_df[merged_df['class_name'] == class_name]\n    species_counts = class_data.groupby('primary_label')['filename'].count().sort_values(ascending=False)\n    \n    # Plot top 20 species for each class\n    top_20 = species_counts.head(20)\n    axes[i].barh(range(len(top_20)), top_20.values, color=class_colors[i], alpha=0.8)\n    axes[i].set_yticks(range(len(top_20)))\n    axes[i].set_yticklabels(top_20.index, fontsize=8)\n    axes[i].set_xlabel('Number of Recordings')\n    axes[i].set_title(f'🔍 Top Species in {class_name} Class', fontweight='bold')\n    axes[i].grid(axis='x', alpha=0.3)\n    \n    # Add summary statistics\n    total_recordings = len(class_data)\n    unique_species = class_data['primary_label'].nunique()\n    axes[i].text(0.02, 0.98, f'Total: {total_recordings:,}\\nSpecies: {unique_species}', \n                transform=axes[i].transAxes, fontsize=10, verticalalignment='top',\n                bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:46.534145Z","iopub.execute_input":"2025-05-22T20:23:46.534771Z","iopub.status.idle":"2025-05-22T20:23:47.599607Z","shell.execute_reply.started":"2025-05-22T20:23:46.534736Z","shell.execute_reply":"2025-05-22T20:23:47.598689Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🌍 5. Geographic Analysis","metadata":{}},{"cell_type":"code","source":"# Geographic statistics by class\ngeo_stats = merged_df.groupby('class_name').agg({\n    'latitude': ['min', 'max', 'mean'],\n    'longitude': ['min', 'max', 'mean'],\n    'primary_label': 'count'\n}).round(2)\n\nprint(\"🌍 GEOGRAPHIC ANALYSIS\")\nprint(\"=\"*30)\nprint(\"Geographic Distribution Statistics:\")\ndisplay(geo_stats)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:47.600453Z","iopub.execute_input":"2025-05-22T20:23:47.600721Z","iopub.status.idle":"2025-05-22T20:23:47.628021Z","shell.execute_reply.started":"2025-05-22T20:23:47.600699Z","shell.execute_reply":"2025-05-22T20:23:47.627249Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load the world map from Geopandas\nworld = gpd.read_file(gpd.datasets.get_path(\"naturalearth_lowres\"))\n\n# Create individual geographic plots for each class\nfig, axes = plt.subplots(2, 2, figsize=(16, 10))\naxes = axes.ravel()\n\nfor i, class_name in enumerate(classes):\n    class_data = merged_df[merged_df[\"class_name\"] == class_name]\n    \n    # Plot the world map background\n    world.plot(ax=axes[i], color=\"lightgray\", edgecolor=\"black\", alpha=0.5)\n    \n    # Scatter plot for species locations\n    axes[i].scatter(class_data[\"longitude\"], class_data[\"latitude\"], \n                   alpha=0.6, s=10, color=class_colors[i])\n    \n    axes[i].set_title(f'🌍 {class_name} Geographic Distribution', fontweight=\"bold\")\n    axes[i].set_xlabel(\"Longitude\")\n    axes[i].set_ylabel(\"Latitude\")\n    axes[i].grid(True, alpha=0.3)\n    \n    # Add count annotation\n    count = len(class_data)\n    axes[i].text(0.02, 0.98, f'Records: {count:,}', \n                 transform=axes[i].transAxes, fontsize=10, verticalalignment=\"top\",\n                 bbox=dict(boxstyle=\"round\", facecolor=\"white\", alpha=0.8))\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:25:32.965468Z","iopub.execute_input":"2025-05-22T20:25:32.966311Z","iopub.status.idle":"2025-05-22T20:25:36.635118Z","shell.execute_reply.started":"2025-05-22T20:25:32.966281Z","shell.execute_reply":"2025-05-22T20:25:36.634268Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🔊 6. Audio Data Analysis","metadata":{}},{"cell_type":"code","source":"# Analyze train_soundscapes directory\nsoundscape_path = \"/kaggle/input/birdclef-2025/train_soundscapes/\"\nsoundscape_files = [f for f in os.listdir(soundscape_path) if f.endswith('.ogg')]\n\nprint(\"🔊 AUDIO DATA ANALYSIS\")\nprint(\"=\"*30)\nprint(f\"📁 Soundscape Files: {len(soundscape_files)}\")\n\n# Sample analysis of audio characteristics\nsample_size = min(2000, len(soundscape_files))\nsampled_files = random.sample(soundscape_files, sample_size)\n\nprint(f\"🎵 Analyzing {sample_size} sample files for audio characteristics...\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:48.524018Z","iopub.execute_input":"2025-05-22T20:23:48.524293Z","iopub.status.idle":"2025-05-22T20:23:48.623623Z","shell.execute_reply.started":"2025-05-22T20:23:48.524270Z","shell.execute_reply":"2025-05-22T20:23:48.622801Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"durations = []\nrms_values = []\n\nfor file in tqdm(sampled_files, desc=\"Processing audio\"):\n    try:\n        audio_path = os.path.join(soundscape_path, file)\n        waveform, sample_rate = torchaudio.load(audio_path)\n        \n        # Calculate duration\n        duration = waveform.shape[1] / sample_rate\n        durations.append(duration)\n        \n        # Calculate RMS energy (noise level indicator)\n        rms_energy = torch.sqrt(torch.mean(waveform ** 2)).item()\n        rms_values.append(rms_energy)\n        \n    except Exception as e:\n        print(f\"Error processing {file}: {e}\")\n        continue\n\nprint(f\"✅ Successfully processed {len(durations)} audio files\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:48.624270Z","iopub.execute_input":"2025-05-22T20:23:48.624491Z","iopub.status.idle":"2025-05-22T20:23:55.326220Z","shell.execute_reply.started":"2025-05-22T20:23:48.624475Z","shell.execute_reply":"2025-05-22T20:23:55.325258Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Plot audio characteristics\nif durations and rms_values:\n    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))\n    \n    # Duration distribution\n    ax1.hist(durations, bins=20, color='#4ECDC4', alpha=0.7, edgecolor='black')\n    ax1.set_xlabel('Duration (seconds)')\n    ax1.set_ylabel('Frequency')\n    ax1.set_title('🕐 Audio Duration Distribution')\n    ax1.grid(axis='y', alpha=0.3)\n    ax1.axvline(np.mean(durations), color='red', linestyle='--', \n               label=f'Mean: {np.mean(durations):.1f}s')\n    ax1.legend()\n    \n    # RMS energy distribution\n    ax2.hist(rms_values, bins=20, color='#FF6B6B', alpha=0.7, edgecolor='black')\n    ax2.set_xlabel('RMS Energy')\n    ax2.set_ylabel('Frequency')\n    ax2.set_title('📊 Background Noise Level Distribution')\n    ax2.grid(axis='y', alpha=0.3)\n    ax2.axvline(np.mean(rms_values), color='red', linestyle='--', \n               label=f'Mean: {np.mean(rms_values):.4f}')\n    ax2.legend()\n    \n    plt.tight_layout()\n    plt.show()\n    \n    # Print statistics\n    print(f\"📊 Audio Statistics:\")\n    print(f\"   Duration: {np.mean(durations):.1f}±{np.std(durations):.1f} seconds\")\n    print(f\"   RMS Energy: {np.mean(rms_values):.4f}±{np.std(rms_values):.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:55.327170Z","iopub.execute_input":"2025-05-22T20:23:55.327425Z","iopub.status.idle":"2025-05-22T20:23:56.041409Z","shell.execute_reply.started":"2025-05-22T20:23:55.327406Z","shell.execute_reply":"2025-05-22T20:23:56.040284Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 📋 7. Data Quality Assessment","metadata":{}},{"cell_type":"code","source":"# Data quality checks\nprint(\"🔍 DATA QUALITY ASSESSMENT\")\nprint(\"=\"*40)\n\n# Check for species with very few recordings\nspecies_counts = train.groupby('primary_label')['filename'].count()\nlow_count_species = species_counts[species_counts < 5]\n\nprint(f\"📊 Recording Distribution:\")\nprint(f\"   Total species: {len(species_counts)}\")\nprint(f\"   Species with <5 recordings: {len(low_count_species)} ({len(low_count_species)/len(species_counts)*100:.1f}%)\")\nprint(f\"   Species with <10 recordings: {len(species_counts[species_counts < 10])} ({len(species_counts[species_counts < 10])/len(species_counts)*100:.1f}%)\")\n\n# Rating quality for XC collection\nxc_data = merged_df[merged_df['collection'] == 'XC']\nrated_recordings = len(xc_data[xc_data['rating'] > 0])\ntotal_xc = len(xc_data)\n\nprint(f\"\\n⭐ Rating Coverage (XC Collection):\")\nprint(f\"   Rated recordings: {rated_recordings:,}/{total_xc:,} ({rated_recordings/total_xc*100:.1f}%)\")\nprint(f\"   Average rating: {xc_data[xc_data['rating'] > 0]['rating'].mean():.2f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:56.042532Z","iopub.execute_input":"2025-05-22T20:23:56.042910Z","iopub.status.idle":"2025-05-22T20:23:56.071191Z","shell.execute_reply.started":"2025-05-22T20:23:56.042878Z","shell.execute_reply":"2025-05-22T20:23:56.070257Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 💡 8. Key Insights and Recommendations","metadata":{}},{"cell_type":"code","source":"print(\"📊 KEY INSIGHTS SUMMARY\")\nprint(\"=\"*50)\n\nprint(\"🎯 DATASET CHARACTERISTICS:\")\nprint(f\"   • Total recordings: {total_recordings:,}\")\nprint(f\"   • Unique species: {unique_species}\")\nprint(f\"   • Data sources: {', '.join(collection_counts.index)}\")\nprint(f\"   • Dominant class: {class_counts.index[0]} ({class_counts.iloc[0]:,} recordings)\")\n\nprint(\"\\n🔍 DATA DISTRIBUTION:\")\nprint(\"   • Highly imbalanced dataset with long-tail distribution\")\nprint(\"   • Aves (birds) dominate with 97% of recordings\")\nprint(\"   • Geographic concentration in Americas and Europe\")\n\nprint(\"\\n⚠️  MODELING CONSIDERATIONS:\")\nprint(\"   • Class imbalance requires careful sampling strategies\")\nprint(\"   • Long-tail distribution suggests need for data augmentation\")\nprint(\"   • Geographic bias may affect model generalization\")\nprint(\"   • Multi-source data requires consistent preprocessing\")\n\nprint(\"\\n💡 RECOMMENDATIONS:\")\nprint(\"   • Use stratified sampling for train/validation splits\")\nprint(\"   • Apply class weighting or focal loss for imbalanced classes\")\nprint(\"   • Consider geographic stratification for robust evaluation\")\nprint(\"   • Implement data augmentation for rare species\")\nprint(\"   • Filter low-quality recordings based on ratings\")\n\nprint(\"\\n✅ Analysis Complete! Ready for modeling phase.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-22T20:23:56.072174Z","iopub.execute_input":"2025-05-22T20:23:56.072872Z","iopub.status.idle":"2025-05-22T20:23:56.080868Z","shell.execute_reply.started":"2025-05-22T20:23:56.072838Z","shell.execute_reply":"2025-05-22T20:23:56.079733Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---\n\n## 🚀 Next Steps\n\nBased on this analysis, here are the recommended next steps:\n\n1. **Data Preprocessing**: Implement audio normalization and feature extraction\n2. **Model Selection**: Consider architectures suitable for audio classification\n3. **Training Strategy**: Design sampling and augmentation strategies for imbalanced data\n4. **Evaluation**: Set up proper validation with geographic and temporal splits\n\nGood luck with the BirdCLEF 2025 competition! 🏆","metadata":{}}]}