Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 处理选定行时避免数据帧中的for循环_Python_Loops_Pandas_Apply - Fatal编程技术网

Python 处理选定行时避免数据帧中的for循环

Python 处理选定行时避免数据帧中的for循环,python,loops,pandas,apply,Python,Loops,Pandas,Apply,我有一个pandas数据框,df,它为每个驾驶员提供每秒的数据(经度、纬度等)。数据帧由多个行程组成。有一种称为事件类型的功能,可用于确定行程的开始和结束: ignitionOnList = df[df['Event_Type'] == 'Ignition On'].index.tolist() ignitionOffList = df[df['Event_Type'] == 'Ignition Off'].index.tolist() 假设我在这个数据框中有5次旅行。IgnitionList

我有一个
pandas
数据框,
df
,它为每个驾驶员提供每秒的数据(经度、纬度等)。数据帧由多个行程组成。有一种称为
事件类型
的功能,可用于确定行程的开始和结束:

ignitionOnList = df[df['Event_Type'] == 'Ignition On'].index.tolist()
ignitionOffList = df[df['Event_Type'] == 'Ignition Off'].index.tolist()
假设我在这个数据框中有5次旅行。
IgnitionList
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\u steering\u risk
功能可以定义为在
df
中每秒使
0
1
,然后在
dfTrips
中,每次行程
1
s的百分比将是
Harsh\u steering
。但是,有些函数不能应用于整个数据帧。例如,一个函数将速度与加速度进行回归,并且应该一次一次地进行。最好的方法是什么?谢谢。

我怀疑任何性能问题实际上都可能是由于您不断增长的
dfTrips
造成的。我发现,创建许多小的、甚至是单行(或单列)数据帧,然后使用
pd.concat
将它们全部连接起来,然后尝试一行一行地增长一个df,速度要快几个数量级

我问了一个类似的问题。查看公认答案中的
concat
快了多少

[编辑] 下面是一个例子,说明了为什么每次迭代都覆盖临时df并将其附加到列表中是行不通的(请参阅下面的注释):


我不确定这是否会节省时间,但您可以(某种程度上)通过使用
groupby
来避免循环。首先,您需要定义一个新的列,例如
trip\u number
,以索引每个唯一的trip(这可能仍然需要在tripNumber上循环)。然后按行程编号分组

您可以使用
apply
将单个函数分别应用于每个组

最后,您将使用水平
concat
将它们连接到输出df中

请参阅文档的“”部分

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', ...]

您的二到二数据帧是否非常大?我经常发现,打开一次大的df,然后对小的临时df进行所有分析,就像在您的示例中一样,内存效率更高。此外,循环的读取端看起来效率也不是很低。进入dfTemp的每个行块只读取一次。@andrew
df
数据帧一点也不大。它来自一个2MB的csv文件。然而,我有数千个这样的文件需要输入到我的代码中,这就是为什么我要尽可能提高代码的效率。根据我下面的回答,我认为你会看到性能受到更坏的影响,因为一行一行地构建
dfTrips
,然后你会从循环中看到。Pandas
read_csv
解析器的速度也非常快。我不会担心I/O开销,这是有道理的。我要试一试。因此,在for循环的每一步中,我将定义
dfTripsStep=pd.DataFrame({})
,然后使用类似于
dfTripsStep.loc[0,'Start\u Time']='3:00'
的内容在for循环的每一步末尾,我将执行
dfTrips.append(dfTripsStep)
最后,在for循环之外,我将执行pd.concat(fTrips)
。在每个步骤中以这种方式制作这些1行
dfTripsStep
对您来说合理吗?或者可能有更好的方法来实现这一点?使用上述方法,传递13个文件的时间减少了
2.9%
,这很好,但没有太大意义。我假设如果我有更多的文件,并且
dfTrips
有更多的行,那么差异将更加显著。
dfTrips
是您版本中的列表吗?它不应该是一个df(有一个df.append方法,这很昂贵)。此外,我还将逐列增加
dfTripsStep
。我将编写一个助手来一次性初始化它:temp_dat=generate_measures(dfTemp)#生成所有度量值,长度与colsdfTripsStep=pd.DataFrame(data=temp_dat,columns=cols)如果您尝试此方法,请报告速度。我很好奇它是否有明显的不同。我尝试过这种方法,它是有效的。它比for循环稍微快一点。问题是我有13个文件,每个文件有5-6次行程。我想如果我在每个文件中有更多的行程,这个方法会明显更快。无论如何,这肯定是一种更干净的方法。谢谢,很有趣。我将不得不在较大的dfs上进行一些时间测试。谢谢你的回复
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', ...]