File size: 6,577 Bytes
300be5a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
import pandas as pd
import numpy as np
import random
from datetime import datetime, timedelta
import os
# Set random seed for reproducibility
np.random.seed(43)
def generate_vehicle_data(n_vehicles=10):
"""
Generate synthetic vehicle data for a delivery fleet optimization problem.
This function creates a realistic delivery fleet with various vehicle types,
capacities, and operational parameters to be used in route optimization.
Parameters:
-----------
n_vehicles : int, default=10
Number of vehicles to generate in the fleet
Returns:
--------
pd.DataFrame
DataFrame containing the generated vehicle data
"""
# Vehicle IDs
vehicle_ids = [f'VEH{str(i).zfill(3)}' for i in range(1, n_vehicles + 1)]
# Vehicle types
vehicle_types = []
for _ in range(n_vehicles):
vehicle_type = random.choices(['Standard', 'Large', 'Refrigerated'],
weights=[0.7, 0.2, 0.1])[0]
vehicle_types.append(vehicle_type)
# Vehicle capacities based on type
max_weights = []
max_volumes = []
for v_type in vehicle_types:
if v_type == 'Standard':
max_weights.append(random.uniform(800, 1200))
max_volumes.append(random.uniform(8, 12))
elif v_type == 'Large':
max_weights.append(random.uniform(1500, 2500))
max_volumes.append(random.uniform(15, 25))
else: # Refrigerated
max_weights.append(random.uniform(600, 1000))
max_volumes.append(random.uniform(6, 10))
# Realistic depot/warehouse locations in Singapore industrial areas
# [name, latitude, longitude]
warehouse_locations = [
["Tuas Logistics Hub", 1.3187, 103.6390],
["Jurong Industrial Estate", 1.3233, 103.6994],
["Loyang Industrial Park", 1.3602, 103.9761],
["Changi Logistics Centre", 1.3497, 103.9742],
["Keppel Distripark", 1.2706, 103.8219],
["Pandan Logistics Hub", 1.3187, 103.7509],
["Alexandra Distripark", 1.2744, 103.8012],
["Kallang Way Industrial", 1.3315, 103.8731],
["Defu Industrial Park", 1.3610, 103.8891],
["Woodlands Industrial", 1.4428, 103.7875]
]
# Assign warehouses to vehicles (multiple vehicles can be from same warehouse)
# Either assign sequentially to ensure all warehouses are used at least once (if n_vehicles >= len(warehouse_locations)),
# or randomly select from the list
depot_names = []
depot_lats = []
depot_lons = []
if n_vehicles <= len(warehouse_locations):
# Use first n_vehicles warehouses (one vehicle per warehouse)
selected_warehouses = warehouse_locations[:n_vehicles]
else:
# Ensure every warehouse is used at least once
selected_warehouses = warehouse_locations.copy()
# Then add random ones for remaining vehicles
remaining = n_vehicles - len(warehouse_locations)
selected_warehouses.extend([random.choice(warehouse_locations) for _ in range(remaining)])
# Shuffle to avoid sequential assignment
random.shuffle(selected_warehouses)
# Extract depot information
for warehouse in selected_warehouses:
depot_names.append(warehouse[0])
depot_lats.append(warehouse[1])
depot_lons.append(warehouse[2])
# Add small variation for vehicles from the same warehouse (within warehouse compound)
# This makes each vehicle's position slightly different, simulating different loading bays
for i in range(len(depot_lats)):
# Much smaller variation - within warehouse compound (approximately 50-100m variation)
depot_lats[i] += random.uniform(-0.0005, 0.0005)
depot_lons[i] += random.uniform(-0.0005, 0.0005)
# Driver names
first_names = ['Ahmad', 'Raj', 'Michael', 'Wei', 'Siti', 'Kumar', 'Chong', 'David', 'Suresh', 'Ali']
last_names = ['Tan', 'Singh', 'Lee', 'Wong', 'Kumar', 'Abdullah', 'Zhang', 'Lim', 'Raj', 'Teo']
driver_names = []
for i in range(n_vehicles):
if i < len(first_names):
driver_names.append(f"{first_names[i]} {random.choice(last_names)}")
else:
driver_names.append(f"{random.choice(first_names)} {random.choice(last_names)}")
# Vehicle availability
start_times = [f"{random.randint(7, 10):02d}:00" for _ in range(n_vehicles)]
end_times = [f"{random.randint(17, 21):02d}:00" for _ in range(n_vehicles)]
# Max working hours
max_working_hours = [random.randint(8, 10) for _ in range(n_vehicles)]
# Average speed (km/h)
avg_speeds = [random.uniform(30, 50) for _ in range(n_vehicles)]
# Cost per km
cost_per_km = [random.uniform(0.5, 1.5) for _ in range(n_vehicles)]
# Vehicle status
statuses = np.random.choice(['Available', 'In Service', 'Maintenance'], n_vehicles, p=[0.7, 0.2, 0.1])
# License plates (Singapore format)
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
license_plates = []
for _ in range(n_vehicles):
letter_part = ''.join(random.choices(letters, k=3))
number_part = random.randint(1000, 9999)
license_plates.append(f"S{letter_part}{number_part}")
# Create DataFrame
df = pd.DataFrame({
'vehicle_id': vehicle_ids,
'vehicle_type': vehicle_types,
'license_plate': license_plates,
'driver_name': driver_names,
'max_weight_kg': np.array(max_weights).round(2),
'max_volume_m3': np.array(max_volumes).round(2),
'depot_name': depot_names,
'depot_latitude': np.array(depot_lats).round(6),
'depot_longitude': np.array(depot_lons).round(6),
'start_time': start_times,
'end_time': end_times,
'max_working_hours': max_working_hours,
'avg_speed_kmh': np.array(avg_speeds).round(2),
'cost_per_km': np.array(cost_per_km).round(2),
'status': statuses
})
# Ensure the directory exists
data_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'data', 'vehicle-data')
os.makedirs(data_dir, exist_ok=True)
# Save to CSV
output_path = os.path.join(data_dir, 'vehicle_data.csv')
df.to_csv(output_path, index=False)
print(f"Vehicle data generated and saved to {output_path}")
return df
if __name__ == "__main__":
# Generate vehicle data
vehicle_data = generate_vehicle_data(10)
print("Sample of vehicle data:")
print(vehicle_data.head()) |