【问题标题】:Efficient way to loop through GroupBy DataFrame循环通过 GroupBy DataFrame 的有效方法
【发布时间】:2021-01-13 17:14:17
【问题描述】:

自从我上一篇文章确实缺乏信息:

我的 df 示例(重要的 col): deviceID:车辆的唯一 ID。车辆在 X 分钟内发送数据。 里程:自上一条消息以来移动的距离(以公里为单位) positon_timestamp_measure:数据集创建时间的unixTimestamp。

deviceID mileage positon_timestamp_measure
54672      10       1600696079
43423      20       1600696079
42342      3        1600701501
54672      3        1600702102
43423      2        1600702701

我的目标是通过使用时间戳和里程计算车辆的速度,将里程与车辆的最大速度(即 80 公里/小时)进行比较来验证里程。然后将结果写入原始数据集中。

到目前为止,我所做的如下:

df_ori['dataIndex'] = df_ori.index
df = df_ori.groupby('device_id')
#create new col and set all values to false
df_ori['valid'] = 0

for group_name, group in df:

    #sort group by time
    group = group.sort_values(by='position_timestamp_measure')
    group = group.reset_index()

    #since I can't validate the first point in the group, I set it to valid
    df_ori.loc[df_ori.index == group.dataIndex.values[0], 'validPosition'] = 1
    
    #iterate through each data in the group
    
    for i in range(1, len(group)):
        timeGoneSec = abs(group.position_timestamp_measure.values[i]-group.position_timestamp_measure.values[i-1])
        timeHours = (timeGoneSec/60)/60
        #calculate speed
        if((group.mileage.values[i]/timeHours)<maxSpeedKMH):
            df_ori.loc[dataset.index == group.dataIndex.values[i], 'validPosition'] = 1
            
            

dataset.validPosition.value_counts()

它确实按我想要的方式工作,但是它在性能方面缺乏很多。 df 包含近 700k 的数据(已清理)。我仍然是初学者,无法找到更好的解决方案。非常感谢您的帮助。

【问题讨论】:

    标签: python pandas dataframe loops pandas-groupby


    【解决方案1】:

    如果我做对了,这里就不需要 for 循环了。这是我将您的代码转换成的内容:

    df_ori['dataIndex'] = df_ori.index
    df = df_ori.groupby('device_id')
    #create new col and set all values to false
    df_ori['valid'] = 0
    
    df_ori = df_ori.sort_values(['position_timestamp_measure'])
    
    # Subtract preceding values from currnet value
    df_ori['timeGoneSec'] = \
        df_ori.groupby('device_id')['position_timestamp_measure'].transform('diff')
    
    
    # The operation above will produce NaN values for the first values in each group
    # fill the 'valid' with 1 according the original code
    df_ori[df_ori['timeGoneSec'].isna(), 'valid'] = 1
    
    df_ori['timeHours'] = df_ori['timeGoneSec']/3600   # 60*60 = 3600
    df_ori['flag'] = (df_ori['mileage'] / df_ori['timeHours']) <= maxSpeedKMH
    
    df_ori.loc[df_ori['flag'], 'valid'] = 1
    
    # Remove helper columns
    df_ori = df.drop(columns=['flag', 'timeHours', 'timeGoneSec'])
    
    

    基本思想是尽量使用向量化操作并避免 for 循环,通常是逐行迭代,这可能会非常慢。

    由于我无法获取您代码的上下文,请仔细检查逻辑并确保其按预期工作。

    【讨论】:

    • 非常感谢!但是我对以下行有疑问: df_ori['timeGoneSec'] = \ df_ori.groupby('device_id')['position_timestamp_measure'].transform('diff') 我认为你错过了一个括号,我不能退出遵循它背后的逻辑。
    • @YannickAaron 现在修复了丢失的右括号。而transform 应用了函数diff,它计算了一个序列中的两个连续值之间的差异(即value[i] - value[i-1]),它确保结果结果在我们groupby 之前具有精确的顺序,因此我们可以分配结果直接到原始数据框,而不会弄乱顺序。
    • 想通了!非常感谢!它按我的意愿工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-15
    • 2013-05-23
    • 2021-12-13
    • 2018-05-02
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    相关资源
    最近更新 更多