{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":59156,"databundleVersionId":13874099,"sourceType":"competition"}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-09-28T16:44:23.286775Z","iopub.execute_input":"2025-09-28T16:44:23.287004Z","iopub.status.idle":"2025-09-28T16:44:36.316383Z","shell.execute_reply.started":"2025-09-28T16:44:23.286981Z","shell.execute_reply":"2025-09-28T16:44:36.315598Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================================\n# EXPLORATORY DATA ANALYSIS (EDA) & MACHINE LEARNING PIPELINE\n# ============================================================================\n# Versi: 1.0 | Tujuan: Analisis data otomatis + pemodelan ML dasar\n# ============================================================================\n\n# 1. IMPORT LIBRARIES\n# ============================================================================\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# ML Libraries\nfrom sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV\nfrom sklearn.preprocessing import StandardScaler, LabelEncoder, OneHotEncoder\nfrom sklearn.impute import SimpleImputer\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.metrics import (\n    accuracy_score, precision_score, recall_score, f1_score, roc_auc_score,\n    mean_squared_error, r2_score, classification_report, confusion_matrix,\n    ConfusionMatrixDisplay, RocCurveDisplay\n)\n\n# Models\nfrom sklearn.ensemble import RandomForestClassifier, RandomForestRegressor\nfrom sklearn.linear_model import LogisticRegression, LinearRegression\nfrom sklearn.svm import SVC, SVR\nfrom xgboost import XGBClassifier, XGBRegressor\n\n# Set style\nplt.style.use('seaborn-v0_8-whitegrid')\nsns.set_palette(\"Set2\")\npd.set_option('display.max_columns', None)\npd.set_option('display.width', None)\n\n# ============================================================================\n# 2. LOAD DATA\n# ============================================================================\n# Ganti dengan path dataset Anda\ndf = pd.read_csv('/kaggle/input/MABe-mouse-behavior-detection/train.csv')  # 👈 GANTI NAMA FILE DI SINI\n\n# Atau jika dataset ada di direktori input Kaggle:\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         df = pd.read_csv(os.path.join(dirname, filename))\n#         break\n\nprint(\"✅ Data berhasil dimuat!\")\nprint(f\"Shape: {df.shape}\")\nprint(\"\\n5 baris pertama:\")\nprint(df.head())\n\n# ============================================================================\n# 3. EDA: EXPLORATORY DATA ANALYSIS\n# ============================================================================\n\n# --- 3.1 Informasi Dasar ---\nprint(\"\\n\" + \"=\"*60)\nprint(\"📊 INFORMASI DASAR DATASET\")\nprint(\"=\"*60)\nprint(df.info())\nprint(\"\\nStatistik Deskriptif:\")\nprint(df.describe(include='all').T)\n\n# --- 3.2 Missing Values ---\nprint(\"\\n\" + \"=\"*60)\nprint(\"🔍 MISSING VALUES\")\nprint(\"=\"*60)\nmissing = df.isnull().sum()\nmissing = missing[missing > 0].sort_values(ascending=False)\nif missing.empty:\n    print(\"✅ Tidak ada missing values.\")\nelse:\n    print(missing)\n    plt.figure(figsize=(10, 4))\n    sns.heatmap(df.isnull(), cbar=True, yticklabels=False, cmap='viridis')\n    plt.title('Heatmap Missing Values')\n    plt.show()\n\n# --- 3.3 Distribusi Target (Ganti 'target' dengan nama kolom target Anda!) ---\nTARGET = 'behaviors_labeled'\nIS_CLASSIFICATION = True   # atau sesuaikan\n\nprint(\"\\n\" + \"=\"*60)\nprint(f\"🎯 DISTRIBUSI TARGET: '{TARGET}'\")\nprint(\"=\"*60)\nif TARGET not in df.columns:\n    raise ValueError(f\"Kolom target '{TARGET}' tidak ditemukan! Kolom yang tersedia: {list(df.columns)}\")\n\nif IS_CLASSIFICATION:\n    print(df[TARGET].value_counts())\n    plt.figure(figsize=(8, 5))\n    sns.countplot(x=df[TARGET], palette='Set2')\n    plt.title(f'Distribusi Kelas: {TARGET}')\n    plt.show()\nelse:\n    plt.figure(figsize=(8, 5))\n    sns.histplot(df[TARGET], kde=True, color='skyblue')\n    plt.title(f'Distribusi Target (Regresi): {TARGET}')\n    plt.show()\n\n# --- 3.4 Distribusi Fitur Numerik ---\nnum_cols = df.select_dtypes(include=np.number).columns.tolist()\nnum_cols = [col for col in num_cols if col != TARGET]\n\nif num_cols:\n    print(\"\\n📈 DISTRIBUSI FITUR NUMERIK\")\n    n_cols = min(3, len(num_cols))\n    n_rows = (len(num_cols) + n_cols - 1) // n_cols\n    fig, axes = plt.subplots(n_rows, n_cols, figsize=(5*n_cols, 4*n_rows))\n    axes = axes.flatten() if len(num_cols) > 1 else [axes]\n    \n    for i, col in enumerate(num_cols):\n        sns.histplot(df[col].dropna(), kde=True, ax=axes[i], color='lightcoral')\n        axes[i].set_title(f'{col}')\n    \n    # Sembunyikan subplot kosong\n    for j in range(i+1, len(axes)):\n        axes[j].axis('off')\n    \n    plt.tight_layout()\n    plt.show()\n\n# --- 3.5 Korelasi (Numerik) ---\n# Ambil kolom numerik benar-benar (exclude target kalau numeric)\nnum_cols = [c for c in df.select_dtypes(include=[np.number]).columns if c != TARGET]\n\nprint(\"Kolom numerik:\", num_cols)\n\nif len(num_cols) == 0:\n    print(\">> Tidak ada kolom numerik untuk dihitung korelasinya.\")\nelse:\n    # Optional: Buang kolom numerik yang constant (std = 0) karena tidak informatif\n    constant_num = [c for c in num_cols if df[c].nunique() <= 1]\n    if constant_num:\n        print(\"Kolom numerik konstan di-drop:\", constant_num)\n        num_cols = [c for c in num_cols if c not in constant_num]\n\n    corr = df[num_cols].corr()\n\n    # Kalau semua NaN (misal karena kolom sangat spars / banyak NaN)\n    if corr.isna().all().all():\n        print(\">> Korelasi tidak dapat dihitung (semua NaN). Periksa missing values di fitur numerik.\")\n    else:\n        plt.figure(figsize=(min(1+len(num_cols), 14), min(1+len(num_cols), 10)))\n        mask = np.triu(np.ones_like(corr, dtype=bool))\n        sns.heatmap(\n            corr,\n            mask=mask,\n            cmap='coolwarm',\n            annot=False,\n            fmt='.2f',\n            square=True,\n            cbar_kws={'shrink': 0.7}\n        )\n        plt.title('Matriks Korelasi (Hanya Fitur Numerik)')\n        plt.tight_layout()\n        plt.show()\n\n# --- 3.6 Fitur Kategorikal ---\ncat_cols = [c for c in df.select_dtypes(exclude=[np.number]).columns if c != TARGET]\nprint(f\"\\nJumlah fitur kategorikal (exclude TARGET): {len(cat_cols)}\")\n\nif cat_cols:\n    print(\"\\n⚙️  CONTOH 5 FITUR KATEGORIKAL:\")\n    for col in cat_cols[:5]:\n        nunique = df[col].nunique()\n        print(f\"\\n{col} -> {nunique} kategori unik\")\n        print(df[col].value_counts().head())\nelse:\n    print(\">> Tidak ada fitur kategorikal selain target.\")\n\n# --- 3.7 Encoding Target (single-label) ---\nfrom sklearn.preprocessing import LabelEncoder\nle = LabelEncoder()\ny = le.fit_transform(df[TARGET])\nprint(\"\\nMapping label (contoh 10):\", dict(zip(le.classes_[:10], range(min(len(le.classes_),10)))))\nprint(\"Jumlah kelas:\", len(le.classes_))\n\n# --- 3.8 Siapkan X (gabung numerik + kategorikal yang di-encode) ---\n# Contoh sederhana: one-hot encode kategorikal selain target.\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.impute import SimpleImputer\nfrom sklearn.linear_model import LogisticRegression\n\nX = df[num_cols + cat_cols].copy()\n\n# Pipeline:\nnumeric_transformer = Pipeline(steps=[\n    (\"imputer\", SimpleImputer(strategy=\"median\"))\n])\n\ncategorical_transformer = Pipeline(steps=[\n    (\"imputer\", SimpleImputer(strategy=\"most_frequent\")),\n    (\"ohe\", OneHotEncoder(handle_unknown=\"ignore\"))\n])\n\npreprocessor = ColumnTransformer(\n    transformers=[\n        (\"num\", numeric_transformer, num_cols),\n        (\"cat\", categorical_transformer, cat_cols)\n    ]\n)\n\nmodel = Pipeline(steps=[\n    (\"prep\", preprocessor),\n    (\"clf\", LogisticRegression(max_iter=1000))\n])\n\n# --- 3.9 Train-test split ---\nfrom sklearn.model_selection import train_test_split\n\n# Pastikan tidak ada kelas yang frekuensinya <2 jika ingin stratify\nvc = pd.Series(y).value_counts()\nrare = vc[vc < 2]\nif not rare.empty:\n    print(\"\\nPERINGATAN: Ada kelas sangat langka (freq <2). Stratify bisa gagal. Kelas langka:\", rare.to_dict())\n    use_stratify = False\nelse:\n    use_stratify = True\n\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y,\n    test_size=0.2,\n    random_state=42,\n    stratify=y if use_stratify else None\n)\n\nprint(\"Shape train:\", X_train.shape, \"test:\", X_test.shape)\n\n# --- 3.10 Fit model cepat (untuk sanity check) ---\nmodel.fit(X_train, y_train)\nprint(\"Skor train:\", model.score(X_train, y_train))\nprint(\"Skor test :\", model.score(X_test, y_test))\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-28T17:11:03.561394Z","iopub.execute_input":"2025-09-28T17:11:03.561716Z","iopub.status.idle":"2025-09-28T17:12:39.829522Z","shell.execute_reply.started":"2025-09-28T17:11:03.56169Z","shell.execute_reply":"2025-09-28T17:12:39.828648Z"},"_kg_hide-input":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================================\n# 4. PREPROCESSING\n# ============================================================================\n\n# Pisahkan fitur dan target\nX = df.drop(columns=[TARGET])\ny = df[TARGET]\n\n# Handle missing values & encoding\nnumeric_features = X.select_dtypes(include=[np.number]).columns\ncategorical_features = X.select_dtypes(exclude=[np.number]).columns\n\n# Preprocessor\nnumeric_transformer = Pipeline(steps=[\n    ('imputer', SimpleImputer(strategy='median')),\n    ('scaler', StandardScaler())\n])\n\ncategorical_transformer = Pipeline(steps=[\n    ('imputer', SimpleImputer(strategy='most_frequent')),\n    ('onehot', OneHotEncoder(handle_unknown='ignore'))\n])\n\npreprocessor = ColumnTransformer(\n    transformers=[\n        ('num', numeric_transformer, numeric_features),\n        ('cat', categorical_transformer, categorical_features)\n    ]\n)\n\n# Split data\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.2, random_state=42, \n    stratify=y if IS_CLASSIFICATION else None\n)\n\nprint(f\"\\n✅ Data dibagi: Train={X_train.shape}, Test={X_test.shape}\")\n\n# ============================================================================\n# 5. MACHINE LEARNING MODELING\n# ============================================================================\n\n# Pilih model berdasarkan jenis masalah\nif IS_CLASSIFICATION:\n    models = {\n        'Logistic Regression': LogisticRegression(max_iter=1000),\n        'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),\n        'XGBoost': XGBClassifier(random_state=42, use_label_encoder=False, eval_metric='logloss')\n    }\n    scoring = 'accuracy'\nelse:\n    models = {\n        'Linear Regression': LinearRegression(),\n        'Random Forest': RandomForestRegressor(n_estimators=100, random_state=42),\n        'XGBoost': XGBRegressor(random_state=42)\n    }\n    scoring = 'r2'\n\n# Latih dan evaluasi model\nresults = {}\nbest_model = None\nbest_score = -np.inf if IS_CLASSIFICATION else -np.inf\n\nprint(\"\\n\" + \"=\"*60)\nprint(\"🤖 TRAINING & EVALUASI MODEL\")\nprint(\"=\"*60)\n\nfor name, model in models.items():\n    # Buat pipeline\n    pipeline = Pipeline(steps=[\n        ('preprocessor', preprocessor),\n        ('model', model)\n    ])\n    \n    # Cross-validation\n    cv_scores = cross_val_score(pipeline, X_train, y_train, cv=5, scoring=scoring)\n    mean_score = cv_scores.mean()\n    std_score = cv_scores.std()\n    \n    # Simpan hasil\n    results[name] = {'cv_mean': mean_score, 'cv_std': std_score}\n    \n    # Cari model terbaik\n    if mean_score > best_score:\n        best_score = mean_score\n        best_model = pipeline\n        best_name = name\n    \n    print(f\"{name:20} | CV {scoring}: {mean_score:.4f} ± {std_score:.4f}\")\n\n# Latih model terbaik pada seluruh data train\nbest_model.fit(X_train, y_train)\ny_pred = best_model.predict(X_test)\n\nprint(f\"\\n🏆 Model Terbaik: {best_name} (CV {scoring}: {best_score:.4f})\")\n\n# ============================================================================\n# 6. EVALUASI AKHIR\n# ============================================================================\n\nprint(\"\\n\" + \"=\"*60)\nprint(\"📊 EVALUASI MODEL TERBAIK PADA DATA TEST\")\nprint(\"=\"*60)\n\nif IS_CLASSIFICATION:\n    # Metrik klasifikasi\n    acc = accuracy_score(y_test, y_pred)\n    prec = precision_score(y_test, y_pred, average='weighted')\n    rec = recall_score(y_test, y_pred, average='weighted')\n    f1 = f1_score(y_test, y_pred, average='weighted')\n    \n    print(f\"Akurasi   : {acc:.4f}\")\n    print(f\"Presisi   : {prec:.4f}\")\n    print(f\"Recall    : {rec:.4f}\")\n    print(f\"F1-Score  : {f1:.4f}\")\n    \n    # Confusion Matrix\n    plt.figure(figsize=(8, 6))\n    cm = confusion_matrix(y_test, y_pred)\n    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')\n    plt.title('Confusion Matrix')\n    plt.ylabel('True Label')\n    plt.xlabel('Predicted Label')\n    plt.show()\n    \n    # Classification Report\n    print(\"\\nLaporan Klasifikasi:\")\n    print(classification_report(y_test, y_pred))\n    \nelse:\n    # Metrik regresi\n    mse = mean_squared_error(y_test, y_pred)\n    rmse = np.sqrt(mse)\n    r2 = r2_score(y_test, y_pred)\n    \n    print(f\"MSE  : {mse:.4f}\")\n    print(f\"RMSE : {rmse:.4f}\")\n    print(f\"R²   : {r2:.4f}\")\n    \n    # Plot prediksi vs aktual\n    plt.figure(figsize=(8, 6))\n    plt.scatter(y_test, y_pred, alpha=0.6, color='teal')\n    plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)\n    plt.xlabel('Nilai Aktual')\n    plt.ylabel('Nilai Prediksi')\n    plt.title('Prediksi vs Aktual')\n    plt.show()\n\n# ============================================================================\n# 7. FEATURE IMPORTANCE (Jika model mendukung)\n# ============================================================================\n\nif hasattr(best_model.named_steps['model'], 'feature_importances_'):\n    # Ambil nama fitur setelah preprocessing\n    feature_names = (\n        numeric_features.tolist() +\n        list(best_model.named_steps['preprocessor']\n             .named_transformers_['cat']\n             .named_steps['onehot']\n             .get_feature_names_out(categorical_features))\n    )\n    \n    importances = best_model.named_steps['model'].feature_importances_\n    feat_imp = pd.DataFrame({'feature': feature_names, 'importance': importances})\n    feat_imp = feat_imp.sort_values('importance', ascending=False).head(15)\n    \n    plt.figure(figsize=(10, 6))\n    sns.barplot(data=feat_imp, y='feature', x='importance', palette='viridis')\n    plt.title('Top 15 Feature Importance')\n    plt.xlabel('Importance')\n    plt.tight_layout()\n    plt.show()\n\n# ============================================================================\n# 8. SIMPAN MODEL (Opsional)\n# ============================================================================\n# import joblib\n# joblib.dump(best_model, 'best_model.pkl')\n# print(\"\\n💾 Model disimpan sebagai 'best_model.pkl'\")\n\nprint(\"\\n✅ Analisis selesai!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-28T17:14:18.040995Z","iopub.execute_input":"2025-09-28T17:14:18.041598Z","iopub.status.idle":"2025-09-28T17:14:18.069519Z","shell.execute_reply.started":"2025-09-28T17:14:18.041549Z","shell.execute_reply":"2025-09-28T17:14:18.068525Z"}},"outputs":[],"execution_count":null}]}