Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 144 additions & 88 deletions ridepy/util/analytics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
TransportSpace,
)
from ridepy.events import VehicleStateEndEvent, VehicleStateBeginEvent
from ridepy.extras.io import create_params_json
from ridepy.util import make_sim_id


def _create_events_dataframe(events: Iterable[dict]) -> pd.DataFrame:
Expand Down Expand Up @@ -377,8 +379,8 @@ def _add_locations_to_stoplist_dataframe(*, reqs, stops, space) -> pd.DataFrame:
# this must be changed.
# See also [issue #45](https://github.com/PhysicsOfMobility/ridepy/issues/45)
locations.index = locations.index.set_levels(
locations.index.levels[1].map({"origin": 1.0, "destination": -1.0}),
1,
levels=locations.index.levels[1].map({"origin": 1.0, "destination": -1.0}),
level=1,
)

# finally fill the locations missing in the stops dataframe by joining on request_id and delta_occupancy
Expand Down Expand Up @@ -843,29 +845,29 @@ def get_vehicle_quantities(stops: pd.DataFrame, requests: pd.DataFrame) -> pd.Da
efficiency_dist = total_direct_dist / total_dist_driven
efficiency_time = total_direct_time / total_time_driven

avg_system_stoplist_length_service_time = stops.groupby("vehicle_id").apply(
lambda gdf: (
gdf["system_stoplist_length_service_time"] * gdf["state_duration"]
).sum()
/ gdf["state_duration"].sum()
)
avg_system_stoplist_length_submission_time = stops.groupby("vehicle_id").apply(
lambda gdf: (
gdf["system_stoplist_length_submission_time"] * gdf["state_duration"]
).sum()
/ gdf["state_duration"].sum()
)

avg_stoplist_length_service_time = stops.groupby("vehicle_id").apply(
lambda gdf: (gdf["stoplist_length_service_time"] * gdf["state_duration"]).sum()
/ gdf["state_duration"].sum()
)
avg_stoplist_length_submission_time = stops.groupby("vehicle_id").apply(
lambda gdf: (
gdf["stoplist_length_submission_time"] * gdf["state_duration"]
).sum()
/ gdf["state_duration"].sum()
)
# avg_system_stoplist_length_service_time = stops.groupby("vehicle_id").apply(
# lambda gdf: (
# gdf["system_stoplist_length_service_time"] * gdf["state_duration"]
# ).sum()
# / gdf["state_duration"].sum()
# )
# avg_system_stoplist_length_submission_time = stops.groupby("vehicle_id").apply(
# lambda gdf: (
# gdf["system_stoplist_length_submission_time"] * gdf["state_duration"]
# ).sum()
# / gdf["state_duration"].sum()
# )
#
# avg_stoplist_length_service_time = stops.groupby("vehicle_id").apply(
# lambda gdf: (gdf["stoplist_length_service_time"] * gdf["state_duration"]).sum()
# / gdf["state_duration"].sum()
# )
# avg_stoplist_length_submission_time = stops.groupby("vehicle_id").apply(
# lambda gdf: (
# gdf["stoplist_length_submission_time"] * gdf["state_duration"]
# ).sum()
# / gdf["state_duration"].sum()
# )

return pd.DataFrame(
dict(
Expand All @@ -880,10 +882,10 @@ def get_vehicle_quantities(stops: pd.DataFrame, requests: pd.DataFrame) -> pd.Da
total_direct_time=total_direct_time,
efficiency_dist=efficiency_dist,
efficiency_time=efficiency_time,
avg_system_stoplist_length_service_time=avg_system_stoplist_length_service_time,
avg_system_stoplist_length_submission_time=avg_system_stoplist_length_submission_time,
avg_stoplist_length_service_time=avg_stoplist_length_service_time,
avg_stoplist_length_submission_time=avg_stoplist_length_submission_time,
# avg_system_stoplist_length_service_time=avg_system_stoplist_length_service_time,
# avg_system_stoplist_length_submission_time=avg_system_stoplist_length_submission_time,
# avg_stoplist_length_service_time=avg_stoplist_length_service_time,
# avg_stoplist_length_submission_time=avg_stoplist_length_submission_time,
)
).rename_axis("vehicle_id")

Expand Down Expand Up @@ -915,7 +917,7 @@ def get_system_quantities(
- avg_stoplist_length_submission_time
- avg_waiting_time
- rejection_ratio
- median_stoplist_length
- avg_stoplist_length
- avg_detour
- (n_vehicles)
- (request_rate)
Expand Down Expand Up @@ -957,11 +959,16 @@ def get_system_quantities(

avg_segment_dist = stops["dist_to_next"].mean()
avg_segment_time = stops["time_to_next"].mean()
avg_segment_duration = stops["state_duration"].mean()
avg_idle_duration = (stops["state_duration"] - stops["time_to_next"]).mean()

total_dist_driven = stops["dist_to_next"].sum()
total_time_driven = stops["time_to_next"].sum()

avg_direct_dist = serviced_requests[("submitted", "direct_travel_distance")].mean()
avg_direct_dist_submitted = requests[("submitted", "direct_travel_distance")].mean()
avg_direct_dist_serviced = serviced_requests[
("submitted", "direct_travel_distance")
].mean()
avg_direct_time = serviced_requests[("submitted", "direct_travel_time")].mean()

total_direct_dist = serviced_requests[("submitted", "direct_travel_distance")].sum()
Expand All @@ -974,90 +981,139 @@ def get_system_quantities(

rejection_ratio = 1 - len(serviced_requests) / len(requests)

_stops = stops.dropna(
subset=(
"system_stoplist_length_service_time",
"system_stoplist_length_submission_time",
)
)
avg_system_stoplist_length_service_time = (
_stops["system_stoplist_length_service_time"] * _stops["state_duration"]
).sum() / _stops["state_duration"].sum()

avg_system_stoplist_length_submission_time = (
_stops["system_stoplist_length_submission_time"] * _stops["state_duration"]
).sum() / _stops["state_duration"].sum()

# not sure if it is necessary to do it again...
_stops = stops.dropna(
subset=("stoplist_length_service_time", "stoplist_length_submission_time")
)

avg_stoplist_length_submission_time = (
_stops["stoplist_length_submission_time"] * _stops["state_duration"]
).sum() / _stops["state_duration"].sum()

avg_stoplist_length_service_time = (
_stops["stoplist_length_service_time"] * _stops["state_duration"]
).sum() / _stops["state_duration"].sum()

stops["event_type"] = stops["delta_occupancy"].map({1.0: "pickup", -1.0: "dropoff"})
# _stops = stops.dropna(
# subset=(
# "system_stoplist_length_service_time",
# "system_stoplist_length_submission_time",
# )
# )
# avg_system_stoplist_length_service_time = (
# _stops["system_stoplist_length_service_time"] * _stops["state_duration"]
# ).sum() / _stops["state_duration"].sum()
#
# avg_system_stoplist_length_submission_time = (
# _stops["system_stoplist_length_submission_time"] * _stops["state_duration"]
# ).sum() / _stops["state_duration"].sum()
#
# # not sure if it is necessary to do it again...
# _stops = stops.dropna(
# subset=("stoplist_length_service_time", "stoplist_length_submission_time")
# )
#
# avg_stoplist_length_submission_time = (
# _stops["stoplist_length_submission_time"] * _stops["state_duration"]
# ).sum() / _stops["state_duration"].sum()
#
# avg_stoplist_length_service_time = (
# _stops["stoplist_length_service_time"] * _stops["state_duration"]
# ).sum() / _stops["state_duration"].sum()

submission_events = requests.loc[
:, [("submitted", "timestamp"), ("serviced", "vehicle_id")]
].dropna()

submission_events.columns = ["timestamp", "vehicle_id"]
submission_events = (
submission_events.reset_index()
submission_events.reset_index(drop=True)
.set_index(["vehicle_id", "timestamp"])
.assign(n_stops_delta=2)
)

stops = stops.copy()
stops["n_stops_delta"] = stops["delta_occupancy"].map({1.0: -1, -1.0: -1, 0.0: 0})

stop_events = (
stops[["timestamp", "n_stops_delta"]]
.reset_index("stop_id", drop=True)
.set_index("timestamp", append=True)
)

all_events = (
pd.concat(
[
submission_events,
stop_events,
],
axis="index",
)
.sort_index()
.assign(event_type="submission")
.squeeze()
)

event_log = pd.concat(
[
stops[["event_type", "request_id"]],
submission_events,
],
axis="index",
).sort_index()

median_stoplist_length = (
event_log["event_type"]
.map(dict(submission=2, pickup=-1, dropoff=-1))
.cumsum()
.median()
avg_stoplist_length = (
all_events.groupby("vehicle_id").cumsum().groupby("vehicle_id").mean().mean()
)
assert not avg_stoplist_length < 0

avg_detour = requests["inferred", "relative_travel_time"].mean()

res = dict(
total_system_time = (
stops.groupby("vehicle_id")
.apply(
lambda gdf: gdf.loc[gdf["request_id"] == -200, "timestamp"].item()
- gdf.loc[gdf["request_id"] == -100, "timestamp"].item()
)
.sum()
)
n_vehicles = len(stops.index.levels[0])
n_vehicles_used = (
requests.groupby(("serviced", "vehicle_id")).count().iloc[:, 0] > 0
).sum()
avg_request_rate_submitted = len(requests) / (total_system_time / n_vehicles)
avg_request_rate_serviced = len(serviced_requests) / (
total_system_time / n_vehicles
)

res = {}
if params:
theoretical_request_rate = params.get("request_generator", {}).get(
"rate", np.nan
)
velocity = params.get("general", {}).get("space").velocity
res |= dict(
n_vehicles=n_vehicles,
theoretical_request_rate=theoretical_request_rate,
max_pickup_delay=params.get("request_generator", {}).get(
"max_pickup_delay", np.nan
),
max_delivery_delay_rel=params.get("request_generator", {}).get(
"max_delivery_delay_rel", np.nan
),
velocity=velocity,
load_theoretical=(theoretical_request_rate * avg_direct_dist_submitted)
/ (velocity * n_vehicles),
seat_capacity=params.get("general", {}).get("seat_capacity", np.nan),
load_submitted=(avg_request_rate_submitted * avg_direct_dist_submitted)
/ (velocity * n_vehicles),
load_serviced=(avg_request_rate_serviced * avg_direct_dist_serviced)
/ (velocity * n_vehicles),
)

res |= dict(
avg_occupancy=avg_occupancy,
n_vehicles_used=n_vehicles_used,
avg_segment_dist=avg_segment_dist,
avg_segment_time=avg_segment_time,
avg_segment_duration=avg_segment_duration,
avg_idle_duration=avg_idle_duration,
total_dist_driven=total_dist_driven,
total_time_driven=total_time_driven,
avg_direct_dist=avg_direct_dist,
avg_direct_dist=avg_direct_dist_serviced,
avg_direct_time=avg_direct_time,
total_direct_dist=total_direct_dist,
total_direct_time=total_direct_time,
efficiency_dist=efficiency_dist,
efficiency_time=efficiency_time,
avg_system_stoplist_length_service_time=avg_system_stoplist_length_service_time,
avg_system_stoplist_length_submission_time=avg_system_stoplist_length_submission_time,
avg_stoplist_length_service_time=avg_stoplist_length_service_time,
avg_stoplist_length_submission_time=avg_stoplist_length_submission_time,
# avg_system_stoplist_length_service_time=avg_system_stoplist_length_service_time,
# avg_system_stoplist_length_submission_time=avg_system_stoplist_length_submission_time,
# avg_stoplist_length_service_time=avg_stoplist_length_service_time,
# avg_stoplist_length_submission_time=avg_stoplist_length_submission_time,
avg_waiting_time=avg_waiting_time,
rejection_ratio=rejection_ratio,
median_stoplist_length=median_stoplist_length,
avg_stoplist_length=avg_stoplist_length,
avg_detour=avg_detour,
avg_request_rate_submitted=avg_request_rate_submitted,
avg_request_rate_serviced=avg_request_rate_serviced,
)

if params:
res |= dict(
n_vehicles=params["general"]["n_vehicles"],
request_rate=params["request_generator"]["rate"],
velocity=params["general"]["space"].velocity,
)

return res
Loading