You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

共享单车项目空闲时间计算算法异常问题排查求助

共享单车空闲时间计算异常排查

我们正在开展一项高校项目,任务是优化共享单车的维修维护计划。单车仅能在停靠站点租借和归还,需计算空闲时间:单车x在站点y归还后,到该站点任意单车被租用的时间段。

我们的实现代码运行后出现部分异常结果(比如负空闲时间)。虽然已按start_time对DataFrame排序,但仍存在后续行交易的start_time早于之前交易的end_time的情况。原本需要在满足以下两个条件时更新空闲时间,但该逻辑未生效:

  • 待计算空闲时间的交易的end_station_id与当前循环交易的start_station_id一致;
  • 当前循环交易的start_time晚于待计算交易的end_time。

原实现代码

import pandas as pd
csv_file = '../Data_Cleanup/outCSV/Clean_Metro_Set.csv'
metro = pd.read_csv(csv_file)
metro['start_time'] = pd.to_datetime(metro['start_time'])
metro ['end_time'] = pd.to_datetime(metro['end_time'])
metro = metro.sort_values(by='start_time')
metro['idle_time'] = None

BigDict = {
    # station_id: {
    #     bike_id: (transaction_id ,end_time)
    # }
}

for i, row in metro.iterrows():
    current_start_time = row["start_time"]
    current_end_time = row["end_time"]
    current_end_station_id = row["end_station_id"]
    current_start_station_id = row["start_station_id"]
    current_bike_id = row["bike_id"]
    current_index = i

    if current_start_station_id in BigDict:
        for bike in list(BigDict[current_start_station_id]):  # Create a copy of the keys
            idle_time = current_start_time - BigDict[current_start_station_id][bike][1]
            metro.at[BigDict[current_start_station_id][bike][0], "idle_time"] = idle_time
            if idle_time.total_seconds() >= 0:
                del BigDict[current_start_station_id][bike]

    if current_end_station_id not in BigDict:
        BigDict[current_end_station_id] = {current_bike_id: (current_index, current_end_time)}

    BigDict[current_end_station_id][current_bike_id] = (current_index, current_end_time)

metro.to_csv('../Data_Cleanup/outCSV/Metro_Set_with_IdleTime.csv')

问题原因分析

  1. 时间判断逻辑顺序错误:原代码先计算所有该站点已归还单车的空闲时间并赋值,再判断时间是否合法。这就导致即使current_start_time早于单车的end_time(即空闲时间为负),也会把错误值写入idle_time字段。
  2. 无效覆盖操作:最后两行关于BigDict的更新逻辑冗余,虽不影响功能,但核心的时间校验时机错误,是异常值产生的直接原因。

修复后的代码

import pandas as pd
csv_file = '../Data_Cleanup/outCSV/Clean_Metro_Set.csv'
metro = pd.read_csv(csv_file)
metro['start_time'] = pd.to_datetime(metro['start_time'])
metro['end_time'] = pd.to_datetime(metro['end_time'])
metro = metro.sort_values(by='start_time')
metro['idle_time'] = None

# 结构:station_id -> {bike_id: (transaction_index, end_time)}
BigDict = {}

for i, row in metro.iterrows():
    current_start_time = row["start_time"]
    current_end_time = row["end_time"]
    current_end_station_id = row["end_station_id"]
    current_start_station_id = row["start_station_id"]
    current_bike_id = row["bike_id"]
    current_index = i

    # 处理当前租借站点的已归还单车
    if current_start_station_id in BigDict:
        # 遍历站点内的所有已归还单车
        for bike in list(BigDict[current_start_station_id].keys()):
            bike_end_time = BigDict[current_start_station_id][bike][1]
            # 先判断时间条件:当前租借时间晚于单车归还时间
            if current_start_time > bike_end_time:
                idle_time = current_start_time - bike_end_time
                # 仅满足条件时才更新空闲时间
                metro.at[BigDict[current_start_station_id][bike][0], "idle_time"] = idle_time
                # 移除已计算完成的单车记录
                del BigDict[current_start_station_id][bike]

    # 更新当前单车的归还记录到字典
    if current_end_station_id not in BigDict:
        BigDict[current_end_station_id] = {}
    BigDict[current_end_station_id][current_bike_id] = (current_index, current_end_time)

metro.to_csv('../Data_Cleanup/outCSV/Metro_Set_with_IdleTime.csv')

关键修改点

  • 调换时间判断与赋值顺序:先检查当前租借时间是否晚于单车归还时间,只有符合条件时才计算并写入空闲时间,彻底避免负数值的产生。
  • 保留未满足条件的记录:对于当前租借时间早于归还时间的单车,继续保留在BigDict中,等待后续时间更晚的租借交易来匹配计算。
  • 简化字典更新逻辑:将站点字典的初始化与单车记录更新合并,代码更简洁易读。

内容的提问来源于stack exchange,提问作者Yusuf Shehadeh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 06:35:03