update 01 file train_odc.py
This commit is contained in:
+79
-44
@@ -726,7 +726,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"execution_count": null,
|
||||
"id": "2e955884-d4af-422d-a8e6-d436199540e0",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@@ -772,57 +772,100 @@
|
||||
" print(\" (Sử dụng nhiều spectral indices để cải thiện accuracy)\")\n",
|
||||
" \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",
|
||||
" X = []\n",
|
||||
" y = []\n",
|
||||
" \n",
|
||||
" skipped_nan = 0\n",
|
||||
" skipped_label = 0\n",
|
||||
" skipped_other = 0\n",
|
||||
"\n",
|
||||
" # Available features from data\n",
|
||||
" available_features = ['ndvi_mean', 'ndvi_min', 'ndvi_max', 'ndvi_std', 'ndvi_range',\n",
|
||||
" 'ndwi_mean', 'ndbi_mean', 'evi_mean']\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" # Check which features are actually available\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",
|
||||
" print(\" ❌ No spectral features found in dataset!\")\n",
|
||||
" print(\" Available variables:\", list(data.data_vars))\n",
|
||||
" model = None\n",
|
||||
" else:\n",
|
||||
" print(f\" Using {len(features_to_use)} features: {features_to_use}\")\n",
|
||||
" \n",
|
||||
" for idx, point in train.iterrows():\n",
|
||||
"\n",
|
||||
" for idx, point in train_proj.iterrows():\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",
|
||||
" feature_vec = []\n",
|
||||
" for feat_name in features_to_use:\n",
|
||||
" feat_val = float(data[feat_name].sel(\n",
|
||||
" x=point.geometry.x, \n",
|
||||
" y=point.geometry.y, \n",
|
||||
" method='nearest'\n",
|
||||
" x=px, y=py, method='nearest'\n",
|
||||
" ).values)\n",
|
||||
" feature_vec.append(feat_val)\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" # Get label\n",
|
||||
" label = label_mapping[point.Hientrang]\n",
|
||||
" \n",
|
||||
" # Only add if no NaN values\n",
|
||||
" if not np.isnan(feature_vec).any():\n",
|
||||
" X.append(feature_vec)\n",
|
||||
" y.append(int(label))\n",
|
||||
" try:\n",
|
||||
" label = label_mapping[point.Hientrang]\n",
|
||||
" except KeyError:\n",
|
||||
" skipped_label += 1\n",
|
||||
" continue\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",
|
||||
" # Skip points with errors\n",
|
||||
" skipped_other += 1\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",
|
||||
" X = np.array(X)\n",
|
||||
" y = np.array(y)\n",
|
||||
" print(f\" ✅ Extracted {len(X)} samples with {X.shape[1]} features each\")\n",
|
||||
" \n",
|
||||
" print(f\" ✅ {len(X)} samples × {X.shape[1]} features\")\n",
|
||||
"\n",
|
||||
" # Show feature statistics\n",
|
||||
" print(f\"\\n Feature statistics:\")\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",
|
||||
" \n",
|
||||
"\n",
|
||||
" # Split data\n",
|
||||
" print(f\"\\n[2] Splitting data (80-20)...\")\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",
|
||||
" )\n",
|
||||
" print(f\" Train: {len(X_train)}, Test: {len(X_test)}\")\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" # Show class distribution\n",
|
||||
" unique, counts = np.unique(y_train, return_counts=True)\n",
|
||||
" print(f\"\\n Class distribution in training set:\")\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",
|
||||
" print(f\" {cls}: {cls_name:15s} - {count:4d} samples ({count/len(y_train)*100:.1f}%)\")\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" # Train model\n",
|
||||
" print(f\"\\n[3] Training Random Forest for LAND USE CLASSIFICATION...\")\n",
|
||||
" from sklearn.ensemble import RandomForestClassifier\n",
|
||||
" from sklearn.metrics import accuracy_score, classification_report\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" model = RandomForestClassifier(\n",
|
||||
" n_estimators=200, # More trees for better accuracy\n",
|
||||
" n_estimators=200,\n",
|
||||
" max_depth=30,\n",
|
||||
" min_samples_split=5,\n",
|
||||
" random_state=42,\n",
|
||||
@@ -852,31 +895,31 @@
|
||||
" verbose=1\n",
|
||||
" )\n",
|
||||
" model.fit(X_train, y_train)\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" # Evaluate\n",
|
||||
" y_pred = model.predict(X_test)\n",
|
||||
" accuracy = accuracy_score(y_test, y_pred)\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" print(f\"\\n ✅ Model trained!\")\n",
|
||||
" print(f\" Training accuracy: {model.score(X_train, y_train)*100:.2f}%\")\n",
|
||||
" print(f\" Testing accuracy: {accuracy*100:.2f}%\")\n",
|
||||
" \n",
|
||||
" print(f\" Testing accuracy : {accuracy*100:.2f}%\")\n",
|
||||
"\n",
|
||||
" # Show feature importance\n",
|
||||
" print(f\"\\n Feature importance:\")\n",
|
||||
" importances = model.feature_importances_\n",
|
||||
" indices = np.argsort(importances)[::-1]\n",
|
||||
" for i, idx in enumerate(indices):\n",
|
||||
" print(f\" {i+1}. {features_to_use[idx]:15s}: {importances[idx]:.4f}\")\n",
|
||||
" \n",
|
||||
" for i, idx_fi in enumerate(indices):\n",
|
||||
" print(f\" {i+1}. {features_to_use[idx_fi]:15s}: {importances[idx_fi]:.4f}\")\n",
|
||||
"\n",
|
||||
" # 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",
|
||||
" print(classification_report(y_test, y_pred, target_names=class_names, zero_division=0))\n",
|
||||
" \n",
|
||||
"\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",
|
||||
" \n",
|
||||
"\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\" ❌ Error: {e}\")\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(\" 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(\"=\"*70)"
|
||||
"print(\"=\"*70)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1094,14 +1137,6 @@
|
||||
"print(\"✅ PIPELINE COMPLETE\")\n",
|
||||
"print(\"=\"*70)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ef65aa25-9032-4e1c-8808-64747e8005c6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
Reference in New Issue
Block a user