【问题标题】:Average between points based on time基于时间的点之间的平均值
【发布时间】:2020-10-09 05:29:27
【问题描述】:

我正在尝试使用 Python 来获取时间,以及在点之间移动的对象之间的平均速度。

数据看起来有点像这样,

location    initialtime id  speed distance
    1   2020-09-18T12:03:14.485952Z car_uno 72 9km
    2   2020-09-18T12:10:14.485952Z car_uno 83 8km
    3   2020-09-18T11:59:14.484781Z car_duo 70 9km
    7   2020-09-18T12:00:14.484653Z car_trio    85 8km
    8   2020-09-18T12:12:14.484653Z car_trio    70 7.5km

我目前使用的功能基本上是这样的,

Speeds.index = pd.to_datetime(Speeds.index)
..etc

现在,如果我通常这样做,我只会获取 id 的唯一值,

for x in speeds.id.unique():
    Speeds[speeds.id=="x"]...

但是这个方法真的不行。

简单地查看是否有多个 id 点随时间推移,然后取给定时间的平均速度的最佳方法是什么?否则,如果没有多个值,则只返回速度本身。

我可以使用更简单的 pandas 过滤器吗?

预期的输出很简单,

area - id - initial time - journey time - average speed.
关键是要获得经过两点的车辆的平均时间和行程时间

【问题讨论】:

  • 您可以从示例数据中添加预期输出吗?还是需要df.groupby('id').mean()
  • @jezrael groupby 是个好主意,哈哈!唯一的问题是,它需要考虑时间 - 我想知道我是否可以为此创建一个函数嗯
  • @LeCoda 我不太明白平均速度是什么意思,是汽车在不同区域和不同时间的平均速度吗?这样的平均值代表什么?
  • 如果汽车已经在两个点,那么平均速度,给定点之间所用的时间,以及每个点的速度
  • 您想加权给定 ID 的连续条目之间的 timedelta 平均值吗?

标签: python pandas


【解决方案1】:

要获得平均速度和行程时间,您可以使用groupby() 并传入确定完整行程的列,例如idarea

import pandas as pd
from io import StringIO

data = StringIO("""
area    initialtime id  speed
    1   2020-09-18T12:03:14.485952Z car_uno 72
    2   2020-09-18T12:10:14.485952Z car_uno 83
    3   2020-09-18T11:59:14.484781Z car_duo 70
    7   2020-09-18T12:00:14.484653Z car_trio    85
    8   2020-09-18T12:12:14.484653Z car_trio    70
""")

df = pd.read_csv(data, delim_whitespace=True)

df["initialtime"] = pd.to_datetime(df["initialtime"])

# change to ["id", "area"] if need more granular aggregation
group_cols = ["id"]

time = df.groupby(group_cols)["initialtime"].agg([max, min]).eval('max-min').reset_index(name="journey_time")

speed = df.groupby(group_cols)["speed"].mean().reset_index(name="average_speed")

pd.merge(time, speed, on=group_cols)

         id journey_time  average_speed
0   car_duo     00:00:00           70.0
1  car_trio     00:12:00           77.5
2   car_uno     00:07:00           77.5

【讨论】:

  • 区域很重要——一般来说,上面会起作用,因为汽车通常只有两点,但具体是在这两点之间时
  • 在这种情况下,只需将area 添加到groupby 即可。您的示例数据只有几行,因此聚合结果将与原始数据相同。
  • 谢谢 - 最后一点是,汽车也可能在城市的不同部分,因此可能会经过多个地方,因此聚合必须在一定程度上基于时间
  • 我仍然不能 100% 确定您想要的是什么。很高兴能提供进一步的帮助,但您能否提供更多示例代码和完整的预期输出,而不仅仅是输出标题。
【解决方案2】:

我尝试使用一个非常直观的解决方案。我假设数据已经加载到df

df['initialtime'] = pd.to_datetime(df['initialtime'])

result = []

for car in df['id'].unique():
    _df = df[df['id'] == car].sort_values('initialtime', ascending=True)

    #  Where the car is leaving "from" and where it's heading "to"
    _df['From'] = _df['location']
    _df['To'] = _df['location'].shift(-1, fill_value=_df['location'].iloc[0])

   #  Auxiliary columns
    _df['end_time'] = _df['initialtime'].shift(-1, fill_value=_df['initialtime'].iloc[0])
    _df['end_speed'] = _df['speed'].shift(-1, fill_value=_df['speed'].iloc[0])
   
    #  Desired columns
    _df['journey_time'] = _df['end_time'] - _df['initialtime']
    _df['avg_speed'] = (_df['speed'] + _df['end_speed']) / 2

    _df = _df[_df['journey_time'] >= pd.Timedelta(0)]
    _df.drop(['location', 'distance', 'speed', 'end_time', 'end_speed'], 
             axis=1, inplace=True)

    result.append(_df)

final_df = pd.concat(result).reset_index(drop=True)

最终的DataFrame如下:

                       initialtime        id  From  To    journey_time  avg_speed
0 2020-09-18 12:03:14.485952+00:00   car_uno     1   2 0 days 00:07:00       77.5
1 2020-09-18 11:59:14.484781+00:00   car_duo     3   3 0 days 00:00:00       70.0
2 2020-09-18 12:00:14.484653+00:00  car_trio     7   8 0 days 00:12:00       77.5

【讨论】:

    【解决方案3】:

    这是另一种方法。我的结果与其他帖子不同,所以我可能误解了要求。简而言之,我将每个平均速度计算为总距离除以总时间(对于每辆车)。

    from io import StringIO
    import pandas as pd
    
    # speed in km / hour; distance in km
    data = '''location    initial-time id  speed distance
    1   2020-09-18T12:03:14.485952Z car_uno 72 9
    2   2020-09-18T12:10:14.485952Z car_uno 83 8
    3   2020-09-18T11:59:14.484781Z car_duo 70 9
    7   2020-09-18T12:00:14.484653Z car_trio    85 8
    8   2020-09-18T12:12:14.484653Z car_trio    70 7.5
    '''
    

    现在创建数据框并执行计算

    # create data frame
    df = pd.read_csv(StringIO(data), delim_whitespace=True)
    df['elapsed-time'] = df['distance'] / df['speed'] # in hours
    
    # utility function
    def hours_to_hms(elapsed):
        ''' Convert `elapsed` (in hours) to hh:mm:ss (round to nearest sec)'''
        h, m = divmod(elapsed, 1)
        m *= 60
        _, s = divmod(m, 1)
        s *= 60
        hms = '{:02d}:{:02d}:{:02d}'.format(int(h), int(m), int(round(s, 0)))
        return hms
    
    # perform calculations
    start_time = df.groupby('id')['initial-time'].min()
    journey_hrs = df.groupby('id')['elapsed-time'].sum().rename('elapsed-hrs')
    hms = journey_hrs.apply(lambda x: hours_to_hms(x)).rename('hh:mm:ss')
    ave_speed = ((df.groupby('id')['distance'].sum() 
                 / df.groupby('id')['elapsed-time'].sum())
                 .rename('ave speed (km/hr)')
                 .round(2))
    
    # assemble results
    result = pd.concat([start_time, journey_hrs, hms, ave_speed], axis=1)
    
    print(result)
                             initial-time  elapsed-hrs  hh:mm:ss  \
    id                                                             
    car_duo   2020-09-18T11:59:14.484781Z     0.128571  00:07:43   
    car_trio  2020-09-18T12:00:14.484653Z     0.201261  00:12:05   
    car_uno   2020-09-18T12:03:14.485952Z     0.221386  00:13:17   
    
              ave speed (km/hr)  
    id                           
    car_duo               70.00  
    car_trio              77.01  
    car_uno               76.79  
    

    【讨论】:

      【解决方案4】:

      您应该提供更好的数据集(即具有相同时间点)以便我们更好地了解输入,并提供预期输出示例以便我们了解平均速度的计算。

      因此,如果 df 是包含您的输入数据的数据框,我只是猜测您可能正在寻找 df.groupby('initialtime')['speed'].mean()

      【讨论】:

      • 这应该是一条评论。你离 50 代表不远了。
      猜你喜欢
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 2018-02-17
      • 2012-12-04
      • 2023-03-10
      • 1970-01-01
      • 2020-07-12
      相关资源
      最近更新 更多