Claude Skill

mcda-suitability-analysis

Always invoke for spatial suitability, site selection, AHP, criteria weights, or weighted-overlay work, including audits of inconsistent pairwise judgments and requests for only a final map. Covers consistency, standardization, constraints, ranked surfaces, shortlists, and sensit

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download muend-geoai-skills-skills_mcda-suitability-analysis-096e5d4.zip · 5 KB
Part of muend/geoai-skills — 18 skills

Install

skills CLI npx skills add https://github.com/muend/geoai-skills/tree/main/skills/mcda-suitability-analysis
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install muend-geoai-skills@llmmart
Git git clone https://github.com/muend/geoai-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole muend/geoai-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

MCDA & Suitability Analysis

Purpose: produce suitability maps whose weights, scales, and assumptions are explicit, consistent, and stress-tested. A suitability map without a sensitivity analysis is an opinion with a legend.

Workflow

  1. Structure: goal → criteria (factors) → constraints. Constraints are binary masks (legal exclusions, water bodies, slope > threshold) applied at the END by multiplication; factors are continuous and weighted. Keep them apart — encoding a constraint as a heavily-weighted factor is a classic error that lets forbidden areas score "acceptable".
  2. Criteria layers: each factor as a raster on a COMMON grid (same CRS, extent, cell size, snap). Resample categorical layers with nearest, continuous with bilinear; document each.
  3. Standardization to a common suitability scale (0-1 or 0-255):
    • Linear min-max for monotonic "more is better/worse".
    • Fuzzy membership (sigmoid/linear with control points) when suitability saturates — justify control points from domain knowledge.
    • Categorical layers: explicit reclass table, shown to the user. Direction check: confirm for EVERY layer whether high raw value means high or low suitability (slope: low=good; distance-to-road: usually low=good). Direction bugs survive to the final map invisibly.
  4. Weights (AHP below, or direct/ranked methods with rationale).
  5. Aggregation: weighted linear combination (WLC) default; OWA when the decision-maker's risk attitude (AND-like vs OR-like) matters.
  6. Constraint mask multiply; classify the result (equal interval or quantiles — say which and why); sensitivity analysis; validate against known good/bad sites if any exist.

AHP with consistency enforcement

Pairwise comparisons on Saaty's 1-9 scale; weights from the principal eigenvector; consistency ratio (CR) must be < 0.10 or the matrix goes back for revision. Run scripts/ahp_weights.py to compute weights + CR from a reciprocal comparison matrix (it validates reciprocity and reports λ_max).

Practices: elicit comparisons pair by pair with verbal anchors ("moderately more important" = 3); with multiple experts, aggregate judgments by geometric mean BEFORE computing weights; report the full matrix, weights, λ_max and CR in the deliverable. If CR ≥ 0.10, identify the most inconsistent triad and ask the expert to revisit it — do not silently massage numbers.

Aggregation

suit = np.zeros_like(factors[0], dtype="float32")
for w_i, f in zip(weights, factors):   # factors already standardized 0-1
    suit += w_i * f
suit *= constraint_mask                 # binary 0/1, applied last

OWA variant: sort factor values per cell and apply order weights — full AND (min) to full OR (max) continuum; use when stakeholders disagree on risk tolerance and show 2-3 scenarios.

Sensitivity analysis — mandatory

A result that flips with a small weight change is not a result:

  • One-at-a-time: perturb each weight ±20% (renormalize), recompute, report % of area changing suitability class and a stability map (cells that never change class across perturbations).
  • Scenario: 2-3 alternative weight sets from different stakeholder priorities; present side-by-side.
  • If a Monte Carlo budget exists: sample weights from Dirichlet around the AHP vector; per-cell probability of "highly suitable" is a far stronger product than a single map.

Deliverable standard

Suitability map (classified + continuous), constraint mask map, weights table with CR, standardization functions per criterion (with direction), sensitivity/stability summary, and limitations paragraph (data currency, resolution, criteria omitted). Route cartography to cartography-geoviz; network-access criteria come from network-accessibility-analysis.

Pitfalls checklist

  • Direction inversion on a criterion (the silent killer — double-check distance-based factors).
  • Mixing resolutions without declaring the resampling rule.
  • CR ignored or unreported.
  • Constraints blended as weights → forbidden zones scored medium.
  • Classifying with quantiles then reading them as absolute suitability.
  • No sensitivity analysis; single map presented as truth.

Execution contract

  • Workflow: define decision and stakeholders; separate constraints from factors; standardize criteria; elicit and validate weights; aggregate; test sensitivity; communicate uncertainty.
  • Decision rules: use MCDA for transparent criteria-ranked surfaces, network analysis for route-constrained access, and optimization when discrete placement or capacity decisions dominate.
  • Verification protocol: check criterion direction and alignment, AHP consistency, constraint enforcement, weight and threshold perturbations, and stable-versus-fragile areas.
  • Failure modes: reject the model when criteria double-count the same construct, weights lack provenance, constraints leak into compensation, or rankings collapse under plausible perturbations.
  • Deliverables: continuous and classified suitability maps, constraints, criteria transformations, weights and consistency ratio, sensitivity results, and limitations.
  • Source freshness: consult the authoritative source registry before applying methods or implementation APIs and record the checked date.
Files (geoai-skills)
  • agents
    • openai.yaml 229 B
      interface:
        display_name: "MCDA Suitability Analysis"
        short_description: "Build transparent spatial suitability models"
        default_prompt: "Use $mcda-suitability-analysis to create and stress-test this site suitability model."
      
  • references
    • authoritative-sources.md 867 B
      # Authoritative sources
      
      - Last verified: 2026-07-19
      - Review cadence: every 12 months
      - Refresh triggers: weighting method change, decision-policy change, or implementation dependency release
      
      ## Canonical sources
      
      - [Saaty, The Analytic Hierarchy Process](https://doi.org/10.1016/0270-0255(87)90473-8) — primary AHP scale and consistency foundation.
      - [JRC sensitivity analysis resources](https://joint-research-centre.ec.europa.eu/sensitivity-analysis-samo_en) — European Commission guidance and tools for sensitivity analysis.
      - [NumPy linear algebra documentation](https://numpy.org/doc/stable/reference/routines.linalg.html) — implementation behavior for the bundled weight calculator.
      
      Document stakeholder provenance and the exact pairwise matrix. A mathematically consistent matrix does not make criteria, preferences, or policy assumptions objective.
      
  • scripts
    • ahp_weights.py 2.8 KB
      """AHP weights + consistency ratio from a pairwise comparison matrix.
      
      Run:    python ahp_weights.py matrix.csv        (n x n CSV, no header)
      Import: from ahp_weights import ahp_weights
      """
      from __future__ import annotations
      
      import argparse
      from pathlib import Path
      
      import numpy as np
      
      # Saaty's random consistency index by matrix order
      RI = {1: 0.0, 2: 0.0, 3: 0.58, 4: 0.90, 5: 1.12, 6: 1.24, 7: 1.32, 8: 1.41, 9: 1.45, 10: 1.49}
      
      
      def ahp_weights(A: np.ndarray) -> tuple[np.ndarray, float]:
          """Principal-eigenvector AHP weights and consistency ratio.
      
          Args:
              A: n x n positive reciprocal pairwise comparison matrix
                 (Saaty 1-9 scale).
      
          Returns:
              (weights summing to 1, CR). CR >= 0.10 means judgments are too
              inconsistent to use — revise the most discordant comparison.
      
          Raises:
              ValueError: If the matrix is not finite, positive, square, reciprocal,
                  or supported by the bundled random consistency index table.
          """
          A = np.asarray(A, dtype=float)
          if A.ndim != 2 or A.shape[0] != A.shape[1]:
              raise ValueError("AHP matrix must be a square 2D array.")
      
          n = A.shape[0]
          if n not in RI:
              raise ValueError(f"AHP matrix order {n} is unsupported; expected 1–10.")
          if not np.isfinite(A).all():
              raise ValueError("AHP matrix must contain only finite values.")
          if np.any(A <= 0):
              raise ValueError("AHP matrix values must be strictly positive.")
          if not np.allclose(np.diag(A), 1.0, rtol=0.0, atol=1e-8):
              raise ValueError("AHP matrix diagonal must contain only 1 values.")
          if not np.allclose(A * A.T, np.ones_like(A), rtol=1e-6):
              raise ValueError("Matrix is not reciprocal (A[i,j] must equal 1/A[j,i]).")
      
          eigvals, eigvecs = np.linalg.eig(A)
          k = int(np.argmax(eigvals.real))
          if abs(eigvals[k].imag) > 1e-8:
              raise ValueError("Principal eigenvalue is unexpectedly complex.")
      
          w = eigvecs[:, k].real
          if w.sum() < 0:
              w = -w
          if np.any(w <= 0):
              raise ValueError("Principal eigenvector did not produce positive weights.")
          w /= w.sum()
          lam_max = eigvals[k].real
          ci = max(0.0, (lam_max - n) / (n - 1)) if n > 2 else 0.0
          cr = ci / RI[n] if RI.get(n, 0) > 0 else 0.0
          return w, float(cr)
      
      
      def main() -> None:
          """Read a headerless CSV matrix and print weights plus consistency."""
          parser = argparse.ArgumentParser(description=__doc__)
          parser.add_argument("matrix", type=Path)
          args = parser.parse_args()
      
          matrix = np.loadtxt(args.matrix, delimiter=",")
          weights, cr = ahp_weights(matrix)
          for i, wi in enumerate(weights):
              print(f"criterion_{i + 1}: {wi:.4f}")
          verdict = "OK" if cr < 0.10 else "REVISE — inconsistent judgments"
          print(f"CR = {cr:.4f}  [{verdict}]")
      
      
      if __name__ == "__main__":
          main()
      
  • SKILL.md 5.8 KB
    ---
    name: mcda-suitability-analysis
    description: >-
      Always invoke for spatial suitability, site selection, AHP, criteria
      weights, or weighted-overlay work, including audits of inconsistent
      pairwise judgments and requests for only a final map. Covers consistency,
      standardization, constraints, ranked surfaces, shortlists, and sensitivity.
      Route travel-time placement and location-allocation to
      network-accessibility-analysis.
    license: MIT
    metadata:
      author: Muhammed Enes Duran
    ---
    
    # MCDA & Suitability Analysis
    
    Purpose: produce suitability maps whose weights, scales, and assumptions are
    explicit, consistent, and stress-tested. A suitability map without a
    sensitivity analysis is an opinion with a legend.
    
    ## Workflow
    
    1. **Structure**: goal → criteria (factors) → constraints. Constraints are
       binary masks (legal exclusions, water bodies, slope > threshold) applied
       at the END by multiplication; factors are continuous and weighted.
       Keep them apart — encoding a constraint as a heavily-weighted factor is
       a classic error that lets forbidden areas score "acceptable".
    2. **Criteria layers**: each factor as a raster on a COMMON grid (same CRS,
       extent, cell size, snap). Resample categorical layers with nearest,
       continuous with bilinear; document each.
    3. **Standardization** to a common suitability scale (0-1 or 0-255):
       - Linear min-max for monotonic "more is better/worse".
       - Fuzzy membership (sigmoid/linear with control points) when suitability
         saturates — justify control points from domain knowledge.
       - Categorical layers: explicit reclass table, shown to the user.
       Direction check: confirm for EVERY layer whether high raw value means
       high or low suitability (slope: low=good; distance-to-road: usually
       low=good). Direction bugs survive to the final map invisibly.
    4. **Weights** (AHP below, or direct/ranked methods with rationale).
    5. **Aggregation**: weighted linear combination (WLC) default; OWA when
       the decision-maker's risk attitude (AND-like vs OR-like) matters.
    6. **Constraint mask** multiply; classify the result (equal interval or
       quantiles — say which and why); **sensitivity analysis**; validate
       against known good/bad sites if any exist.
    
    ## AHP with consistency enforcement
    
    Pairwise comparisons on Saaty's 1-9 scale; weights from the principal
    eigenvector; consistency ratio (CR) must be < 0.10 or the matrix goes back
    for revision. Run `scripts/ahp_weights.py` to compute weights + CR from a
    reciprocal comparison matrix (it validates reciprocity and reports λ_max).
    
    Practices: elicit comparisons pair by pair with verbal anchors ("moderately
    more important" = 3); with multiple experts, aggregate judgments by
    geometric mean BEFORE computing weights; report the full matrix, weights,
    λ_max and CR in the deliverable. If CR ≥ 0.10, identify the most
    inconsistent triad and ask the expert to revisit it — do not silently
    massage numbers.
    
    ## Aggregation
    
    ```python
    suit = np.zeros_like(factors[0], dtype="float32")
    for w_i, f in zip(weights, factors):   # factors already standardized 0-1
        suit += w_i * f
    suit *= constraint_mask                 # binary 0/1, applied last
    ```
    
    OWA variant: sort factor values per cell and apply order weights — full
    AND (min) to full OR (max) continuum; use when stakeholders disagree on
    risk tolerance and show 2-3 scenarios.
    
    ## Sensitivity analysis — mandatory
    
    A result that flips with a small weight change is not a result:
    
    - **One-at-a-time**: perturb each weight ±20% (renormalize), recompute,
      report % of area changing suitability class and a stability map (cells
      that never change class across perturbations).
    - **Scenario**: 2-3 alternative weight sets from different stakeholder
      priorities; present side-by-side.
    - If a Monte Carlo budget exists: sample weights from Dirichlet around the
      AHP vector; per-cell probability of "highly suitable" is a far stronger
      product than a single map.
    
    ## Deliverable standard
    
    Suitability map (classified + continuous), constraint mask map, weights
    table with CR, standardization functions per criterion (with direction),
    sensitivity/stability summary, and limitations paragraph (data currency,
    resolution, criteria omitted). Route cartography to `cartography-geoviz`;
    network-access criteria come from `network-accessibility-analysis`.
    
    ## Pitfalls checklist
    
    - Direction inversion on a criterion (the silent killer — double-check
      distance-based factors).
    - Mixing resolutions without declaring the resampling rule.
    - CR ignored or unreported.
    - Constraints blended as weights → forbidden zones scored medium.
    - Classifying with quantiles then reading them as absolute suitability.
    - No sensitivity analysis; single map presented as truth.
    
    ## Execution contract
    
    - **Workflow:** define decision and stakeholders; separate constraints from factors; standardize criteria; elicit and validate weights; aggregate; test sensitivity; communicate uncertainty.
    - **Decision rules:** use MCDA for transparent criteria-ranked surfaces, network analysis for route-constrained access, and optimization when discrete placement or capacity decisions dominate.
    - **Verification protocol:** check criterion direction and alignment, AHP consistency, constraint enforcement, weight and threshold perturbations, and stable-versus-fragile areas.
    - **Failure modes:** reject the model when criteria double-count the same construct, weights lack provenance, constraints leak into compensation, or rankings collapse under plausible perturbations.
    - **Deliverables:** continuous and classified suitability maps, constraints, criteria transformations, weights and consistency ratio, sensitivity results, and limitations.
    - **Source freshness:** consult [the authoritative source registry](references/authoritative-sources.md) before applying methods or implementation APIs and record the checked date.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related