[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FJPKVBMG2FSVT0PMAVYQ6N":3,"skill-same:01M6FJPKVBMG2FSVT0PMAVYQ6N":61},{"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":28,"linkOnly":29,"markdownContent":30,"markdownBody":31,"frontMatter":32,"refName":34,"commitSha":35,"skillDirectory":36,"forksCount":37,"repositoryHtmlUrl":38,"repositoryHomepageUrl":6,"ownerHtmlUrl":39,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":40,"install":41,"resources":54},"01M6FJPKVBMG2FSVT0PMAVYQ6N","cwicr-historical-cost",null,"Track and analyze historical cost data using CWICR. Compare actual vs estimated costs, build project cost database, and improve future estimates.","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-historical-cost\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27],"cost","cwicr historical cost","database","data","improve","analyze","build","project","compare","build project","2026-11-10 10:12:30",false,"---\r\nslug: \"cwicr-historical-cost\"\r\ndisplay_name: \"CWICR Historical Cost\"\r\ndescription: \"Track and analyze historical cost data using CWICR. Compare actual vs estimated costs, build project cost database, and improve future estimates.\"\r\n---\r\n\r\n# CWICR Historical Cost Tracker\r\n\r\n## Business Case\r\n\r\n### Problem Statement\r\nImproving estimates requires:\r\n- Actual cost feedback\r\n- Historical comparisons\r\n- Trend analysis\r\n- Lessons learned\r\n\r\n### Solution\r\nTrack actual costs against CWICR estimates, build historical database, and use data to improve future estimating accuracy.\r\n\r\n### Business Value\r\n- **Accuracy improvement** - Learn from actuals\r\n- **Benchmarking** - Project comparisons\r\n- **Trend analysis** - Cost movement patterns\r\n- **Organizational knowledge** - Cost database\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\r\nfrom dataclasses import dataclass, field\r\nfrom datetime import datetime, date\r\nfrom enum import Enum\r\nimport json\r\n\r\n\r\nclass ProjectStatus(Enum):\r\n    \"\"\"Project status.\"\"\"\r\n    ESTIMATED = \"estimated\"\r\n    IN_PROGRESS = \"in_progress\"\r\n    COMPLETED = \"completed\"\r\n    CANCELLED = \"cancelled\"\r\n\r\n\r\n@dataclass\r\nclass CostRecord:\r\n    \"\"\"Historical cost record.\"\"\"\r\n    project_id: str\r\n    project_name: str\r\n    work_item_code: str\r\n    quantity: float\r\n    estimated_cost: float\r\n    actual_cost: float\r\n    variance: float\r\n    variance_percent: float\r\n    completion_date: date\r\n    notes: str = \"\"\r\n\r\n\r\n@dataclass\r\nclass ProjectCostSummary:\r\n    \"\"\"Project cost summary.\"\"\"\r\n    project_id: str\r\n    project_name: str\r\n    project_type: str\r\n    location: str\r\n    status: ProjectStatus\r\n    estimated_total: float\r\n    actual_total: float\r\n    variance: float\r\n    variance_percent: float\r\n    start_date: date\r\n    completion_date: Optional[date]\r\n    item_count: int\r\n\r\n\r\nclass CWICRHistoricalCost:\r\n    \"\"\"Track historical costs using CWICR data.\"\"\"\r\n\r\n    def __init__(self, cwicr_data: pd.DataFrame = None):\r\n        self.cwicr = cwicr_data\r\n        self._projects: Dict[str, ProjectCostSummary] = {}\r\n        self._records: List[CostRecord] = []\r\n\r\n        if cwicr_data is not None:\r\n            self._index_cwicr()\r\n\r\n    def _index_cwicr(self):\r\n        \"\"\"Index CWICR data.\"\"\"\r\n        if 'work_item_code' in self.cwicr.columns:\r\n            self._cwicr_index = self.cwicr.set_index('work_item_code')\r\n        else:\r\n            self._cwicr_index = None\r\n\r\n    def add_project(self,\r\n                    project_id: str,\r\n                    project_name: str,\r\n                    project_type: str,\r\n                    location: str,\r\n                    estimated_total: float,\r\n                    start_date: date) -> str:\r\n        \"\"\"Add new project to historical database.\"\"\"\r\n\r\n        summary = ProjectCostSummary(\r\n            project_id=project_id,\r\n            project_name=project_name,\r\n            project_type=project_type,\r\n            location=location,\r\n            status=ProjectStatus.ESTIMATED,\r\n            estimated_total=estimated_total,\r\n            actual_total=0,\r\n            variance=0,\r\n            variance_percent=0,\r\n            start_date=start_date,\r\n            completion_date=None,\r\n            item_count=0\r\n        )\r\n\r\n        self._projects[project_id] = summary\r\n        return project_id\r\n\r\n    def record_actual_cost(self,\r\n                           project_id: str,\r\n                           work_item_code: str,\r\n                           quantity: float,\r\n                           actual_cost: float,\r\n                           completion_date: date = None,\r\n                           notes: str = \"\") -> CostRecord:\r\n        \"\"\"Record actual cost for work item.\"\"\"\r\n\r\n        # Get estimated cost from CWICR\r\n        estimated_unit_cost = 0\r\n        if self._cwicr_index is not None and work_item_code in self._cwicr_index.index:\r\n            item = self._cwicr_index.loc[work_item_code]\r\n            labor = float(item.get('labor_cost', 0) or 0)\r\n            material = float(item.get('material_cost', 0) or 0)\r\n            equipment = float(item.get('equipment_cost', 0) or 0)\r\n            estimated_unit_cost = labor + material + equipment\r\n\r\n        estimated_cost = estimated_unit_cost * quantity\r\n        variance = actual_cost - estimated_cost\r\n        variance_pct = (variance \u002F estimated_cost * 100) if estimated_cost > 0 else 0\r\n\r\n        record = CostRecord(\r\n            project_id=project_id,\r\n            project_name=self._projects.get(project_id, {}).project_name if project_id in self._projects else \"\",\r\n            work_item_code=work_item_code,\r\n            quantity=quantity,\r\n            estimated_cost=round(estimated_cost, 2),\r\n            actual_cost=round(actual_cost, 2),\r\n            variance=round(variance, 2),\r\n            variance_percent=round(variance_pct, 1),\r\n            completion_date=completion_date or date.today(),\r\n            notes=notes\r\n        )\r\n\r\n        self._records.append(record)\r\n\r\n        # Update project summary\r\n        if project_id in self._projects:\r\n            proj = self._projects[project_id]\r\n            proj.actual_total += actual_cost\r\n            proj.variance = proj.actual_total - proj.estimated_total\r\n            proj.variance_percent = (proj.variance \u002F proj.estimated_total * 100) if proj.estimated_total > 0 else 0\r\n            proj.item_count += 1\r\n            proj.status = ProjectStatus.IN_PROGRESS\r\n\r\n        return record\r\n\r\n    def complete_project(self, project_id: str, completion_date: date = None):\r\n        \"\"\"Mark project as completed.\"\"\"\r\n        if project_id in self._projects:\r\n            self._projects[project_id].status = ProjectStatus.COMPLETED\r\n            self._projects[project_id].completion_date = completion_date or date.today()\r\n\r\n    def get_work_item_history(self, work_item_code: str) -> Dict[str, Any]:\r\n        \"\"\"Get historical data for specific work item.\"\"\"\r\n\r\n        records = [r for r in self._records if r.work_item_code == work_item_code]\r\n\r\n        if not records:\r\n            return {'work_item_code': work_item_code, 'records': 0}\r\n\r\n        variances = [r.variance_percent for r in records]\r\n        actual_costs = [r.actual_cost \u002F r.quantity if r.quantity > 0 else 0 for r in records]\r\n\r\n        return {\r\n            'work_item_code': work_item_code,\r\n            'records': len(records),\r\n            'average_variance_pct': round(np.mean(variances), 1),\r\n            'variance_std': round(np.std(variances), 1),\r\n            'average_actual_unit_cost': round(np.mean(actual_costs), 2),\r\n            'min_actual_unit_cost': round(min(actual_costs), 2),\r\n            'max_actual_unit_cost': round(max(actual_costs), 2),\r\n            'projects': list(set(r.project_id for r in records)),\r\n            'trend': 'increasing' if len(records) > 2 and actual_costs[-1] > actual_costs[0] else 'stable'\r\n        }\r\n\r\n    def get_accuracy_metrics(self) -> Dict[str, Any]:\r\n        \"\"\"Calculate overall estimating accuracy metrics.\"\"\"\r\n\r\n        if not self._records:\r\n            return {}\r\n\r\n        variances = [r.variance_percent for r in self._records]\r\n\r\n        # Accuracy by category\r\n        by_category = {}\r\n        for record in self._records:\r\n            category = record.work_item_code.split('-')[0] if '-' in record.work_item_code else 'Other'\r\n            if category not in by_category:\r\n                by_category[category] = []\r\n            by_category[category].append(record.variance_percent)\r\n\r\n        category_accuracy = {\r\n            cat: {\r\n                'average_variance': round(np.mean(vals), 1),\r\n                'count': len(vals)\r\n            }\r\n            for cat, vals in by_category.items()\r\n        }\r\n\r\n        return {\r\n            'total_records': len(self._records),\r\n            'average_variance_pct': round(np.mean(variances), 1),\r\n            'variance_std': round(np.std(variances), 1),\r\n            'within_5pct': sum(1 for v in variances if abs(v) \u003C= 5) \u002F len(variances) * 100,\r\n            'within_10pct': sum(1 for v in variances if abs(v) \u003C= 10) \u002F len(variances) * 100,\r\n            'overestimated_pct': sum(1 for v in variances if v \u003C 0) \u002F len(variances) * 100,\r\n            'underestimated_pct': sum(1 for v in variances if v > 0) \u002F len(variances) * 100,\r\n            'by_category': category_accuracy\r\n        }\r\n\r\n    def suggest_adjustment_factors(self) -> Dict[str, float]:\r\n        \"\"\"Suggest adjustment factors based on historical variance.\"\"\"\r\n\r\n        factors = {}\r\n\r\n        for record in self._records:\r\n            category = record.work_item_code.split('-')[0] if '-' in record.work_item_code else 'Other'\r\n            if category not in factors:\r\n                factors[category] = []\r\n\r\n            if record.estimated_cost > 0:\r\n                actual_factor = record.actual_cost \u002F record.estimated_cost\r\n                factors[category].append(actual_factor)\r\n\r\n        return {\r\n            cat: round(np.mean(vals), 3)\r\n            for cat, vals in factors.items()\r\n            if len(vals) >= 3  # Require minimum data points\r\n        }\r\n\r\n    def compare_projects(self,\r\n                          project_ids: List[str] = None) -> pd.DataFrame:\r\n        \"\"\"Compare multiple projects.\"\"\"\r\n\r\n        if project_ids:\r\n            projects = [self._projects[pid] for pid in project_ids if pid in self._projects]\r\n        else:\r\n            projects = list(self._projects.values())\r\n\r\n        if not projects:\r\n            return pd.DataFrame()\r\n\r\n        return pd.DataFrame([\r\n            {\r\n                'Project ID': p.project_id,\r\n                'Project Name': p.project_name,\r\n                'Type': p.project_type,\r\n                'Location': p.location,\r\n                'Status': p.status.value,\r\n                'Estimated': p.estimated_total,\r\n                'Actual': p.actual_total,\r\n                'Variance': p.variance,\r\n                'Variance %': p.variance_percent,\r\n                'Items': p.item_count\r\n            }\r\n            for p in projects\r\n        ])\r\n\r\n    def get_benchmarks_by_type(self, project_type: str) -> Dict[str, Any]:\r\n        \"\"\"Get cost benchmarks for project type.\"\"\"\r\n\r\n        projects = [p for p in self._projects.values() if p.project_type == project_type]\r\n\r\n        if not projects:\r\n            return {}\r\n\r\n        actuals = [p.actual_total for p in projects if p.status == ProjectStatus.COMPLETED]\r\n\r\n        return {\r\n            'project_type': project_type,\r\n            'completed_projects': len(actuals),\r\n            'average_cost': round(np.mean(actuals), 2) if actuals else 0,\r\n            'min_cost': round(min(actuals), 2) if actuals else 0,\r\n            'max_cost': round(max(actuals), 2) if actuals else 0,\r\n            'average_variance': round(np.mean([p.variance_percent for p in projects]), 1)\r\n        }\r\n\r\n    def export_historical_data(self, output_path: str) -> str:\r\n        \"\"\"Export historical data to Excel.\"\"\"\r\n\r\n        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:\r\n            # Projects\r\n            if self._projects:\r\n                projects_df = self.compare_projects()\r\n                projects_df.to_excel(writer, sheet_name='Projects', index=False)\r\n\r\n            # Records\r\n            if self._records:\r\n                records_df = pd.DataFrame([\r\n                    {\r\n                        'Project': r.project_id,\r\n                        'Work Item': r.work_item_code,\r\n                        'Quantity': r.quantity,\r\n                        'Estimated': r.estimated_cost,\r\n                        'Actual': r.actual_cost,\r\n                        'Variance': r.variance,\r\n                        'Variance %': r.variance_percent,\r\n                        'Date': r.completion_date,\r\n                        'Notes': r.notes\r\n                    }\r\n                    for r in self._records\r\n                ])\r\n                records_df.to_excel(writer, sheet_name='Records', index=False)\r\n\r\n            # Accuracy metrics\r\n            metrics = self.get_accuracy_metrics()\r\n            if metrics:\r\n                metrics_df = pd.DataFrame([{\r\n                    'Total Records': metrics.get('total_records', 0),\r\n                    'Avg Variance %': metrics.get('average_variance_pct', 0),\r\n                    'Within 5%': f\"{metrics.get('within_5pct', 0):.1f}%\",\r\n                    'Within 10%': f\"{metrics.get('within_10pct', 0):.1f}%\"\r\n                }])\r\n                metrics_df.to_excel(writer, sheet_name='Accuracy', index=False)\r\n\r\n        return output_path\r\n\r\n    def save_database(self, filepath: str):\r\n        \"\"\"Save historical database to JSON.\"\"\"\r\n        data = {\r\n            'projects': {\r\n                pid: {\r\n                    'project_id': p.project_id,\r\n                    'project_name': p.project_name,\r\n                    'project_type': p.project_type,\r\n                    'location': p.location,\r\n                    'status': p.status.value,\r\n                    'estimated_total': p.estimated_total,\r\n                    'actual_total': p.actual_total,\r\n                    'start_date': p.start_date.isoformat(),\r\n                    'completion_date': p.completion_date.isoformat() if p.completion_date else None\r\n                }\r\n                for pid, p in self._projects.items()\r\n            },\r\n            'records': [\r\n                {\r\n                    'project_id': r.project_id,\r\n                    'work_item_code': r.work_item_code,\r\n                    'quantity': r.quantity,\r\n                    'estimated_cost': r.estimated_cost,\r\n                    'actual_cost': r.actual_cost,\r\n                    'completion_date': r.completion_date.isoformat(),\r\n                    'notes': r.notes\r\n                }\r\n                for r in self._records\r\n            ]\r\n        }\r\n\r\n        with open(filepath, 'w') as f:\r\n            json.dump(data, f, indent=2)\r\n```\r\n\r\n## Quick Start\r\n\r\n```python\r\nfrom datetime import date\r\n\r\n# Load CWICR data\r\ncwicr = pd.read_parquet(\"ddc_cwicr_en.parquet\")\r\n\r\n# Initialize tracker\r\ntracker = CWICRHistoricalCost(cwicr)\r\n\r\n# Add project\r\ntracker.add_project(\r\n    project_id=\"PROJ-001\",\r\n    project_name=\"Office Building A\",\r\n    project_type=\"commercial\",\r\n    location=\"New York\",\r\n    estimated_total=5000000,\r\n    start_date=date(2024, 1, 1)\r\n)\r\n\r\n# Record actual costs\r\ntracker.record_actual_cost(\r\n    project_id=\"PROJ-001\",\r\n    work_item_code=\"CONC-001\",\r\n    quantity=200,\r\n    actual_cost=32000,\r\n    notes=\"Slightly over due to overtime\"\r\n)\r\n```\r\n\r\n## Common Use Cases\r\n\r\n### 1. Accuracy Analysis\r\n```python\r\nmetrics = tracker.get_accuracy_metrics()\r\nprint(f\"Within 10%: {metrics['within_10pct']:.1f}%\")\r\n```\r\n\r\n### 2. Adjustment Factors\r\n```python\r\nfactors = tracker.suggest_adjustment_factors()\r\nfor cat, factor in factors.items():\r\n    print(f\"{cat}: {factor:.2f}x\")\r\n```\r\n\r\n### 3. Work Item History\r\n```python\r\nhistory = tracker.get_work_item_history(\"CONC-001\")\r\nprint(f\"Average variance: {history['average_variance_pct']}%\")\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.2 - Historical Cost Analysis\r\n","# CWICR Historical Cost Tracker\r\n\r\n## Business Case\r\n\r\n### Problem Statement\r\nImproving estimates requires:\r\n- Actual cost feedback\r\n- Historical comparisons\r\n- Trend analysis\r\n- Lessons learned\r\n\r\n### Solution\r\nTrack actual costs against CWICR estimates, build historical database, and use data to improve future estimating accuracy.\r\n\r\n### Business Value\r\n- **Accuracy improvement** - Learn from actuals\r\n- **Benchmarking** - Project comparisons\r\n- **Trend analysis** - Cost movement patterns\r\n- **Organizational knowledge** - Cost database\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\r\nfrom dataclasses import dataclass, field\r\nfrom datetime import datetime, date\r\nfrom enum import Enum\r\nimport json\r\n\r\n\r\nclass ProjectStatus(Enum):\r\n    \"\"\"Project status.\"\"\"\r\n    ESTIMATED = \"estimated\"\r\n    IN_PROGRESS = \"in_progress\"\r\n    COMPLETED = \"completed\"\r\n    CANCELLED = \"cancelled\"\r\n\r\n\r\n@dataclass\r\nclass CostRecord:\r\n    \"\"\"Historical cost record.\"\"\"\r\n    project_id: str\r\n    project_name: str\r\n    work_item_code: str\r\n    quantity: float\r\n    estimated_cost: float\r\n    actual_cost: float\r\n    variance: float\r\n    variance_percent: float\r\n    completion_date: date\r\n    notes: str = \"\"\r\n\r\n\r\n@dataclass\r\nclass ProjectCostSummary:\r\n    \"\"\"Project cost summary.\"\"\"\r\n    project_id: str\r\n    project_name: str\r\n    project_type: str\r\n    location: str\r\n    status: ProjectStatus\r\n    estimated_total: float\r\n    actual_total: float\r\n    variance: float\r\n    variance_percent: float\r\n    start_date: date\r\n    completion_date: Optional[date]\r\n    item_count: int\r\n\r\n\r\nclass CWICRHistoricalCost:\r\n    \"\"\"Track historical costs using CWICR data.\"\"\"\r\n\r\n    def __init__(self, cwicr_data: pd.DataFrame = None):\r\n        self.cwicr = cwicr_data\r\n        self._projects: Dict[str, ProjectCostSummary] = {}\r\n        self._records: List[CostRecord] = []\r\n\r\n        if cwicr_data is not None:\r\n            self._index_cwicr()\r\n\r\n    def _index_cwicr(self):\r\n        \"\"\"Index CWICR data.\"\"\"\r\n        if 'work_item_code' in self.cwicr.columns:\r\n            self._cwicr_index = self.cwicr.set_index('work_item_code')\r\n        else:\r\n            self._cwicr_index = None\r\n\r\n    def add_project(self,\r\n                    project_id: str,\r\n                    project_name: str,\r\n                    project_type: str,\r\n                    location: str,\r\n                    estimated_total: float,\r\n                    start_date: date) -> str:\r\n        \"\"\"Add new project to historical database.\"\"\"\r\n\r\n        summary = ProjectCostSummary(\r\n            project_id=project_id,\r\n            project_name=project_name,\r\n            project_type=project_type,\r\n            location=location,\r\n            status=ProjectStatus.ESTIMATED,\r\n            estimated_total=estimated_total,\r\n            actual_total=0,\r\n            variance=0,\r\n            variance_percent=0,\r\n            start_date=start_date,\r\n            completion_date=None,\r\n            item_count=0\r\n        )\r\n\r\n        self._projects[project_id] = summary\r\n        return project_id\r\n\r\n    def record_actual_cost(self,\r\n                           project_id: str,\r\n                           work_item_code: str,\r\n                           quantity: float,\r\n                           actual_cost: float,\r\n                           completion_date: date = None,\r\n                           notes: str = \"\") -> CostRecord:\r\n        \"\"\"Record actual cost for work item.\"\"\"\r\n\r\n        # Get estimated cost from CWICR\r\n        estimated_unit_cost = 0\r\n        if self._cwicr_index is not None and work_item_code in self._cwicr_index.index:\r\n            item = self._cwicr_index.loc[work_item_code]\r\n            labor = float(item.get('labor_cost', 0) or 0)\r\n            material = float(item.get('material_cost', 0) or 0)\r\n            equipment = float(item.get('equipment_cost', 0) or 0)\r\n            estimated_unit_cost = labor + material + equipment\r\n\r\n        estimated_cost = estimated_unit_cost * quantity\r\n        variance = actual_cost - estimated_cost\r\n        variance_pct = (variance \u002F estimated_cost * 100) if estimated_cost > 0 else 0\r\n\r\n        record = CostRecord(\r\n            project_id=project_id,\r\n            project_name=self._projects.get(project_id, {}).project_name if project_id in self._projects else \"\",\r\n            work_item_code=work_item_code,\r\n            quantity=quantity,\r\n            estimated_cost=round(estimated_cost, 2),\r\n            actual_cost=round(actual_cost, 2),\r\n            variance=round(variance, 2),\r\n            variance_percent=round(variance_pct, 1),\r\n            completion_date=completion_date or date.today(),\r\n            notes=notes\r\n        )\r\n\r\n        self._records.append(record)\r\n\r\n        # Update project summary\r\n        if project_id in self._projects:\r\n            proj = self._projects[project_id]\r\n            proj.actual_total += actual_cost\r\n            proj.variance = proj.actual_total - proj.estimated_total\r\n            proj.variance_percent = (proj.variance \u002F proj.estimated_total * 100) if proj.estimated_total > 0 else 0\r\n            proj.item_count += 1\r\n            proj.status = ProjectStatus.IN_PROGRESS\r\n\r\n        return record\r\n\r\n    def complete_project(self, project_id: str, completion_date: date = None):\r\n        \"\"\"Mark project as completed.\"\"\"\r\n        if project_id in self._projects:\r\n            self._projects[project_id].status = ProjectStatus.COMPLETED\r\n            self._projects[project_id].completion_date = completion_date or date.today()\r\n\r\n    def get_work_item_history(self, work_item_code: str) -> Dict[str, Any]:\r\n        \"\"\"Get historical data for specific work item.\"\"\"\r\n\r\n        records = [r for r in self._records if r.work_item_code == work_item_code]\r\n\r\n        if not records:\r\n            return {'work_item_code': work_item_code, 'records': 0}\r\n\r\n        variances = [r.variance_percent for r in records]\r\n        actual_costs = [r.actual_cost \u002F r.quantity if r.quantity > 0 else 0 for r in records]\r\n\r\n        return {\r\n            'work_item_code': work_item_code,\r\n            'records': len(records),\r\n            'average_variance_pct': round(np.mean(variances), 1),\r\n            'variance_std': round(np.std(variances), 1),\r\n            'average_actual_unit_cost': round(np.mean(actual_costs), 2),\r\n            'min_actual_unit_cost': round(min(actual_costs), 2),\r\n            'max_actual_unit_cost': round(max(actual_costs), 2),\r\n            'projects': list(set(r.project_id for r in records)),\r\n            'trend': 'increasing' if len(records) > 2 and actual_costs[-1] > actual_costs[0] else 'stable'\r\n        }\r\n\r\n    def get_accuracy_metrics(self) -> Dict[str, Any]:\r\n        \"\"\"Calculate overall estimating accuracy metrics.\"\"\"\r\n\r\n        if not self._records:\r\n            return {}\r\n\r\n        variances = [r.variance_percent for r in self._records]\r\n\r\n        # Accuracy by category\r\n        by_category = {}\r\n        for record in self._records:\r\n            category = record.work_item_code.split('-')[0] if '-' in record.work_item_code else 'Other'\r\n            if category not in by_category:\r\n                by_category[category] = []\r\n            by_category[category].append(record.variance_percent)\r\n\r\n        category_accuracy = {\r\n            cat: {\r\n                'average_variance': round(np.mean(vals), 1),\r\n                'count': len(vals)\r\n            }\r\n            for cat, vals in by_category.items()\r\n        }\r\n\r\n        return {\r\n            'total_records': len(self._records),\r\n            'average_variance_pct': round(np.mean(variances), 1),\r\n            'variance_std': round(np.std(variances), 1),\r\n            'within_5pct': sum(1 for v in variances if abs(v) \u003C= 5) \u002F len(variances) * 100,\r\n            'within_10pct': sum(1 for v in variances if abs(v) \u003C= 10) \u002F len(variances) * 100,\r\n            'overestimated_pct': sum(1 for v in variances if v \u003C 0) \u002F len(variances) * 100,\r\n            'underestimated_pct': sum(1 for v in variances if v > 0) \u002F len(variances) * 100,\r\n            'by_category': category_accuracy\r\n        }\r\n\r\n    def suggest_adjustment_factors(self) -> Dict[str, float]:\r\n        \"\"\"Suggest adjustment factors based on historical variance.\"\"\"\r\n\r\n        factors = {}\r\n\r\n        for record in self._records:\r\n            category = record.work_item_code.split('-')[0] if '-' in record.work_item_code else 'Other'\r\n            if category not in factors:\r\n                factors[category] = []\r\n\r\n            if record.estimated_cost > 0:\r\n                actual_factor = record.actual_cost \u002F record.estimated_cost\r\n                factors[category].append(actual_factor)\r\n\r\n        return {\r\n            cat: round(np.mean(vals), 3)\r\n            for cat, vals in factors.items()\r\n            if len(vals) >= 3  # Require minimum data points\r\n        }\r\n\r\n    def compare_projects(self,\r\n                          project_ids: List[str] = None) -> pd.DataFrame:\r\n        \"\"\"Compare multiple projects.\"\"\"\r\n\r\n        if project_ids:\r\n            projects = [self._projects[pid] for pid in project_ids if pid in self._projects]\r\n        else:\r\n            projects = list(self._projects.values())\r\n\r\n        if not projects:\r\n            return pd.DataFrame()\r\n\r\n        return pd.DataFrame([\r\n            {\r\n                'Project ID': p.project_id,\r\n                'Project Name': p.project_name,\r\n                'Type': p.project_type,\r\n                'Location': p.location,\r\n                'Status': p.status.value,\r\n                'Estimated': p.estimated_total,\r\n                'Actual': p.actual_total,\r\n                'Variance': p.variance,\r\n                'Variance %': p.variance_percent,\r\n                'Items': p.item_count\r\n            }\r\n            for p in projects\r\n        ])\r\n\r\n    def get_benchmarks_by_type(self, project_type: str) -> Dict[str, Any]:\r\n        \"\"\"Get cost benchmarks for project type.\"\"\"\r\n\r\n        projects = [p for p in self._projects.values() if p.project_type == project_type]\r\n\r\n        if not projects:\r\n            return {}\r\n\r\n        actuals = [p.actual_total for p in projects if p.status == ProjectStatus.COMPLETED]\r\n\r\n        return {\r\n            'project_type': project_type,\r\n            'completed_projects': len(actuals),\r\n            'average_cost': round(np.mean(actuals), 2) if actuals else 0,\r\n            'min_cost': round(min(actuals), 2) if actuals else 0,\r\n            'max_cost': round(max(actuals), 2) if actuals else 0,\r\n            'average_variance': round(np.mean([p.variance_percent for p in projects]), 1)\r\n        }\r\n\r\n    def export_historical_data(self, output_path: str) -> str:\r\n        \"\"\"Export historical data to Excel.\"\"\"\r\n\r\n        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:\r\n            # Projects\r\n            if self._projects:\r\n                projects_df = self.compare_projects()\r\n                projects_df.to_excel(writer, sheet_name='Projects', index=False)\r\n\r\n            # Records\r\n            if self._records:\r\n                records_df = pd.DataFrame([\r\n                    {\r\n                        'Project': r.project_id,\r\n                        'Work Item': r.work_item_code,\r\n                        'Quantity': r.quantity,\r\n                        'Estimated': r.estimated_cost,\r\n                        'Actual': r.actual_cost,\r\n                        'Variance': r.variance,\r\n                        'Variance %': r.variance_percent,\r\n                        'Date': r.completion_date,\r\n                        'Notes': r.notes\r\n                    }\r\n                    for r in self._records\r\n                ])\r\n                records_df.to_excel(writer, sheet_name='Records', index=False)\r\n\r\n            # Accuracy metrics\r\n            metrics = self.get_accuracy_metrics()\r\n            if metrics:\r\n                metrics_df = pd.DataFrame([{\r\n                    'Total Records': metrics.get('total_records', 0),\r\n                    'Avg Variance %': metrics.get('average_variance_pct', 0),\r\n                    'Within 5%': f\"{metrics.get('within_5pct', 0):.1f}%\",\r\n                    'Within 10%': f\"{metrics.get('within_10pct', 0):.1f}%\"\r\n                }])\r\n                metrics_df.to_excel(writer, sheet_name='Accuracy', index=False)\r\n\r\n        return output_path\r\n\r\n    def save_database(self, filepath: str):\r\n        \"\"\"Save historical database to JSON.\"\"\"\r\n        data = {\r\n            'projects': {\r\n                pid: {\r\n                    'project_id': p.project_id,\r\n                    'project_name': p.project_name,\r\n                    'project_type': p.project_type,\r\n                    'location': p.location,\r\n                    'status': p.status.value,\r\n                    'estimated_total': p.estimated_total,\r\n                    'actual_total': p.actual_total,\r\n                    'start_date': p.start_date.isoformat(),\r\n                    'completion_date': p.completion_date.isoformat() if p.completion_date else None\r\n                }\r\n                for pid, p in self._projects.items()\r\n            },\r\n            'records': [\r\n                {\r\n                    'project_id': r.project_id,\r\n                    'work_item_code': r.work_item_code,\r\n                    'quantity': r.quantity,\r\n                    'estimated_cost': r.estimated_cost,\r\n                    'actual_cost': r.actual_cost,\r\n                    'completion_date': r.completion_date.isoformat(),\r\n                    'notes': r.notes\r\n                }\r\n                for r in self._records\r\n            ]\r\n        }\r\n\r\n        with open(filepath, 'w') as f:\r\n            json.dump(data, f, indent=2)\r\n```\r\n\r\n## Quick Start\r\n\r\n```python\r\nfrom datetime import date\r\n\r\n# Load CWICR data\r\ncwicr = pd.read_parquet(\"ddc_cwicr_en.parquet\")\r\n\r\n# Initialize tracker\r\ntracker = CWICRHistoricalCost(cwicr)\r\n\r\n# Add project\r\ntracker.add_project(\r\n    project_id=\"PROJ-001\",\r\n    project_name=\"Office Building A\",\r\n    project_type=\"commercial\",\r\n    location=\"New York\",\r\n    estimated_total=5000000,\r\n    start_date=date(2024, 1, 1)\r\n)\r\n\r\n# Record actual costs\r\ntracker.record_actual_cost(\r\n    project_id=\"PROJ-001\",\r\n    work_item_code=\"CONC-001\",\r\n    quantity=200,\r\n    actual_cost=32000,\r\n    notes=\"Slightly over due to overtime\"\r\n)\r\n```\r\n\r\n## Common Use Cases\r\n\r\n### 1. Accuracy Analysis\r\n```python\r\nmetrics = tracker.get_accuracy_metrics()\r\nprint(f\"Within 10%: {metrics['within_10pct']:.1f}%\")\r\n```\r\n\r\n### 2. Adjustment Factors\r\n```python\r\nfactors = tracker.suggest_adjustment_factors()\r\nfor cat, factor in factors.items():\r\n    print(f\"{cat}: {factor:.2f}x\")\r\n```\r\n\r\n### 3. Work Item History\r\n```python\r\nhistory = tracker.get_work_item_history(\"CONC-001\")\r\nprint(f\"Average variance: {history['average_variance_pct']}%\")\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.2 - Historical Cost Analysis\r\n",{"slug":5,"description":7,"display_name":33},"CWICR Historical Cost","main","e7e336ac628c3e3bd771aff1aaa469c93778f94a","skills\u002Fdatadrivenconstruction\u002Fcwicr-historical-cost",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":42,"prompt":52,"zipAvailable":53},[43,46,49],{"tool":44,"command":45},"npx","npx skills add kbarbel640-del\u002Fskills --skill cwicr-historical-cost",{"tool":47,"command":48},"bunx","bunx skills add kbarbel640-del\u002Fskills --skill cwicr-historical-cost",{"tool":50,"command":51},"pnpm","pnpm dlx skills add kbarbel640-del\u002Fskills --skill cwicr-historical-cost","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fcwicr-historical-cost\u002FSKILL.md",true,[55],{"path":56,"resourceType":57,"resourceTypeDesc":58,"sizeBytes":59,"sourceHtmlUrl":60},"_meta.json","REFERENCE","参考文档",310,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fcwicr-historical-cost\u002F_meta.json",[62,92,120,141,147,167],{"skillNo":63,"name":64,"nameZh":6,"description":65,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":66,"categories":67,"keywords":73,"publishedAt":28},"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",[68],{"categoryNo":69,"categoryName":70,"taxonomyType":71,"taxonomyTypeDesc":72},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[74,75,76,77,78,79,80,81,82,83,84,85,86,22,87,88,89,90,91],"crowd prompting","prompting","api","with","tokens","domain","world","prompts","operations","instructions","text","tool","system","productivity","marketplace","https","content","ai agents",{"skillNo":93,"name":94,"nameZh":6,"description":95,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":96,"categories":97,"keywords":103,"publishedAt":28},"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",[98],{"categoryNo":99,"categoryName":100,"taxonomyType":101,"taxonomyTypeDesc":102},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[104,76,105,23,106,107,108,109,110,111,112,113,114,115,116,117,118,81,119],"dilemm ai","arena","browser","openclaw agent","create","automation","browser automation","bot","openclaw","design","strategy","headless","compete","submit","matchmaking","use",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":129,"publishedAt":28},"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",[126],{"categoryNo":127,"categoryName":128,"taxonomyType":101,"taxonomyTypeDesc":102},"01JBSEEDCAT000000000000021","资料检索与研究",[130,131,132,133,134,135,136,77,137,117,119,138,76,139,140],"arxiv paper reviews","reviews","arxiv","paper","crawler","papers","comments","fetch","read","http","via",{"skillNo":142,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":146,"publishedAt":28},"01M6G8HQJ7N7WMY6YV7D7SSJ16","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Farxiv-paper-reviews\u002FSKILL.md",[145],{"categoryNo":127,"categoryName":128,"taxonomyType":101,"taxonomyTypeDesc":102},[133,132,131,130,140,135,136,77,134,117,119,137,138,76,139],{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":151,"categories":152,"keywords":153,"publishedAt":28},"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",[],[154,155,156,157,158,159,160,161,162,163,164,165,166],"git","summary","git summary","commits","repository","win32","status","linux","contributors","true","quick","get","branches",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":177,"publishedAt":28},"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",[173,174],{"categoryNo":99,"categoryName":100,"taxonomyType":101,"taxonomyTypeDesc":102},{"categoryNo":175,"categoryName":176,"taxonomyType":71,"taxonomyTypeDesc":72},"01JBSEEDCAT000000000000037","律师与法务",[178,179,180,181,77,182,183,34,184,138,185,186,187,188,189,89,190,191,192],"agent constitution","constitution","contracts","tree","query","base","log","check","Rules","projects","compliance","actions","state","governance","github"]