update 01 file train_odc.py

This commit is contained in:
Victor Phan
2026-02-27 14:36:54 +07:00
parent 5d6efcf56a
commit 3162639529
+79 -44
View File
@@ -726,7 +726,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 16, "execution_count": null,
"id": "2e955884-d4af-422d-a8e6-d436199540e0", "id": "2e955884-d4af-422d-a8e6-d436199540e0",
"metadata": { "metadata": {
"tags": [] "tags": []
@@ -772,57 +772,100 @@
" print(\" (Sử dụng nhiều spectral indices để cải thiện accuracy)\")\n", " print(\" (Sử dụng nhiều spectral indices để cải thiện accuracy)\")\n",
" \n", " \n",
" try:\n", " try:\n",
" # ── FIX 1: Reproject training points to match raster CRS ──────────────\n",
" # Shapefile thường ở WGS84 (EPSG:4326, lon/lat ~105-106)\n",
" # Raster data ở UTM (EPSG:32648, easting ~500000+)\n",
" # Nếu không reproject → .sel() sẽ chọn sai pixel hoàn toàn!\n",
" raster_crs = None\n",
" try:\n",
" # Ưu tiên lấy CRS từ rioxarray\n",
" raster_crs = data.rio.crs\n",
" except Exception:\n",
" pass\n",
" if raster_crs is None:\n",
" # Fallback: dùng biến native_crs đã định nghĩa ở cell load data\n",
" raster_crs = native_crs if 'native_crs' in dir() else 'EPSG:32648'\n",
"\n",
" train_src_crs = train.crs if train.crs is not None else 'EPSG:4326'\n",
" print(f\" Training CRS : {train_src_crs}\")\n",
" print(f\" Raster CRS : {raster_crs}\")\n",
"\n",
" if str(train_src_crs).upper() != str(raster_crs).upper():\n",
" train_proj = train.to_crs(raster_crs)\n",
" print(f\" ✅ Reprojected training points → {raster_crs}\")\n",
" else:\n",
" train_proj = train\n",
" print(f\" ✅ CRS already match, no reprojection needed\")\n",
"\n",
" # Extract features at training point locations\n", " # Extract features at training point locations\n",
" X = []\n", " X = []\n",
" y = []\n", " y = []\n",
" \n", " skipped_nan = 0\n",
" skipped_label = 0\n",
" skipped_other = 0\n",
"\n",
" # Available features from data\n", " # Available features from data\n",
" available_features = ['ndvi_mean', 'ndvi_min', 'ndvi_max', 'ndvi_std', 'ndvi_range',\n", " available_features = ['ndvi_mean', 'ndvi_min', 'ndvi_max', 'ndvi_std', 'ndvi_range',\n",
" 'ndwi_mean', 'ndbi_mean', 'evi_mean']\n", " 'ndwi_mean', 'ndbi_mean', 'evi_mean']\n",
" \n", "\n",
" # Check which features are actually available\n", " # Check which features are actually available\n",
" features_to_use = [f for f in available_features if f in data.data_vars]\n", " features_to_use = [f for f in available_features if f in data.data_vars]\n",
" \n", "\n",
" if not features_to_use:\n", " if not features_to_use:\n",
" print(\" ❌ No spectral features found in dataset!\")\n", " print(\" ❌ No spectral features found in dataset!\")\n",
" print(\" Available variables:\", list(data.data_vars))\n", " print(\" Available variables:\", list(data.data_vars))\n",
" model = None\n", " model = None\n",
" else:\n", " else:\n",
" print(f\" Using {len(features_to_use)} features: {features_to_use}\")\n", " print(f\" Using {len(features_to_use)} features: {features_to_use}\")\n",
" \n", "\n",
" for idx, point in train.iterrows():\n", " for idx, point in train_proj.iterrows():\n",
" try:\n", " try:\n",
" # ── FIX 2: Dùng tọa độ đã reproject ──────────────────────\n",
" px, py = point.geometry.x, point.geometry.y\n",
"\n",
" # Extract all available features at this point\n", " # Extract all available features at this point\n",
" feature_vec = []\n", " feature_vec = []\n",
" for feat_name in features_to_use:\n", " for feat_name in features_to_use:\n",
" feat_val = float(data[feat_name].sel(\n", " feat_val = float(data[feat_name].sel(\n",
" x=point.geometry.x, \n", " x=px, y=py, method='nearest'\n",
" y=point.geometry.y, \n",
" method='nearest'\n",
" ).values)\n", " ).values)\n",
" feature_vec.append(feat_val)\n", " feature_vec.append(feat_val)\n",
" \n", "\n",
" # Get label\n", " # Get label\n",
" label = label_mapping[point.Hientrang]\n", " try:\n",
" \n", " label = label_mapping[point.Hientrang]\n",
" # Only add if no NaN values\n", " except KeyError:\n",
" if not np.isnan(feature_vec).any():\n", " skipped_label += 1\n",
" X.append(feature_vec)\n", " continue\n",
" y.append(int(label))\n", "\n",
" # ── FIX 3: np.isnan phải nhận numpy array, không phải list ─\n",
" feature_arr = np.array(feature_vec, dtype=np.float32)\n",
" if np.isnan(feature_arr).any():\n",
" skipped_nan += 1\n",
" continue\n",
"\n",
" X.append(feature_vec)\n",
" y.append(int(label))\n",
"\n",
" except Exception as e:\n", " except Exception as e:\n",
" # Skip points with errors\n", " skipped_other += 1\n",
" continue\n", " continue\n",
" \n", "\n",
" print(f\"\\n Points extracted : {len(X)}\")\n",
" print(f\" Skipped (NaN) : {skipped_nan}\")\n",
" print(f\" Skipped (label) : {skipped_label}\")\n",
" print(f\" Skipped (other) : {skipped_other}\")\n",
"\n",
" if len(X) > 0:\n", " if len(X) > 0:\n",
" X = np.array(X)\n", " X = np.array(X)\n",
" y = np.array(y)\n", " y = np.array(y)\n",
" print(f\" ✅ Extracted {len(X)} samples with {X.shape[1]} features each\")\n", " print(f\" ✅ {len(X)} samples × {X.shape[1]} features\")\n",
" \n", "\n",
" # Show feature statistics\n", " # Show feature statistics\n",
" print(f\"\\n Feature statistics:\")\n", " print(f\"\\n Feature statistics:\")\n",
" for i, feat_name in enumerate(features_to_use):\n", " for i, feat_name in enumerate(features_to_use):\n",
" print(f\" {feat_name:15s}: mean={X[:,i].mean():.3f}, std={X[:,i].std():.3f}\")\n", " print(f\" {feat_name:15s}: mean={X[:,i].mean():.3f}, std={X[:,i].std():.3f}\")\n",
" \n", "\n",
" # Split data\n", " # Split data\n",
" print(f\"\\n[2] Splitting data (80-20)...\")\n", " print(f\"\\n[2] Splitting data (80-20)...\")\n",
" from sklearn.model_selection import train_test_split\n", " from sklearn.model_selection import train_test_split\n",
@@ -830,21 +873,21 @@
" X, y, test_size=0.2, random_state=42, stratify=y\n", " X, y, test_size=0.2, random_state=42, stratify=y\n",
" )\n", " )\n",
" print(f\" Train: {len(X_train)}, Test: {len(X_test)}\")\n", " print(f\" Train: {len(X_train)}, Test: {len(X_test)}\")\n",
" \n", "\n",
" # Show class distribution\n", " # Show class distribution\n",
" unique, counts = np.unique(y_train, return_counts=True)\n", " unique, counts = np.unique(y_train, return_counts=True)\n",
" print(f\"\\n Class distribution in training set:\")\n", " print(f\"\\n Class distribution in training set:\")\n",
" for cls, count in zip(unique, counts):\n", " for cls, count in zip(unique, counts):\n",
" cls_name = [k for k, v in label_mapping.items() if v == str(cls)][0]\n", " cls_name = [k for k, v in label_mapping.items() if v == str(cls)][0]\n",
" print(f\" {cls}: {cls_name:15s} - {count:4d} samples ({count/len(y_train)*100:.1f}%)\")\n", " print(f\" {cls}: {cls_name:15s} - {count:4d} samples ({count/len(y_train)*100:.1f}%)\")\n",
" \n", "\n",
" # Train model\n", " # Train model\n",
" print(f\"\\n[3] Training Random Forest for LAND USE CLASSIFICATION...\")\n", " print(f\"\\n[3] Training Random Forest for LAND USE CLASSIFICATION...\")\n",
" from sklearn.ensemble import RandomForestClassifier\n", " from sklearn.ensemble import RandomForestClassifier\n",
" from sklearn.metrics import accuracy_score, classification_report\n", " from sklearn.metrics import accuracy_score, classification_report\n",
" \n", "\n",
" model = RandomForestClassifier(\n", " model = RandomForestClassifier(\n",
" n_estimators=200, # More trees for better accuracy\n", " n_estimators=200,\n",
" max_depth=30,\n", " max_depth=30,\n",
" min_samples_split=5,\n", " min_samples_split=5,\n",
" random_state=42,\n", " random_state=42,\n",
@@ -852,31 +895,31 @@
" verbose=1\n", " verbose=1\n",
" )\n", " )\n",
" model.fit(X_train, y_train)\n", " model.fit(X_train, y_train)\n",
" \n", "\n",
" # Evaluate\n", " # Evaluate\n",
" y_pred = model.predict(X_test)\n", " y_pred = model.predict(X_test)\n",
" accuracy = accuracy_score(y_test, y_pred)\n", " accuracy = accuracy_score(y_test, y_pred)\n",
" \n", "\n",
" print(f\"\\n ✅ Model trained!\")\n", " print(f\"\\n ✅ Model trained!\")\n",
" print(f\" Training accuracy: {model.score(X_train, y_train)*100:.2f}%\")\n", " print(f\" Training accuracy: {model.score(X_train, y_train)*100:.2f}%\")\n",
" print(f\" Testing accuracy: {accuracy*100:.2f}%\")\n", " print(f\" Testing accuracy : {accuracy*100:.2f}%\")\n",
" \n", "\n",
" # Show feature importance\n", " # Show feature importance\n",
" print(f\"\\n Feature importance:\")\n", " print(f\"\\n Feature importance:\")\n",
" importances = model.feature_importances_\n", " importances = model.feature_importances_\n",
" indices = np.argsort(importances)[::-1]\n", " indices = np.argsort(importances)[::-1]\n",
" for i, idx in enumerate(indices):\n", " for i, idx_fi in enumerate(indices):\n",
" print(f\" {i+1}. {features_to_use[idx]:15s}: {importances[idx]:.4f}\")\n", " print(f\" {i+1}. {features_to_use[idx_fi]:15s}: {importances[idx_fi]:.4f}\")\n",
" \n", "\n",
" # Classification report\n", " # Classification report\n",
" print(f\"\\n[4] Classification Report:\")\n", " print(f\"\\n[4] Classification Report:\")\n",
" class_names = [k for k, v in sorted(label_mapping.items(), key=lambda x: x[1])]\n", " class_names = [k for k, v in sorted(label_mapping.items(), key=lambda x: x[1])]\n",
" print(classification_report(y_test, y_pred, target_names=class_names, zero_division=0))\n", " print(classification_report(y_test, y_pred, target_names=class_names, zero_division=0))\n",
" \n", "\n",
" else:\n", " else:\n",
" print(f\" ❌ No samples extracted\")\n", " print(f\" ❌ No valid samples extracted — kiểm tra CRS và tọa độ!\")\n",
" model = None\n", " model = None\n",
" \n", "\n",
" except Exception as e:\n", " except Exception as e:\n",
" print(f\" ❌ Error: {e}\")\n", " print(f\" ❌ Error: {e}\")\n",
" import traceback\n", " import traceback\n",
@@ -890,7 +933,7 @@
"print(\"📝 NOTE: Model này dự đoán PHÂN LOẠI SỬ DỤNG ĐẤT (8 lớp)\")\n", "print(\"📝 NOTE: Model này dự đoán PHÂN LOẠI SỬ DỤNG ĐẤT (8 lớp)\")\n",
"print(\" NDVI là một trong các features đầu vào, không phải mục tiêu dự đoán\")\n", "print(\" NDVI là một trong các features đầu vào, không phải mục tiêu dự đoán\")\n",
"print(\" Sau khi predict → có thể hiển thị NDVI map như chỉ số phụ\")\n", "print(\" Sau khi predict → có thể hiển thị NDVI map như chỉ số phụ\")\n",
"print(\"=\"*70)" "print(\"=\"*70)\n"
] ]
}, },
{ {
@@ -1094,14 +1137,6 @@
"print(\"✅ PIPELINE COMPLETE\")\n", "print(\"✅ PIPELINE COMPLETE\")\n",
"print(\"=\"*70)" "print(\"=\"*70)"
] ]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ef65aa25-9032-4e1c-8808-64747e8005c6",
"metadata": {},
"outputs": [],
"source": []
} }
], ],
"metadata": { "metadata": {