| name | cost-prediction |
| description | 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. |
Construction Cost Prediction with Machine Learning
Overview
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
Core Concepts
Historical Data → Feature Engineering → ML Model → Cost Prediction
│ │ │ │
▼ ▼ ▼ ▼
Past projects Prepare data Train model New project
with costs for ML on history cost forecast
Quick Start
import 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
df = pd.read_csv("historical_projects.csv")
X = df[['area_m2', 'floors', 'complexity_score']]
y = df['total_cost']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
model = LinearRegression()
model.fit(X_train, y_train)
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}")
new_project = [[5000, 10, 3]]
cost = model.predict(new_project)
print(f"Predicted cost: ${cost[0]:,.0f}")
Data Preparation
Prepare Historical Dataset
import pandas as pd
import numpy as np
def prepare_cost_dataset(df):
"""Prepare historical project data for ML"""
features = [
'area_m2',
'floors',
'building_type',
'location',
'year_completed',
'complexity_score',
'material_quality',
'total_cost'
]
df = df[features].copy()
df = df.dropna(subset=['total_cost'])
df['complexity_score'] = df['complexity_score'].fillna(df['complexity_score'].median())
df = pd.get_dummies(df, columns=['building_type', 'location'])
df['cost_per_m2'] = df['total_cost'] / df['area_m2']
df['cost_per_floor'] = df['total_cost'] / df['floors']
current_year = 2024
inflation_rate = 0.03
df['years_ago'] = current_year - df['year_completed']
df['adjusted_cost'] = df['total_cost'] * (1 + inflation_rate) ** df['years_ago']
return df
df = pd.read_csv()
df_prepared = prepare_cost_dataset(df)
Feature Engineering
def engineer_features(df):
"""Create additional features for better predictions"""
df['area_x_floors'] = df['area_m2'] * df['floors']
df['area_x_complexity'] = df['area_m2'] * df['complexity_score']
df['area_squared'] = df['area_m2'] ** 2
df['log_area'] = np.log1p(df['area_m2'])
df['size_category'] = pd.cut(
df['area_m2'],
bins=[0, 1000, 5000, 10000, float('inf')],
labels=['small', 'medium', 'large', 'xlarge']
)
return df
Machine Learning Models
Linear Regression
from 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)
coefficients = pd.DataFrame({
'feature': X_train.columns,
'coefficient': pipeline.named_steps['regressor'].coef_
}).sort_values('coefficient', key=abs, ascending=False)
return pipeline, coefficients
model, importance = train_linear_model(X_train, y_train)
print("Feature Importance:")
print(importance)
K-Nearest Neighbors (KNN)
from 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"""
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_train)
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
knn_model, scaler = train_knn_model(X_train, y_train)
Random Forest
from 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)
importance = pd.DataFrame({
'feature': X_train.columns,
'importance': rf.feature_importances_
}).sort_values('importance', ascending=False)
return rf, importance
rf_model, importance = train_random_forest(X_train, y_train)
print("Feature Importance:")
print(importance.head(10))
Gradient Boosting
from 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
gb_model = train_gradient_boosting(X_train, y_train)
Model Evaluation
Comprehensive Evaluation
from 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
metrics, predictions = evaluate_model(model, X_test, y_test, "Linear Regression")
Compare Multiple Models
def 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
models = {
'Linear Regression': linear_model,
'KNN': knn_model,
'Random Forest': rf_model,
'Gradient Boosting': gb_model
}
comparison = compare_models(models, X_test, y_test)
Cross-Validation
from 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
cv_scores = cross_validate_model(rf_model, X, y)
Prediction Pipeline
Complete Prediction Function
import 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
"""
df = pd.DataFrame([project_data])
for col in feature_names:
if col not in df.columns:
df[col] = 0
df = df[feature_names]
if scaler:
df = scaler.transform(df)
prediction = model.predict(df)[0]
confidence = 0.15
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
predictor = create_prediction_pipeline(rf_model, X.columns.tolist())
new_project = {
: ,
: ,
: ,
:
}
result = predictor(new_project)
()
()
Save and Load Model
import joblib
def save_model(model, filepath):
"""Save trained model to file"""
joblib.dump(model, filepath)
print(f"Model saved to {filepath}")
def load_model(filepath):
"""Load model from file"""
model = joblib.load(filepath)
print(f"Model loaded from {filepath}")
return model
save_model(rf_model, "cost_prediction_model.pkl")
loaded_model = load_model("cost_prediction_model.pkl")
Using with ChatGPT
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
"""
Quick Reference
| 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') |
Best Practices
- Data Quality: More historical data = better predictions
- Feature Selection: Include relevant project characteristics
- Inflation Adjustment: Normalize costs to current prices
- Regular Retraining: Update model with new completed projects
- Ensemble Methods: Combine multiple models for robustness
- Confidence Intervals: Always provide prediction ranges
Resources
Next Steps
- See
duration-prediction for project duration forecasting
- See
ml-model-builder for custom ML workflows
- See
kpi-dashboard for visualization
- See
big-data-analysis for large dataset processing