在处理选定行时避免在 pandas 数据框中进行循环
Avoiding for loop in a pandas data frame when working on selected rows
我有一个 pandas
数据框 df
,每个 driver 都有 second-to-second 数据(经度、纬度等)。数据框由多个行程组成。有一个叫做Event_Type
的特性可以用来判断行程的开始和结束:
ignitionOnList = df[df['Event_Type'] == 'Ignition On'].index.tolist()
ignitionOffList = df[df['Event_Type'] == 'Ignition Off'].index.tolist()
所以,假设我在这个数据框中有 5 次旅行。 ignitionOnList
和 ignitionOffList
的长度为 5。我想专门对每次行程进行分析,并将它们存储在 pandas
数据框中。这是我的做法:
dfTrips = pd.DataFrame({'Date' : [],'Vehicle' : [], 'Trip_Number' : [], 'Start_Time' : [], 'Duration' : [],
'Collision': [],'Harsh_Steering' : [], 'Harsh_Deceleration' : [], 'Harsh_Acceleration' : [],
'Harsh_Preferred_Speed' : []})
tripCount = -1
tripNumbers = len(ignitionOnList)
for tripNumber in range(tripNumbers):
tripCount += 1
dfTemp = df.loc[ignitionOnList[tripNumber]:ignitionOffList[tripNumber]+1]
# Doing stuff to this temporary data frame and storing them, for example:
dfTrips.loc[tripCount,'Start_Time'] = dfTemp.loc[0,'Time'].strftime("%H:%M:%S")
dfTrips.loc[tripCount,'Finish_Time'] = dfTemp.loc[dfTemp.shape[0]-1,'Time'].strftime("%H:%M:%S")
# Using a function I have defined named `get_steering_risk` to get risky behaviour for each trip
dfTrips.loc[tripCount,'Harsh_Deceleration'] = get_deceleration_risk(dfTemp)
dfTrips.loc[tripCount,'Harsh_Steering'] = get_steering_risk(dfTemp)
这行得通。但我猜测在 Python 中有更好的方法可以在没有 for 循环的情况下执行此操作。我不确定我是否可以简单地使用 apply
因为我没有对整个数据框应用相同的函数。
另一种方法可能是重新定义函数,以便它们在 df
中生成一列
并将它们应用于整个数据框,然后汇总每次旅行的结果。例如,get_steering_risk
函数可以定义为 0
或 1
在 df
中的每一秒,然后每次行程的 1
的百分比将是Harsh_Steering
在 dfTrips
中。但是,某些功能无法应用于整个数据框。例如,一个函数对速度与加速度进行回归,它应该逐行完成。解决这个问题的最佳方法是什么?谢谢。
我怀疑任何性能问题实际上可能是由于您的成长方式造成的dfTrips
。我发现创建许多小的甚至单行(或单列)数据帧然后使用 pd.concat
将它们全部连接起来然后尝试逐行增长一个 df 的速度要快几个数量级行。
我问过类似的问题。查看接受的答案 concat
有多快。
[编辑]
这是为什么每次迭代都覆盖临时 df 并将其附加到列表中不起作用的说明(请参阅下面的评论):
df = pd.DataFrame(columns=np.arange(5))
df_list= []
for i in np.arange(5):
df.loc[0,:] = i
df_list.append(df)
for d in df_list:
print d
print
我不确定它是否会节省时间,但您可以(某种程度上)通过使用 groupby
来避免循环。首先,您将定义一个新列,比如 trip_number
,为每个唯一的旅行编制索引(这可能仍然涉及循环 tripNumbers)。然后按 trip_number
.
分组
您可以使用 apply
将单个函数分别应用于每个组。
最后,您将使用水平 concat
将它们连接到您的输出 df 中。
请参阅文档的“Felixble apply”部分。
grouped = df.groupby('trip_num')
decel_df = grouped.apply(get_deceleration_risk)
steer_df = grouped.apply(get_steering_risk)
...
dfTrips = pd.concat([decel_df, steer_df, ...], axis=1)
dfTrips.columns = ['Harsh_Deceleration', 'Harsh_Steering', ...]
我有一个 pandas
数据框 df
,每个 driver 都有 second-to-second 数据(经度、纬度等)。数据框由多个行程组成。有一个叫做Event_Type
的特性可以用来判断行程的开始和结束:
ignitionOnList = df[df['Event_Type'] == 'Ignition On'].index.tolist()
ignitionOffList = df[df['Event_Type'] == 'Ignition Off'].index.tolist()
所以,假设我在这个数据框中有 5 次旅行。 ignitionOnList
和 ignitionOffList
的长度为 5。我想专门对每次行程进行分析,并将它们存储在 pandas
数据框中。这是我的做法:
dfTrips = pd.DataFrame({'Date' : [],'Vehicle' : [], 'Trip_Number' : [], 'Start_Time' : [], 'Duration' : [],
'Collision': [],'Harsh_Steering' : [], 'Harsh_Deceleration' : [], 'Harsh_Acceleration' : [],
'Harsh_Preferred_Speed' : []})
tripCount = -1
tripNumbers = len(ignitionOnList)
for tripNumber in range(tripNumbers):
tripCount += 1
dfTemp = df.loc[ignitionOnList[tripNumber]:ignitionOffList[tripNumber]+1]
# Doing stuff to this temporary data frame and storing them, for example:
dfTrips.loc[tripCount,'Start_Time'] = dfTemp.loc[0,'Time'].strftime("%H:%M:%S")
dfTrips.loc[tripCount,'Finish_Time'] = dfTemp.loc[dfTemp.shape[0]-1,'Time'].strftime("%H:%M:%S")
# Using a function I have defined named `get_steering_risk` to get risky behaviour for each trip
dfTrips.loc[tripCount,'Harsh_Deceleration'] = get_deceleration_risk(dfTemp)
dfTrips.loc[tripCount,'Harsh_Steering'] = get_steering_risk(dfTemp)
这行得通。但我猜测在 Python 中有更好的方法可以在没有 for 循环的情况下执行此操作。我不确定我是否可以简单地使用 apply
因为我没有对整个数据框应用相同的函数。
另一种方法可能是重新定义函数,以便它们在 df
中生成一列
并将它们应用于整个数据框,然后汇总每次旅行的结果。例如,get_steering_risk
函数可以定义为 0
或 1
在 df
中的每一秒,然后每次行程的 1
的百分比将是Harsh_Steering
在 dfTrips
中。但是,某些功能无法应用于整个数据框。例如,一个函数对速度与加速度进行回归,它应该逐行完成。解决这个问题的最佳方法是什么?谢谢。
我怀疑任何性能问题实际上可能是由于您的成长方式造成的dfTrips
。我发现创建许多小的甚至单行(或单列)数据帧然后使用 pd.concat
将它们全部连接起来然后尝试逐行增长一个 df 的速度要快几个数量级行。
我问过类似的问题。查看接受的答案 concat
有多快。
[编辑] 这是为什么每次迭代都覆盖临时 df 并将其附加到列表中不起作用的说明(请参阅下面的评论):
df = pd.DataFrame(columns=np.arange(5))
df_list= []
for i in np.arange(5):
df.loc[0,:] = i
df_list.append(df)
for d in df_list:
print d
print
我不确定它是否会节省时间,但您可以(某种程度上)通过使用 groupby
来避免循环。首先,您将定义一个新列,比如 trip_number
,为每个唯一的旅行编制索引(这可能仍然涉及循环 tripNumbers)。然后按 trip_number
.
您可以使用 apply
将单个函数分别应用于每个组。
最后,您将使用水平 concat
将它们连接到您的输出 df 中。
请参阅文档的“Felixble apply”部分。
grouped = df.groupby('trip_num')
decel_df = grouped.apply(get_deceleration_risk)
steer_df = grouped.apply(get_steering_risk)
...
dfTrips = pd.concat([decel_df, steer_df, ...], axis=1)
dfTrips.columns = ['Harsh_Deceleration', 'Harsh_Steering', ...]