虽然.itertuples往往会更快一些,但是在这个例子中使用.iterrows,我们看看这使用iterrows后效果如何。
- >>> @timeit(repeat=3, number=100)
- ... def apply_tariff_iterrows(df):
- ... energy_cost_list = []
- ... for index, row in df.iterrows():
- ... # 获取用电量和时间(小时)
- ... energy_used = row['energy_kwh']
- ... hour = row['date_time'].hour
- ... # 添加cost列表
- ... energy_cost = apply_tariff(energy_used, hour)
- ... energy_cost_list.append(energy_cost)
- ... df['cost_cents'] = energy_cost_list
- ...
- >>> apply_tariff_iterrows(df)
- Best of 3 trials with 100 function calls per trial:
- Function `apply_tariff_iterrows` ran in average of 0.713 seconds.
语法方面:这样的语法更明确,并且行值引用中的混乱更少,因此它更具可读性。
在时间收益方面:快了近5倍! 但是,还有更多的改进空间。我们仍然在使用某种形式的Python for循环,,这意味着每个函数调用都是在Python中完成的,理想情况是它可以用Pandas内部架构中内置的更快的语言完成。
Pandas的 .apply()方法
我们可以使用.apply方法而不是.iterrows进一步改进此操作。Pandas的.apply方法接受函数(callables)并沿DataFrame的轴(所有行或所有列)应用它们。在此示例中,lambda函数将帮助你将两列数据传递给apply_tariff():
- >>> @timeit(repeat=3, number=100)
- ... def apply_tariff_withapply(df):
- ... df['cost_cents'] = df.apply(
- ... lambda row: apply_tariff(
- ... kwh=row['energy_kwh'],
- ... hour=row['date_time'].hour),
- ... axis=1)
- ...
- >>> apply_tariff_withapply(df)
- Best of 3 trials with 100 function calls per trial:
- Function `apply_tariff_withapply` ran in average of 0.272 seconds.
.apply的语法优点很明显,行数少,代码可读性高。在这种情况下,所花费的时间大约是.iterrows方法的一半。
但是,这还不是“非常快”。一个原因是.apply()将在内部尝试循环遍历Cython迭代器。但是在这种情况下,传递的lambda不是可以在Cython中处理的东西,因此它在Python中调用,因此并不是那么快。
如果你使用.apply()获取10年的小时数据,那么你将需要大约15分钟的处理时间。如果这个计算只是大型模型的一小部分,那么你真的应该加快速度。这也就是矢量化操作派上用场的地方。
矢量化操作:使用.isin()选择数据
什么是矢量化操作?如果你不基于一些条件,而是可以在一行代码中将所有电力消耗数据应用于该价格(df ['energy_kwh'] * 28),类似这种。这个特定的操作就是矢量化操作的一个例子,它是在Pandas中执行的最快方法。
但是如何将条件计算应用为Pandas中的矢量化运算?一个技巧是根据你的条件选择和分组DataFrame,然后对每个选定的组应用矢量化操作。 在下一个示例中,你将看到如何使用Pandas的.isin()方法选择行,然后在向量化操作中实现上面新特征的添加。在执行此操作之前,如果将date_time列设置为DataFrame的索引,则会使事情更方便:
- df.set_index('date_time', inplace=True)
-
- @timeit(repeat=3, number=100)
- def apply_tariff_isin(df):
- # 定义小时范围Boolean数组
- peak_hours = df.index.hour.isin(range(17, 24))
- shoulder_hours = df.index.hour.isin(range(7, 17))
- off_peak_hours = df.index.hour.isin(range(0, 7))
-
- # 使用上面的定义
- df.loc[peak_hours, 'cost_cents'] = df.loc[peak_hours, 'energy_kwh'] * 28
- df.loc[shoulder_hours,'cost_cents'] = df.loc[shoulder_hours, 'energy_kwh'] * 20
- df.loc[off_peak_hours,'cost_cents'] = df.loc[off_peak_hours, 'energy_kwh'] * 12
(编辑:源码网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|