Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Predict construction project costs using Machine Learning. Use Linear Regression, K-Nearest Neighbors, and Random Forest models on historical project data. Train, evaluate, and deploy cost prediction models.
.claude/skills/datadrivenconstruction-cost-prediction/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 113% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 127% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 125% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 132% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 168% | 0% |
Based on DDC methodology (Chapter 4.5), this skill enables predicting construction project costs using historical data and machine learning algorithms. The approach transforms traditional expert-based estimation into data-driven prediction.
Book Reference: "Будущее: прогнозы и машинное обучение" / "Future: Predictions and Machine Learning"
> "Предсказания и прогнозы на основе исторических данных позволяют компаниям принимать более точные решения о стоимости и сроках проектов." > — DDC Book, Chapter 4.5
Historical Data → Feature Engineering → ML Model → Cost Prediction
│ │ │ │
▼ ▼ ▼ ▼
Past projects Prepare data Train model New project
with costs for ML on history cost forecastpythonimport pandas as pd from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, r2_score # Load historical project data df = pd.read_csv("historical_projects.csv") # Features and target X = df[['area_m2', 'floors', 'complexity_score']] y = df['total_cost'] # Split data X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) # Train model model = LinearRegression() model.fit(X_train, y_train) # Predict predictions = model.predict(X_test) print(f"R² Score: {r2_score(y_test, predictions):.2f}") print(f"MAE: ${mean_absolute_error(y_test, predictions):,.0f}") # Predict new project new_project = [[5000, 10, 3]] # area, floors, complexity cost = model.predict(new_project) print(f"Predicted cost: ${cost[0]:,.0f}")
pythonimport pandas as pd import numpy as np def prepare_cost_dataset(df): """Prepare historical project data for ML""" # Select relevant features features = [ 'area_m2', 'floors', 'building_type', 'location', 'year_completed', 'complexity_score', 'material_quality', 'total_cost' ] df = df[features].copy() # Handle missing values df = df.dropna(subset=['total_cost']) df['complexity_score'] = df['complexity_score'].fillna(df['complexity_score'].median()) # Encode categorical variables df = pd.get_dummies(df, columns=['building_type', 'location']) # Calculate derived features df['cost_per_m2'] = df['total_cost'] / df['area_m2'] df['cost_per_floor'] = df['total_cost'] / df['floors'] # Adjust for inflation (to current year prices) current_year = 2024 inflation_rate = 0.03 # 3% annual df['years_ago'] = current_year - df['year_completed'] df['adjusted_cost'] = df['total_cost'] * (1 + inflation_rate) ** df['years_ago'] return df # Usage df = pd.read_csv("projects_history.csv") df_prepared = prepare_cost_dataset(df)
pythondef engineer_features(df): """Create additional features for better predictions""" # Interaction features df['area_x_floors'] = df['area_m2'] * df['floors'] df['area_x_complexity'] = df['area_m2'] * df['complexity_score'] # Polynomial features df['area_squared'] = df['area_m2'] ** 2 # Log transforms (for skewed features) df['log_area'] = np.log1p(df['area_m2']) # Binned features df['size_category'] = pd.cut( df['area_m2'], bins=[0, 1000, 5000, 10000, float('inf')], labels=['small', 'medium', 'large', 'xlarge'] ) return df
pythonfrom sklearn.linear_model import LinearRegression from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline def train_linear_model(X_train, y_train): """Train Linear Regression model with scaling""" pipeline = Pipeline([ ('scaler', StandardScaler()), ('regressor', LinearRegression()) ]) pipeline.fit(X_train, y_train) # Feature importance (coefficients) coefficients = pd.DataFrame({ 'feature': X_train.columns, 'coefficient': pipeline.named_steps['regressor'].coef_ }).sort_values('coefficient', key=abs, ascending=False) return pipeline, coefficients # Usage model, importance = train_linear_model(X_train, y_train) print("Feature Importance:") print(importance)
pythonfrom sklearn.neighbors import KNeighborsRegressor from sklearn.preprocessing import StandardScaler from sklearn.model_selection import GridSearchCV def train_knn_model(X_train, y_train): """Train KNN model with optimal k""" # Scale features scaler = StandardScaler() X_scaled = scaler.fit_transform(X_train) # Find optimal k using cross-validation param_grid = {'n_neighbors': range(3, 20)} knn = KNeighborsRegressor() grid_search = GridSearchCV(knn, param_grid, cv=5, scoring='neg_mean_absolute_error') grid_search.fit(X_scaled, y_train) print(f"Best k: {grid_search.best_params_['n_neighbors']}") print(f"Best MAE: ${-grid_search.best_score_:,.0f}") return grid_search.best_estimator_, scaler # Usage knn_model, scaler = train_knn_model(X_train, y_train)
pythonfrom sklearn.ensemble import RandomForestRegressor def train_random_forest(X_train, y_train): """Train Random Forest model""" rf = RandomForestRegressor( n_estimators=100, max_depth=10, min_samples_split=5, random_state=42 ) rf.fit(X_train, y_train) # Feature importance importance = pd.DataFrame({ 'feature': X_train.columns, 'importance': rf.feature_importances_ }).sort_values('importance', ascending=False) return rf, importance # Usage rf_model, importance = train_random_forest(X_train, y_train) print("Feature Importance:") print(importance.head(10))
pythonfrom sklearn.ensemble import GradientBoostingRegressor def train_gradient_boosting(X_train, y_train): """Train Gradient Boosting model""" gb = GradientBoostingRegressor( n_estimators=200, learning_rate=0.1, max_depth=5, random_state=42 ) gb.fit(X_train, y_train) return gb # Usage gb_model = train_gradient_boosting(X_train, y_train)
pythonfrom sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np def evaluate_model(model, X_test, y_test, model_name="Model"): """Comprehensive model evaluation""" predictions = model.predict(X_test) metrics = { 'MAE': mean_absolute_error(y_test, predictions), 'RMSE': np.sqrt(mean_squared_error(y_test, predictions)), 'R²': r2_score(y_test, predictions), 'MAPE': np.mean(np.abs((y_test - predictions) / y_test)) * 100 } print(f"\n{model_name} Evaluation:") print(f" MAE: ${metrics['MAE']:,.0f}") print(f" RMSE: ${metrics['RMSE']:,.0f}") print(f" R²: {metrics['R²']:.3f}") print(f" MAPE: {metrics['MAPE']:.1f}%") return metrics, predictions # Usage metrics, predictions = evaluate_model(model, X_test, y_test, "Linear Regression")
pythondef compare_models(models, X_test, y_test): """Compare multiple models""" results = [] for name, model in models.items(): metrics, _ = evaluate_model(model, X_test, y_test, name) metrics['Model'] = name results.append(metrics) comparison = pd.DataFrame(results) comparison = comparison.set_index('Model') print("\nModel Comparison:") print(comparison.round(2)) return comparison # Usage models = { 'Linear Regression': linear_model, 'KNN': knn_model, 'Random Forest': rf_model, 'Gradient Boosting': gb_model } comparison = compare_models(models, X_test, y_test)
pythonfrom sklearn.model_selection import cross_val_score def cross_validate_model(model, X, y, cv=5): """Perform cross-validation""" scores = cross_val_score(model, X, y, cv=cv, scoring='neg_mean_absolute_error') mae_scores = -scores print(f"Cross-Validation MAE: ${mae_scores.mean():,.0f} (+/- ${mae_scores.std():,.0f})") return mae_scores # Usage cv_scores = cross_validate_model(rf_model, X, y)
pythonimport joblib def create_prediction_pipeline(model, feature_names, scaler=None): """Create a reusable prediction pipeline""" def predict_cost(project_data): """ Predict cost for new project Args: project_data: dict with project features Returns: Predicted cost and confidence interval """ # Create DataFrame from input df = pd.DataFrame([project_data]) # Ensure all required features for col in feature_names: if col not in df.columns: df[col] = 0 df = df[feature_names] # Scale if necessary if scaler: df = scaler.transform(df) # Predict prediction = model.predict(df)[0] # Confidence interval (simple estimation) confidence = 0.15 # 15% margin lower = prediction * (1 - confidence) upper = prediction * (1 + confidence) return { 'predicted_cost': prediction, 'lower_bound': lower, 'upper_bound': upper, 'confidence_level': f"{(1-confidence)*100:.0f}%" } return predict_cost # Usage predictor = create_prediction_pipeline(rf_model, X.columns.tolist()) # Predict new project new_project = { 'area_m2': 5000, 'floors': 8, 'complexity_score': 3, 'material_quality': 2 } result = predictor(new_project) print(f"Predicted Cost: ${result['predicted_cost']:,.0f}") print(f"Range: ${result['lower_bound']:,.0f} - ${result['upper_bound']:,.0f}")
pythonimport joblib # Save model def save_model(model, filepath): """Save trained model to file""" joblib.dump(model, filepath) print(f"Model saved to {filepath}") # Load model def load_model(filepath): """Load model from file""" model = joblib.load(filepath) print(f"Model loaded from {filepath}") return model # Usage save_model(rf_model, "cost_prediction_model.pkl") loaded_model = load_model("cost_prediction_model.pkl")
python# Prompt for ChatGPT to help with cost prediction prompt = """ I have historical construction project data with these columns: - area_m2: Building area in square meters - floors: Number of floors - building_type: residential, commercial, industrial - total_cost: Total project cost in USD Write Python code using scikit-learn to: 1. Prepare the data for machine learning 2. Train a Random Forest model 3. Evaluate the model 4. Predict cost for a new 3000 m² commercial building with 5 floors """
| Task | Code | |------|------| | Split data | train_test_split(X, y, test_size=0.2) | | Linear Regression | LinearRegression().fit(X, y) | | KNN | KNeighborsRegressor(n_neighbors=5) | | Random Forest | RandomForestRegressor(n_estimators=100) | | Predict | model.predict(X_new) | | MAE | mean_absolute_error(y_true, y_pred) | | R² Score | r2_score(y_true, y_pred) | | Cross-validate | cross_val_score(model, X, y, cv=5) | | Save model | joblib.dump(model, 'file.pkl') |
duration-prediction for project duration forecastingml-model-builder for custom ML workflowskpi-dashboard for visualizationbig-data-analysis for large dataset processing| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 21,271 | 13,107 | -38% | 1 | 1 | 0% | 4,462 | 6,263 | +40% | 0 | 0 | — |
case-02 | pass→pass | 11,932 | 8,879 | -26% | 1 | 1 | 0% | 2,236 | 5,189 | +132% | 0 | 0 | — |
case-03 | pass→pass | 11,480 | 11,451 | -0% | 1 | 1 | 0% | 2,118 | 5,675 | +168% | 0 | 0 | — |
case-04 | pass→pass | 11,349 | 6,897 | -39% | 1 | 1 | 0% | 2,030 | 4,720 | +133% | 0 | 0 | — |
case-05 | pass→pass | 12,242 | 9,457 | -23% | 1 | 1 | 0% | 2,166 | 5,243 | +142% | 0 | 0 | — |
case-06 | pass→pass | 14,304 | 10,606 | -26% | 1 | 1 | 0% | 2,410 | 5,443 | +126% | 0 | 0 | — |
case-07 | pass→pass | 14,802 | 11,463 | -23% | 1 | 1 | 0% | 2,716 | 5,686 | +109% | 0 | 0 | — |
case-08 | pass→pass | 15,383 | 11,737 | -24% | 1 | 1 | 0% | 2,718 | 5,717 | +110% | 0 | 0 | — |
case-09 | fail→pass | 15,472 | 11,048 | -29% | 1 | 1 | 0% | 2,602 | 5,546 | +113% | 0 | 0 | — |
case-10 | fail→fail | 12,822 | 10,001 | -22% | 1 | 1 | 0% | 2,222 | 5,514 | +148% | 0 | 0 | — |
case-11 | fail→fail | 14,730 | 12,073 | -18% | 1 | 1 | 0% | 2,657 | 5,751 | +116% | 0 | 0 | — |
case-12 | pass→pass | 13,246 | 8,326 | -37% | 1 | 1 | 0% | 2,319 | 5,193 | +124% | 0 | 0 | — |
case-13 | pass→pass | 4,449 | 4,049 | -9% | 1 | 1 | 0% | 712 | 4,252 | +497% | 0 | 0 | — |
case-14 | fail→fail | 16,261 | 14,932 | -8% | 1 | 1 | 0% | 2,791 | 6,308 | +126% | 0 | 0 | — |
case-15 | fail→pass | 15,589 | 11,627 | -25% | 1 | 1 | 0% | 2,509 | 5,706 | +127% | 0 | 0 | — |
case-16 | pass→pass | 11,577 | 6,043 | -48% | 1 | 1 | 0% | 2,195 | 4,665 | +113% | 0 | 0 | — |
case-17 | fail→pass | 16,493 | 13,108 | -21% | 1 | 1 | 0% | 2,751 | 6,194 | +125% | 0 | 0 | — |
case-18 | pass→pass | 12,730 | 13,535 | +6% | 1 | 1 | 0% | 2,296 | 6,022 | +162% | 0 | 0 | — |
case-19 | pass→pass | 13,723 | 14,862 | +8% | 1 | 1 | 0% | 2,815 | 6,628 | +135% | 0 | 0 | — |
case-20 | fail→fail | 21,235 | 27,125 | +28% | 1 | 1 | 0% | 4,262 | 9,350 | +119% | 0 | 0 | — |
case-21 | fail→fail | 25,869 | 25,360 | -2% | 1 | 1 | 0% | 5,363 | 9,222 | +72% | 0 | 0 | — |
case-22 | fail→fail | 26,013 | 28,103 | +8% | 1 | 1 | 0% | 5,758 | 9,687 | +68% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +14 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.