[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FJNPYQ0N4MC55BT07D8MSF":3,"skill-same:01M6FJNPYQ0N4MC55BT07D8MSF":62},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":29,"linkOnly":30,"markdownContent":31,"markdownBody":32,"frontMatter":33,"refName":35,"commitSha":36,"skillDirectory":37,"forksCount":38,"repositoryHtmlUrl":39,"repositoryHomepageUrl":6,"ownerHtmlUrl":40,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":41,"install":42,"resources":55},"01M6FJNPYQ0N4MC55BT07D8MSF","cwicr-comparison-tool",null,"Compare cost estimates across projects, versions, and scenarios. Identify variances, benchmark against standards, and generate comparison reports.","kbarbel640-del\u002Fskills","kbarbel640-del","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F255315490?v=4","01M6CJPPQGCCESXMG3K7BBGQ5J","01M6CJPPX2PB2BCZERFVM2C2B3",1,"MIT","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fcwicr-comparison-tool\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28],"tool","comparison","cwicr comparison tool","generate","benchmark","projects","cost","standards","reports","across","compare","2026-11-10 10:12:30",false,"---\r\nslug: \"cwicr-comparison-tool\"\r\ndisplay_name: \"CWICR Comparison Tool\"\r\ndescription: \"Compare cost estimates across projects, versions, and scenarios. Identify variances, benchmark against standards, and generate comparison reports.\"\r\n---\r\n\r\n# CWICR Comparison Tool\r\n\r\n## Business Case\r\n\r\n### Problem Statement\r\nProject stakeholders need to compare:\r\n- Alternative design options\r\n- Estimate versions over time\r\n- Projects against benchmarks\r\n- Actual vs estimated costs\r\n\r\n### Solution\r\nStructured comparison of CWICR-based estimates with variance analysis, benchmarking, and visual reporting.\r\n\r\n### Business Value\r\n- **Decision support** - Compare alternatives objectively\r\n- **Version control** - Track estimate evolution\r\n- **Benchmarking** - Compare against standards\r\n- **Audit** - Document estimate changes\r\n\r\n## Technical Implementation\r\n\r\n```python\r\nimport pandas as pd\r\nimport numpy as np\r\nfrom typing import Dict, Any, List, Optional, Tuple\r\nfrom dataclasses import dataclass, field\r\nfrom datetime import datetime\r\nfrom enum import Enum\r\n\r\n\r\nclass ComparisonType(Enum):\r\n    \"\"\"Types of comparisons.\"\"\"\r\n    VERSION = \"version\"          # Same project, different versions\r\n    ALTERNATIVE = \"alternative\"  # Same project, design alternatives\r\n    BENCHMARK = \"benchmark\"      # Project vs standard\u002Fbenchmark\r\n    ACTUAL = \"actual\"            # Estimate vs actual costs\r\n    PROJECT = \"project\"          # Different projects\r\n\r\n\r\nclass VarianceSignificance(Enum):\r\n    \"\"\"Significance level of variance.\"\"\"\r\n    CRITICAL = \"critical\"    # >20% variance\r\n    HIGH = \"high\"            # 10-20%\r\n    MEDIUM = \"medium\"        # 5-10%\r\n    LOW = \"low\"              # \u003C5%\r\n    NONE = \"none\"            # No variance\r\n\r\n\r\n@dataclass\r\nclass ComparisonItem:\r\n    \"\"\"Single item comparison.\"\"\"\r\n    work_item_code: str\r\n    description: str\r\n    base_quantity: float\r\n    base_cost: float\r\n    compare_quantity: float\r\n    compare_cost: float\r\n    quantity_variance: float\r\n    quantity_variance_pct: float\r\n    cost_variance: float\r\n    cost_variance_pct: float\r\n    significance: VarianceSignificance\r\n\r\n\r\n@dataclass\r\nclass ComparisonResult:\r\n    \"\"\"Complete comparison result.\"\"\"\r\n    comparison_type: ComparisonType\r\n    base_name: str\r\n    compare_name: str\r\n    base_total: float\r\n    compare_total: float\r\n    total_variance: float\r\n    total_variance_pct: float\r\n    items: List[ComparisonItem]\r\n    summary_by_category: Dict[str, Dict[str, float]]\r\n    created_at: datetime\r\n\r\n\r\nclass CWICRComparisonTool:\r\n    \"\"\"Compare CWICR-based estimates.\"\"\"\r\n\r\n    SIGNIFICANCE_THRESHOLDS = {\r\n        VarianceSignificance.CRITICAL: 0.20,\r\n        VarianceSignificance.HIGH: 0.10,\r\n        VarianceSignificance.MEDIUM: 0.05,\r\n        VarianceSignificance.LOW: 0.01\r\n    }\r\n\r\n    def __init__(self):\r\n        pass\r\n\r\n    def _get_significance(self, variance_pct: float) -> VarianceSignificance:\r\n        \"\"\"Determine variance significance.\"\"\"\r\n        abs_var = abs(variance_pct) \u002F 100\r\n\r\n        if abs_var >= self.SIGNIFICANCE_THRESHOLDS[VarianceSignificance.CRITICAL]:\r\n            return VarianceSignificance.CRITICAL\r\n        elif abs_var >= self.SIGNIFICANCE_THRESHOLDS[VarianceSignificance.HIGH]:\r\n            return VarianceSignificance.HIGH\r\n        elif abs_var >= self.SIGNIFICANCE_THRESHOLDS[VarianceSignificance.MEDIUM]:\r\n            return VarianceSignificance.MEDIUM\r\n        elif abs_var >= self.SIGNIFICANCE_THRESHOLDS[VarianceSignificance.LOW]:\r\n            return VarianceSignificance.LOW\r\n        else:\r\n            return VarianceSignificance.NONE\r\n\r\n    def compare_estimates(self,\r\n                          base_df: pd.DataFrame,\r\n                          compare_df: pd.DataFrame,\r\n                          base_name: str = \"Base\",\r\n                          compare_name: str = \"Compare\",\r\n                          comparison_type: ComparisonType = ComparisonType.VERSION,\r\n                          code_column: str = 'work_item_code',\r\n                          quantity_column: str = 'quantity',\r\n                          cost_column: str = 'total_cost') -> ComparisonResult:\r\n        \"\"\"Compare two estimates.\"\"\"\r\n\r\n        # Merge on code\r\n        merged = base_df.merge(\r\n            compare_df,\r\n            on=code_column,\r\n            how='outer',\r\n            suffixes=('_base', '_compare')\r\n        )\r\n\r\n        items = []\r\n        for _, row in merged.iterrows():\r\n            base_qty = float(row.get(f'{quantity_column}_base', 0) or 0)\r\n            base_cost = float(row.get(f'{cost_column}_base', 0) or 0)\r\n            compare_qty = float(row.get(f'{quantity_column}_compare', 0) or 0)\r\n            compare_cost = float(row.get(f'{cost_column}_compare', 0) or 0)\r\n\r\n            qty_variance = compare_qty - base_qty\r\n            qty_variance_pct = (qty_variance \u002F base_qty * 100) if base_qty > 0 else (100 if compare_qty > 0 else 0)\r\n\r\n            cost_variance = compare_cost - base_cost\r\n            cost_variance_pct = (cost_variance \u002F base_cost * 100) if base_cost > 0 else (100 if compare_cost > 0 else 0)\r\n\r\n            items.append(ComparisonItem(\r\n                work_item_code=str(row.get(code_column, '')),\r\n                description=str(row.get('description_base', row.get('description_compare', ''))),\r\n                base_quantity=base_qty,\r\n                base_cost=base_cost,\r\n                compare_quantity=compare_qty,\r\n                compare_cost=compare_cost,\r\n                quantity_variance=round(qty_variance, 2),\r\n                quantity_variance_pct=round(qty_variance_pct, 1),\r\n                cost_variance=round(cost_variance, 2),\r\n                cost_variance_pct=round(cost_variance_pct, 1),\r\n                significance=self._get_significance(cost_variance_pct)\r\n            ))\r\n\r\n        # Totals\r\n        base_total = sum(i.base_cost for i in items)\r\n        compare_total = sum(i.compare_cost for i in items)\r\n        total_variance = compare_total - base_total\r\n        total_variance_pct = (total_variance \u002F base_total * 100) if base_total > 0 else 0\r\n\r\n        # Summary by category\r\n        summary_by_category = self._summarize_by_category(items, merged)\r\n\r\n        return ComparisonResult(\r\n            comparison_type=comparison_type,\r\n            base_name=base_name,\r\n            compare_name=compare_name,\r\n            base_total=round(base_total, 2),\r\n            compare_total=round(compare_total, 2),\r\n            total_variance=round(total_variance, 2),\r\n            total_variance_pct=round(total_variance_pct, 1),\r\n            items=items,\r\n            summary_by_category=summary_by_category,\r\n            created_at=datetime.now()\r\n        )\r\n\r\n    def _summarize_by_category(self,\r\n                                items: List[ComparisonItem],\r\n                                merged_df: pd.DataFrame) -> Dict[str, Dict[str, float]]:\r\n        \"\"\"Summarize comparison by category.\"\"\"\r\n\r\n        summary = {}\r\n\r\n        # Try to extract category from work item code prefix\r\n        for item in items:\r\n            code = item.work_item_code\r\n            category = code.split('-')[0] if '-' in code else 'Other'\r\n\r\n            if category not in summary:\r\n                summary[category] = {\r\n                    'base_cost': 0,\r\n                    'compare_cost': 0,\r\n                    'variance': 0,\r\n                    'variance_pct': 0,\r\n                    'item_count': 0\r\n                }\r\n\r\n            summary[category]['base_cost'] += item.base_cost\r\n            summary[category]['compare_cost'] += item.compare_cost\r\n            summary[category]['variance'] += item.cost_variance\r\n            summary[category]['item_count'] += 1\r\n\r\n        # Calculate percentages\r\n        for category in summary:\r\n            base = summary[category]['base_cost']\r\n            if base > 0:\r\n                summary[category]['variance_pct'] = round(\r\n                    summary[category]['variance'] \u002F base * 100, 1\r\n                )\r\n\r\n        return summary\r\n\r\n    def get_significant_variances(self,\r\n                                   result: ComparisonResult,\r\n                                   min_significance: VarianceSignificance = VarianceSignificance.MEDIUM) -> List[ComparisonItem]:\r\n        \"\"\"Get items with significant variances.\"\"\"\r\n\r\n        significance_order = [\r\n            VarianceSignificance.CRITICAL,\r\n            VarianceSignificance.HIGH,\r\n            VarianceSignificance.MEDIUM,\r\n            VarianceSignificance.LOW,\r\n            VarianceSignificance.NONE\r\n        ]\r\n\r\n        min_index = significance_order.index(min_significance)\r\n        significant = [\r\n            item for item in result.items\r\n            if significance_order.index(item.significance) \u003C= min_index\r\n        ]\r\n\r\n        return sorted(significant, key=lambda x: abs(x.cost_variance), reverse=True)\r\n\r\n    def compare_multiple(self,\r\n                          estimates: List[Tuple[str, pd.DataFrame]],\r\n                          base_index: int = 0) -> Dict[str, ComparisonResult]:\r\n        \"\"\"Compare multiple estimates against base.\"\"\"\r\n\r\n        base_name, base_df = estimates[base_index]\r\n        results = {}\r\n\r\n        for i, (name, df) in enumerate(estimates):\r\n            if i == base_index:\r\n                continue\r\n\r\n            result = self.compare_estimates(\r\n                base_df=base_df,\r\n                compare_df=df,\r\n                base_name=base_name,\r\n                compare_name=name,\r\n                comparison_type=ComparisonType.ALTERNATIVE\r\n            )\r\n            results[name] = result\r\n\r\n        return results\r\n\r\n    def benchmark_comparison(self,\r\n                              project_df: pd.DataFrame,\r\n                              benchmark_df: pd.DataFrame,\r\n                              project_name: str,\r\n                              benchmark_name: str = \"Industry Benchmark\") -> ComparisonResult:\r\n        \"\"\"Compare project against benchmark.\"\"\"\r\n\r\n        return self.compare_estimates(\r\n            base_df=benchmark_df,\r\n            compare_df=project_df,\r\n            base_name=benchmark_name,\r\n            compare_name=project_name,\r\n            comparison_type=ComparisonType.BENCHMARK\r\n        )\r\n\r\n    def version_comparison(self,\r\n                           versions: List[Tuple[str, pd.DataFrame]]) -> List[ComparisonResult]:\r\n        \"\"\"Compare sequential versions.\"\"\"\r\n\r\n        results = []\r\n\r\n        for i in range(1, len(versions)):\r\n            prev_name, prev_df = versions[i-1]\r\n            curr_name, curr_df = versions[i]\r\n\r\n            result = self.compare_estimates(\r\n                base_df=prev_df,\r\n                compare_df=curr_df,\r\n                base_name=prev_name,\r\n                compare_name=curr_name,\r\n                comparison_type=ComparisonType.VERSION\r\n            )\r\n            results.append(result)\r\n\r\n        return results\r\n\r\n    def export_comparison(self,\r\n                          result: ComparisonResult,\r\n                          output_path: str) -> str:\r\n        \"\"\"Export comparison to Excel.\"\"\"\r\n\r\n        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:\r\n            # Summary\r\n            summary_df = pd.DataFrame([{\r\n                'Comparison Type': result.comparison_type.value,\r\n                'Base': result.base_name,\r\n                'Compare': result.compare_name,\r\n                'Base Total': result.base_total,\r\n                'Compare Total': result.compare_total,\r\n                'Variance': result.total_variance,\r\n                'Variance %': result.total_variance_pct,\r\n                'Generated': result.created_at.strftime('%Y-%m-%d %H:%M')\r\n            }])\r\n            summary_df.to_excel(writer, sheet_name='Summary', index=False)\r\n\r\n            # Details\r\n            details_df = pd.DataFrame([\r\n                {\r\n                    'Work Item': i.work_item_code,\r\n                    'Description': i.description,\r\n                    f'{result.base_name} Qty': i.base_quantity,\r\n                    f'{result.base_name} Cost': i.base_cost,\r\n                    f'{result.compare_name} Qty': i.compare_quantity,\r\n                    f'{result.compare_name} Cost': i.compare_cost,\r\n                    'Qty Variance': i.quantity_variance,\r\n                    'Qty Variance %': i.quantity_variance_pct,\r\n                    'Cost Variance': i.cost_variance,\r\n                    'Cost Variance %': i.cost_variance_pct,\r\n                    'Significance': i.significance.value\r\n                }\r\n                for i in result.items\r\n            ])\r\n            details_df.to_excel(writer, sheet_name='Details', index=False)\r\n\r\n            # By Category\r\n            cat_df = pd.DataFrame([\r\n                {\r\n                    'Category': cat,\r\n                    'Base Cost': data['base_cost'],\r\n                    'Compare Cost': data['compare_cost'],\r\n                    'Variance': data['variance'],\r\n                    'Variance %': data['variance_pct'],\r\n                    'Items': data['item_count']\r\n                }\r\n                for cat, data in result.summary_by_category.items()\r\n            ])\r\n            cat_df.to_excel(writer, sheet_name='By Category', index=False)\r\n\r\n            # Significant Variances\r\n            significant = self.get_significant_variances(result)\r\n            sig_df = pd.DataFrame([\r\n                {\r\n                    'Work Item': i.work_item_code,\r\n                    'Description': i.description,\r\n                    'Cost Variance': i.cost_variance,\r\n                    'Variance %': i.cost_variance_pct,\r\n                    'Significance': i.significance.value\r\n                }\r\n                for i in significant\r\n            ])\r\n            sig_df.to_excel(writer, sheet_name='Significant', index=False)\r\n\r\n        return output_path\r\n\r\n\r\nclass ComparisonAnalytics:\r\n    \"\"\"Analytics for comparison results.\"\"\"\r\n\r\n    def __init__(self, comparison_tool: CWICRComparisonTool):\r\n        self.tool = comparison_tool\r\n\r\n    def variance_distribution(self, result: ComparisonResult) -> Dict[str, int]:\r\n        \"\"\"Get distribution of variance significance.\"\"\"\r\n\r\n        distribution = {s.value: 0 for s in VarianceSignificance}\r\n\r\n        for item in result.items:\r\n            distribution[item.significance.value] += 1\r\n\r\n        return distribution\r\n\r\n    def top_variances(self,\r\n                      result: ComparisonResult,\r\n                      n: int = 10,\r\n                      positive: bool = True) -> List[ComparisonItem]:\r\n        \"\"\"Get top N variances (positive or negative).\"\"\"\r\n\r\n        if positive:\r\n            sorted_items = sorted(result.items, key=lambda x: x.cost_variance, reverse=True)\r\n        else:\r\n            sorted_items = sorted(result.items, key=lambda x: x.cost_variance)\r\n\r\n        return sorted_items[:n]\r\n\r\n    def category_impact(self, result: ComparisonResult) -> pd.DataFrame:\r\n        \"\"\"Analyze which categories contribute most to variance.\"\"\"\r\n\r\n        data = []\r\n        for cat, values in result.summary_by_category.items():\r\n            contribution_pct = (values['variance'] \u002F result.total_variance * 100) if result.total_variance != 0 else 0\r\n            data.append({\r\n                'Category': cat,\r\n                'Variance': values['variance'],\r\n                'Contribution %': round(contribution_pct, 1)\r\n            })\r\n\r\n        return pd.DataFrame(data).sort_values('Contribution %', ascending=False)\r\n\r\n    def trend_analysis(self,\r\n                        version_results: List[ComparisonResult]) -> pd.DataFrame:\r\n        \"\"\"Analyze cost trend across versions.\"\"\"\r\n\r\n        data = []\r\n        cumulative = 0\r\n\r\n        for result in version_results:\r\n            cumulative += result.total_variance\r\n            data.append({\r\n                'From': result.base_name,\r\n                'To': result.compare_name,\r\n                'Variance': result.total_variance,\r\n                'Variance %': result.total_variance_pct,\r\n                'Cumulative Variance': cumulative\r\n            })\r\n\r\n        return pd.DataFrame(data)\r\n```\r\n\r\n## Quick Start\r\n\r\n```python\r\n# Initialize comparison tool\r\ntool = CWICRComparisonTool()\r\n\r\n# Compare two estimate versions\r\nresult = tool.compare_estimates(\r\n    base_df=estimate_v1,\r\n    compare_df=estimate_v2,\r\n    base_name=\"Estimate v1.0\",\r\n    compare_name=\"Estimate v2.0\"\r\n)\r\n\r\nprint(f\"Total Variance: ${result.total_variance:,.2f} ({result.total_variance_pct}%)\")\r\n```\r\n\r\n## Common Use Cases\r\n\r\n### 1. Significant Variances\r\n```python\r\nsignificant = tool.get_significant_variances(result)\r\nfor item in significant[:5]:\r\n    print(f\"{item.work_item_code}: ${item.cost_variance:,.2f} ({item.significance.value})\")\r\n```\r\n\r\n### 2. Version History\r\n```python\r\nversions = [\r\n    (\"v1.0\", estimate_v1),\r\n    (\"v2.0\", estimate_v2),\r\n    (\"v3.0\", estimate_v3)\r\n]\r\nversion_results = tool.version_comparison(versions)\r\n\r\nanalytics = ComparisonAnalytics(tool)\r\ntrend = analytics.trend_analysis(version_results)\r\n```\r\n\r\n### 3. Design Alternatives\r\n```python\r\nalternatives = [\r\n    (\"Option A - Steel\", option_a),\r\n    (\"Option B - Concrete\", option_b),\r\n    (\"Option C - Hybrid\", option_c)\r\n]\r\ncomparisons = tool.compare_multiple(alternatives, base_index=0)\r\n```\r\n\r\n### 4. Export Report\r\n```python\r\ntool.export_comparison(result, \"estimate_comparison.xlsx\")\r\n```\r\n\r\n## Resources\r\n- **GitHub**: [OpenConstructionEstimate-DDC-CWICR](https:\u002F\u002Fgithub.com\u002Fdatadrivenconstruction\u002FOpenConstructionEstimate-DDC-CWICR)\r\n- **DDC Book**: Chapter 3.1 - Estimate Management\r\n","# CWICR Comparison Tool\r\n\r\n## Business Case\r\n\r\n### Problem Statement\r\nProject stakeholders need to compare:\r\n- Alternative design options\r\n- Estimate versions over time\r\n- Projects against benchmarks\r\n- Actual vs estimated costs\r\n\r\n### Solution\r\nStructured comparison of CWICR-based estimates with variance analysis, benchmarking, and visual reporting.\r\n\r\n### Business Value\r\n- **Decision support** - Compare alternatives objectively\r\n- **Version control** - Track estimate evolution\r\n- **Benchmarking** - Compare against standards\r\n- **Audit** - Document estimate changes\r\n\r\n## Technical Implementation\r\n\r\n```python\r\nimport pandas as pd\r\nimport numpy as np\r\nfrom typing import Dict, Any, List, Optional, Tuple\r\nfrom dataclasses import dataclass, field\r\nfrom datetime import datetime\r\nfrom enum import Enum\r\n\r\n\r\nclass ComparisonType(Enum):\r\n    \"\"\"Types of comparisons.\"\"\"\r\n    VERSION = \"version\"          # Same project, different versions\r\n    ALTERNATIVE = \"alternative\"  # Same project, design alternatives\r\n    BENCHMARK = \"benchmark\"      # Project vs standard\u002Fbenchmark\r\n    ACTUAL = \"actual\"            # Estimate vs actual costs\r\n    PROJECT = \"project\"          # Different projects\r\n\r\n\r\nclass VarianceSignificance(Enum):\r\n    \"\"\"Significance level of variance.\"\"\"\r\n    CRITICAL = \"critical\"    # >20% variance\r\n    HIGH = \"high\"            # 10-20%\r\n    MEDIUM = \"medium\"        # 5-10%\r\n    LOW = \"low\"              # \u003C5%\r\n    NONE = \"none\"            # No variance\r\n\r\n\r\n@dataclass\r\nclass ComparisonItem:\r\n    \"\"\"Single item comparison.\"\"\"\r\n    work_item_code: str\r\n    description: str\r\n    base_quantity: float\r\n    base_cost: float\r\n    compare_quantity: float\r\n    compare_cost: float\r\n    quantity_variance: float\r\n    quantity_variance_pct: float\r\n    cost_variance: float\r\n    cost_variance_pct: float\r\n    significance: VarianceSignificance\r\n\r\n\r\n@dataclass\r\nclass ComparisonResult:\r\n    \"\"\"Complete comparison result.\"\"\"\r\n    comparison_type: ComparisonType\r\n    base_name: str\r\n    compare_name: str\r\n    base_total: float\r\n    compare_total: float\r\n    total_variance: float\r\n    total_variance_pct: float\r\n    items: List[ComparisonItem]\r\n    summary_by_category: Dict[str, Dict[str, float]]\r\n    created_at: datetime\r\n\r\n\r\nclass CWICRComparisonTool:\r\n    \"\"\"Compare CWICR-based estimates.\"\"\"\r\n\r\n    SIGNIFICANCE_THRESHOLDS = {\r\n        VarianceSignificance.CRITICAL: 0.20,\r\n        VarianceSignificance.HIGH: 0.10,\r\n        VarianceSignificance.MEDIUM: 0.05,\r\n        VarianceSignificance.LOW: 0.01\r\n    }\r\n\r\n    def __init__(self):\r\n        pass\r\n\r\n    def _get_significance(self, variance_pct: float) -> VarianceSignificance:\r\n        \"\"\"Determine variance significance.\"\"\"\r\n        abs_var = abs(variance_pct) \u002F 100\r\n\r\n        if abs_var >= self.SIGNIFICANCE_THRESHOLDS[VarianceSignificance.CRITICAL]:\r\n            return VarianceSignificance.CRITICAL\r\n        elif abs_var >= self.SIGNIFICANCE_THRESHOLDS[VarianceSignificance.HIGH]:\r\n            return VarianceSignificance.HIGH\r\n        elif abs_var >= self.SIGNIFICANCE_THRESHOLDS[VarianceSignificance.MEDIUM]:\r\n            return VarianceSignificance.MEDIUM\r\n        elif abs_var >= self.SIGNIFICANCE_THRESHOLDS[VarianceSignificance.LOW]:\r\n            return VarianceSignificance.LOW\r\n        else:\r\n            return VarianceSignificance.NONE\r\n\r\n    def compare_estimates(self,\r\n                          base_df: pd.DataFrame,\r\n                          compare_df: pd.DataFrame,\r\n                          base_name: str = \"Base\",\r\n                          compare_name: str = \"Compare\",\r\n                          comparison_type: ComparisonType = ComparisonType.VERSION,\r\n                          code_column: str = 'work_item_code',\r\n                          quantity_column: str = 'quantity',\r\n                          cost_column: str = 'total_cost') -> ComparisonResult:\r\n        \"\"\"Compare two estimates.\"\"\"\r\n\r\n        # Merge on code\r\n        merged = base_df.merge(\r\n            compare_df,\r\n            on=code_column,\r\n            how='outer',\r\n            suffixes=('_base', '_compare')\r\n        )\r\n\r\n        items = []\r\n        for _, row in merged.iterrows():\r\n            base_qty = float(row.get(f'{quantity_column}_base', 0) or 0)\r\n            base_cost = float(row.get(f'{cost_column}_base', 0) or 0)\r\n            compare_qty = float(row.get(f'{quantity_column}_compare', 0) or 0)\r\n            compare_cost = float(row.get(f'{cost_column}_compare', 0) or 0)\r\n\r\n            qty_variance = compare_qty - base_qty\r\n            qty_variance_pct = (qty_variance \u002F base_qty * 100) if base_qty > 0 else (100 if compare_qty > 0 else 0)\r\n\r\n            cost_variance = compare_cost - base_cost\r\n            cost_variance_pct = (cost_variance \u002F base_cost * 100) if base_cost > 0 else (100 if compare_cost > 0 else 0)\r\n\r\n            items.append(ComparisonItem(\r\n                work_item_code=str(row.get(code_column, '')),\r\n                description=str(row.get('description_base', row.get('description_compare', ''))),\r\n                base_quantity=base_qty,\r\n                base_cost=base_cost,\r\n                compare_quantity=compare_qty,\r\n                compare_cost=compare_cost,\r\n                quantity_variance=round(qty_variance, 2),\r\n                quantity_variance_pct=round(qty_variance_pct, 1),\r\n                cost_variance=round(cost_variance, 2),\r\n                cost_variance_pct=round(cost_variance_pct, 1),\r\n                significance=self._get_significance(cost_variance_pct)\r\n            ))\r\n\r\n        # Totals\r\n        base_total = sum(i.base_cost for i in items)\r\n        compare_total = sum(i.compare_cost for i in items)\r\n        total_variance = compare_total - base_total\r\n        total_variance_pct = (total_variance \u002F base_total * 100) if base_total > 0 else 0\r\n\r\n        # Summary by category\r\n        summary_by_category = self._summarize_by_category(items, merged)\r\n\r\n        return ComparisonResult(\r\n            comparison_type=comparison_type,\r\n            base_name=base_name,\r\n            compare_name=compare_name,\r\n            base_total=round(base_total, 2),\r\n            compare_total=round(compare_total, 2),\r\n            total_variance=round(total_variance, 2),\r\n            total_variance_pct=round(total_variance_pct, 1),\r\n            items=items,\r\n            summary_by_category=summary_by_category,\r\n            created_at=datetime.now()\r\n        )\r\n\r\n    def _summarize_by_category(self,\r\n                                items: List[ComparisonItem],\r\n                                merged_df: pd.DataFrame) -> Dict[str, Dict[str, float]]:\r\n        \"\"\"Summarize comparison by category.\"\"\"\r\n\r\n        summary = {}\r\n\r\n        # Try to extract category from work item code prefix\r\n        for item in items:\r\n            code = item.work_item_code\r\n            category = code.split('-')[0] if '-' in code else 'Other'\r\n\r\n            if category not in summary:\r\n                summary[category] = {\r\n                    'base_cost': 0,\r\n                    'compare_cost': 0,\r\n                    'variance': 0,\r\n                    'variance_pct': 0,\r\n                    'item_count': 0\r\n                }\r\n\r\n            summary[category]['base_cost'] += item.base_cost\r\n            summary[category]['compare_cost'] += item.compare_cost\r\n            summary[category]['variance'] += item.cost_variance\r\n            summary[category]['item_count'] += 1\r\n\r\n        # Calculate percentages\r\n        for category in summary:\r\n            base = summary[category]['base_cost']\r\n            if base > 0:\r\n                summary[category]['variance_pct'] = round(\r\n                    summary[category]['variance'] \u002F base * 100, 1\r\n                )\r\n\r\n        return summary\r\n\r\n    def get_significant_variances(self,\r\n                                   result: ComparisonResult,\r\n                                   min_significance: VarianceSignificance = VarianceSignificance.MEDIUM) -> List[ComparisonItem]:\r\n        \"\"\"Get items with significant variances.\"\"\"\r\n\r\n        significance_order = [\r\n            VarianceSignificance.CRITICAL,\r\n            VarianceSignificance.HIGH,\r\n            VarianceSignificance.MEDIUM,\r\n            VarianceSignificance.LOW,\r\n            VarianceSignificance.NONE\r\n        ]\r\n\r\n        min_index = significance_order.index(min_significance)\r\n        significant = [\r\n            item for item in result.items\r\n            if significance_order.index(item.significance) \u003C= min_index\r\n        ]\r\n\r\n        return sorted(significant, key=lambda x: abs(x.cost_variance), reverse=True)\r\n\r\n    def compare_multiple(self,\r\n                          estimates: List[Tuple[str, pd.DataFrame]],\r\n                          base_index: int = 0) -> Dict[str, ComparisonResult]:\r\n        \"\"\"Compare multiple estimates against base.\"\"\"\r\n\r\n        base_name, base_df = estimates[base_index]\r\n        results = {}\r\n\r\n        for i, (name, df) in enumerate(estimates):\r\n            if i == base_index:\r\n                continue\r\n\r\n            result = self.compare_estimates(\r\n                base_df=base_df,\r\n                compare_df=df,\r\n                base_name=base_name,\r\n                compare_name=name,\r\n                comparison_type=ComparisonType.ALTERNATIVE\r\n            )\r\n            results[name] = result\r\n\r\n        return results\r\n\r\n    def benchmark_comparison(self,\r\n                              project_df: pd.DataFrame,\r\n                              benchmark_df: pd.DataFrame,\r\n                              project_name: str,\r\n                              benchmark_name: str = \"Industry Benchmark\") -> ComparisonResult:\r\n        \"\"\"Compare project against benchmark.\"\"\"\r\n\r\n        return self.compare_estimates(\r\n            base_df=benchmark_df,\r\n            compare_df=project_df,\r\n            base_name=benchmark_name,\r\n            compare_name=project_name,\r\n            comparison_type=ComparisonType.BENCHMARK\r\n        )\r\n\r\n    def version_comparison(self,\r\n                           versions: List[Tuple[str, pd.DataFrame]]) -> List[ComparisonResult]:\r\n        \"\"\"Compare sequential versions.\"\"\"\r\n\r\n        results = []\r\n\r\n        for i in range(1, len(versions)):\r\n            prev_name, prev_df = versions[i-1]\r\n            curr_name, curr_df = versions[i]\r\n\r\n            result = self.compare_estimates(\r\n                base_df=prev_df,\r\n                compare_df=curr_df,\r\n                base_name=prev_name,\r\n                compare_name=curr_name,\r\n                comparison_type=ComparisonType.VERSION\r\n            )\r\n            results.append(result)\r\n\r\n        return results\r\n\r\n    def export_comparison(self,\r\n                          result: ComparisonResult,\r\n                          output_path: str) -> str:\r\n        \"\"\"Export comparison to Excel.\"\"\"\r\n\r\n        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:\r\n            # Summary\r\n            summary_df = pd.DataFrame([{\r\n                'Comparison Type': result.comparison_type.value,\r\n                'Base': result.base_name,\r\n                'Compare': result.compare_name,\r\n                'Base Total': result.base_total,\r\n                'Compare Total': result.compare_total,\r\n                'Variance': result.total_variance,\r\n                'Variance %': result.total_variance_pct,\r\n                'Generated': result.created_at.strftime('%Y-%m-%d %H:%M')\r\n            }])\r\n            summary_df.to_excel(writer, sheet_name='Summary', index=False)\r\n\r\n            # Details\r\n            details_df = pd.DataFrame([\r\n                {\r\n                    'Work Item': i.work_item_code,\r\n                    'Description': i.description,\r\n                    f'{result.base_name} Qty': i.base_quantity,\r\n                    f'{result.base_name} Cost': i.base_cost,\r\n                    f'{result.compare_name} Qty': i.compare_quantity,\r\n                    f'{result.compare_name} Cost': i.compare_cost,\r\n                    'Qty Variance': i.quantity_variance,\r\n                    'Qty Variance %': i.quantity_variance_pct,\r\n                    'Cost Variance': i.cost_variance,\r\n                    'Cost Variance %': i.cost_variance_pct,\r\n                    'Significance': i.significance.value\r\n                }\r\n                for i in result.items\r\n            ])\r\n            details_df.to_excel(writer, sheet_name='Details', index=False)\r\n\r\n            # By Category\r\n            cat_df = pd.DataFrame([\r\n                {\r\n                    'Category': cat,\r\n                    'Base Cost': data['base_cost'],\r\n                    'Compare Cost': data['compare_cost'],\r\n                    'Variance': data['variance'],\r\n                    'Variance %': data['variance_pct'],\r\n                    'Items': data['item_count']\r\n                }\r\n                for cat, data in result.summary_by_category.items()\r\n            ])\r\n            cat_df.to_excel(writer, sheet_name='By Category', index=False)\r\n\r\n            # Significant Variances\r\n            significant = self.get_significant_variances(result)\r\n            sig_df = pd.DataFrame([\r\n                {\r\n                    'Work Item': i.work_item_code,\r\n                    'Description': i.description,\r\n                    'Cost Variance': i.cost_variance,\r\n                    'Variance %': i.cost_variance_pct,\r\n                    'Significance': i.significance.value\r\n                }\r\n                for i in significant\r\n            ])\r\n            sig_df.to_excel(writer, sheet_name='Significant', index=False)\r\n\r\n        return output_path\r\n\r\n\r\nclass ComparisonAnalytics:\r\n    \"\"\"Analytics for comparison results.\"\"\"\r\n\r\n    def __init__(self, comparison_tool: CWICRComparisonTool):\r\n        self.tool = comparison_tool\r\n\r\n    def variance_distribution(self, result: ComparisonResult) -> Dict[str, int]:\r\n        \"\"\"Get distribution of variance significance.\"\"\"\r\n\r\n        distribution = {s.value: 0 for s in VarianceSignificance}\r\n\r\n        for item in result.items:\r\n            distribution[item.significance.value] += 1\r\n\r\n        return distribution\r\n\r\n    def top_variances(self,\r\n                      result: ComparisonResult,\r\n                      n: int = 10,\r\n                      positive: bool = True) -> List[ComparisonItem]:\r\n        \"\"\"Get top N variances (positive or negative).\"\"\"\r\n\r\n        if positive:\r\n            sorted_items = sorted(result.items, key=lambda x: x.cost_variance, reverse=True)\r\n        else:\r\n            sorted_items = sorted(result.items, key=lambda x: x.cost_variance)\r\n\r\n        return sorted_items[:n]\r\n\r\n    def category_impact(self, result: ComparisonResult) -> pd.DataFrame:\r\n        \"\"\"Analyze which categories contribute most to variance.\"\"\"\r\n\r\n        data = []\r\n        for cat, values in result.summary_by_category.items():\r\n            contribution_pct = (values['variance'] \u002F result.total_variance * 100) if result.total_variance != 0 else 0\r\n            data.append({\r\n                'Category': cat,\r\n                'Variance': values['variance'],\r\n                'Contribution %': round(contribution_pct, 1)\r\n            })\r\n\r\n        return pd.DataFrame(data).sort_values('Contribution %', ascending=False)\r\n\r\n    def trend_analysis(self,\r\n                        version_results: List[ComparisonResult]) -> pd.DataFrame:\r\n        \"\"\"Analyze cost trend across versions.\"\"\"\r\n\r\n        data = []\r\n        cumulative = 0\r\n\r\n        for result in version_results:\r\n            cumulative += result.total_variance\r\n            data.append({\r\n                'From': result.base_name,\r\n                'To': result.compare_name,\r\n                'Variance': result.total_variance,\r\n                'Variance %': result.total_variance_pct,\r\n                'Cumulative Variance': cumulative\r\n            })\r\n\r\n        return pd.DataFrame(data)\r\n```\r\n\r\n## Quick Start\r\n\r\n```python\r\n# Initialize comparison tool\r\ntool = CWICRComparisonTool()\r\n\r\n# Compare two estimate versions\r\nresult = tool.compare_estimates(\r\n    base_df=estimate_v1,\r\n    compare_df=estimate_v2,\r\n    base_name=\"Estimate v1.0\",\r\n    compare_name=\"Estimate v2.0\"\r\n)\r\n\r\nprint(f\"Total Variance: ${result.total_variance:,.2f} ({result.total_variance_pct}%)\")\r\n```\r\n\r\n## Common Use Cases\r\n\r\n### 1. Significant Variances\r\n```python\r\nsignificant = tool.get_significant_variances(result)\r\nfor item in significant[:5]:\r\n    print(f\"{item.work_item_code}: ${item.cost_variance:,.2f} ({item.significance.value})\")\r\n```\r\n\r\n### 2. Version History\r\n```python\r\nversions = [\r\n    (\"v1.0\", estimate_v1),\r\n    (\"v2.0\", estimate_v2),\r\n    (\"v3.0\", estimate_v3)\r\n]\r\nversion_results = tool.version_comparison(versions)\r\n\r\nanalytics = ComparisonAnalytics(tool)\r\ntrend = analytics.trend_analysis(version_results)\r\n```\r\n\r\n### 3. Design Alternatives\r\n```python\r\nalternatives = [\r\n    (\"Option A - Steel\", option_a),\r\n    (\"Option B - Concrete\", option_b),\r\n    (\"Option C - Hybrid\", option_c)\r\n]\r\ncomparisons = tool.compare_multiple(alternatives, base_index=0)\r\n```\r\n\r\n### 4. Export Report\r\n```python\r\ntool.export_comparison(result, \"estimate_comparison.xlsx\")\r\n```\r\n\r\n## Resources\r\n- **GitHub**: [OpenConstructionEstimate-DDC-CWICR](https:\u002F\u002Fgithub.com\u002Fdatadrivenconstruction\u002FOpenConstructionEstimate-DDC-CWICR)\r\n- **DDC Book**: Chapter 3.1 - Estimate Management\r\n",{"slug":5,"description":7,"display_name":34},"CWICR Comparison Tool","main","e7e336ac628c3e3bd771aff1aaa469c93778f94a","skills\u002Fdatadrivenconstruction\u002Fcwicr-comparison-tool",0,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del","2026-08-23 22:39:37",{"source":8,"skillName":5,"commands":43,"prompt":53,"zipAvailable":54},[44,47,50],{"tool":45,"command":46},"npx","npx skills add kbarbel640-del\u002Fskills --skill cwicr-comparison-tool",{"tool":48,"command":49},"bunx","bunx skills add kbarbel640-del\u002Fskills --skill cwicr-comparison-tool",{"tool":51,"command":52},"pnpm","pnpm dlx skills add kbarbel640-del\u002Fskills --skill cwicr-comparison-tool","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fcwicr-comparison-tool\u002FSKILL.md",true,[56],{"path":57,"resourceType":58,"resourceTypeDesc":59,"sizeBytes":60,"sourceHtmlUrl":61},"_meta.json","REFERENCE","参考文档",310,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fcwicr-comparison-tool\u002F_meta.json",[63,93,122,143,149,169],{"skillNo":64,"name":65,"nameZh":6,"description":66,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":67,"categories":68,"keywords":74,"publishedAt":29},"01M6G8J55967D6281ACMKAKTEQ","crowd-prompting","A marketplace where AI agents improve prompts, system instructions, tool descriptions, and other text-based content with domain expertise from real-world operations — and earn tokens for valuable contributions.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzzadrian\u002Fcrowd-prompting\u002FSKILL.md",[69],{"categoryNo":70,"categoryName":71,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[75,76,77,78,79,80,81,82,83,84,85,18,86,87,88,89,90,91,92],"crowd prompting","prompting","api","with","tokens","domain","world","prompts","operations","instructions","text","system","improve","productivity","marketplace","https","content","ai agents",{"skillNo":94,"name":95,"nameZh":6,"description":96,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":97,"categories":98,"keywords":104,"publishedAt":29},"01M6G8J0PKPAYVET6BWE8W4C26","dilemm-ai","Compete in DilemmAI, the prisoner's dilemma AI arena at dilemm.ai. Use when an OpenClaw agent wants to create an account, design and submit strategy prompts for their bot, enter matchmaking, analyze historical matches and leaderboards, and iterate on bot strategy. Requires headless browser automation (no API available yet).","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzyori\u002Fdilemm-ai\u002FSKILL.md",[99],{"categoryNo":100,"categoryName":101,"taxonomyType":102,"taxonomyTypeDesc":103},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[105,77,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,82,121],"dilemm ai","arena","analyze","browser","openclaw agent","create","automation","browser automation","bot","openclaw","design","strategy","headless","compete","submit","matchmaking","use",{"skillNo":123,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":131,"publishedAt":29},"01M6G8HWAF3K9SW7NP3Z83CPJ6","arxiv-paper-reviews","Interact with arXiv Crawler API to fetch papers, read reviews, and submit comments. Use when working with arXiv papers, fetching paper lists by date\u002Fcategory\u002Finterest, viewing paper details with comments, or submitting paper reviews via API at http:\u002F\u002F150.158.152.82:8000.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Fweak-accept\u002FSKILL.md",[128],{"categoryNo":129,"categoryName":130,"taxonomyType":102,"taxonomyTypeDesc":103},"01JBSEEDCAT000000000000021","资料检索与研究",[132,133,134,135,136,137,138,78,139,119,121,140,77,141,142],"arxiv paper reviews","reviews","arxiv","paper","crawler","papers","comments","fetch","read","http","via",{"skillNo":144,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":148,"publishedAt":29},"01M6G8HQJ7N7WMY6YV7D7SSJ16","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Farxiv-paper-reviews\u002FSKILL.md",[147],{"categoryNo":129,"categoryName":130,"taxonomyType":102,"taxonomyTypeDesc":103},[135,134,133,132,142,137,138,78,136,119,121,139,140,77,141],{"skillNo":150,"name":151,"nameZh":6,"description":152,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":153,"categories":154,"keywords":155,"publishedAt":29},"01M6G8HM95Y64JNVFC2HN4E2BG","git-summary","Get a quick summary of the current Git repository including status, recent commits, branches, and contributors.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzweack\u002Fgit-summary\u002FSKILL.md",[],[156,157,158,159,160,161,162,163,164,165,166,167,168],"git","summary","git summary","commits","repository","win32","status","linux","contributors","true","quick","get","branches",{"skillNo":170,"name":171,"nameZh":6,"description":172,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":173,"categories":174,"keywords":179,"publishedAt":29},"01M6G8HGEGF05CNEJCGVYFSC4R","agent-constitution","Interact with AgentConstitution governance contracts on Base Sepolia. Check compliance, read rules, log actions, query governance state.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fztsalexey\u002Fagent-constitution\u002FSKILL.md",[175,176],{"categoryNo":100,"categoryName":101,"taxonomyType":102,"taxonomyTypeDesc":103},{"categoryNo":177,"categoryName":178,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000037","律师与法务",[180,181,182,183,78,184,185,35,186,140,187,188,23,189,190,90,191,192,193],"agent constitution","constitution","contracts","tree","query","base","log","check","Rules","compliance","actions","state","governance","github"]