for是所有编程语言的基础语法,初学者为了快速实现功能,依懒性较强。但如果从运算时间性能上考虑可能不是特别好的选择。
本次东哥介绍几个常见的提速方法,一个比一个快,了解pandas本质,才能知道如何提速。
下面是一个例子,数据获取方式见文末。
- >>> import pandas as pd
- # 导入数据集
- >>> df = pd.read_csv('demand_profile.csv')
- >>> df.head()
- date_time energy_kwh
- 0 1/1/13 0:00 0.586
- 1 1/1/13 1:00 0.580
- 2 1/1/13 2:00 0.572
- 3 1/1/13 3:00 0.596
- 4 1/1/13 4:00 0.592
基于上面的数据,我们现在要增加一个新的特征,但这个新的特征是基于一些时间条件生成的,根据时长(小时)而变化,如下:
因此,如果你不知道如何提速,那正常第一想法可能就是用apply方法写一个函数,函数里面写好时间条件的逻辑代码。
- def apply_tariff(kwh, hour):
- """计算每个小时的电费"""
- if 0 <= hour < 7:
- rate = 12
- elif 7 <= hour < 17:
- rate = 20
- elif 17 <= hour < 24:
- rate = 28
- else:
- raise ValueError(f'Invalid hour: {hour}')
- return rate * kwh
然后使用for循环来遍历df,根据apply函数逻辑添加新的特征,如下:
- >>> # 不赞同这种操作
- >>> @timeit(repeat=3, number=100)
- … def apply_tariff_loop(df):
- … """用for循环计算enery cost,并添加到列表"""
- … energy_cost_list = []
- … for i in range(len(df)):
- … # 获取用电量和时间(小时)
- … energy_used = df.iloc[i]['energy_kwh']
- … hour = df.iloc[i]['date_time'].hour
- … energy_cost = apply_tariff(energy_used, hour)
- … energy_cost_list.append(energy_cost)
- … df['cost_cents'] = energy_cost_list
- …
- >>> apply_tariff_loop(df)
- Best of 3 trials with 100 function calls per trial:
- Function `apply_tariff_loop` ran in average of 3.152 seconds.
对于那些写Pythonic风格的人来说,这个设计看起来很自然。然而,这个循环将会严重影响效率。原因有几个:
首先,它需要初始化一个将记录输出的列表。
其次,它使用不透明对象范围(0,len(df))循环,然后再应用apply_tariff()之后,它必须将结果附加到用于创建新DataFrame列的列表中。另外,还使用df.iloc [i]['date_time']执行所谓的链式索引,这通常会导致意外的结果。
这种方法的最大问题是计算的时间成本。对于8760行数据,此循环花费了3秒钟。
接下来,一起看下优化的提速方案。