加入收藏 | 设为首页 | 会员中心 | 我要投稿 宜春站长网 (https://www.0795zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

还在抱怨Pandas运行速度慢?这几个方法会颠覆你的看法

发布时间:2018-12-20 15:16:11 所属栏目:教程 来源:知乎
导读:前言 当大家谈到数据分析时,提及最多的语言就是Python和SQL。Python之所以适合数据分析,是因为它有很多第三方强大的库来协助,pandas就是其中之一。pandas的文档中是这样描述的: 快速,灵活,富有表现力的数据结构,旨在使关系或标记数据的使用既简单又

1.61s,看上去挺快,但其实可以更快,我们来看一下下面的方法。

  1. >>> @timeit(repeat=3, number=100) 
  2. >>> def convert_with_format(df, column_name): 
  3. ...     return pd.to_datetime(df[column_name], 
  4. ...                           format='%d/%m/%y %H:%M') 
  5. Best of 3 trials with 100 function calls per trial: 
  6. Function `convert_with_format` ran in average of 0.032 seconds. 

结果只有0.032s,快了将近50倍。原因是:我们设置了转化的格式format。由于在CSV中的datetimes并不是 ISO 8601 格式的,如果不进行设置的话,那么pandas将使用 dateutil 包把每个字符串str转化成date日期。

相反,如果原始数据datetime已经是 ISO 8601 格式了,那么pandas就可以立即使用最快速的方法来解析日期。这也就是为什么提前设置好格式format可以提升这么多。

pandas数据的循环操作

仍然基于上面的数据,我们想添加一个新的特征,但这个新的特征是基于一些时间条件的,根据时长(小时)而变化,如下:

还在抱怨Pandas运行速度慢?这几个方法会颠覆你的看法

因此,按照我们正常的做法就是使用apply方法写一个函数,函数里面写好时间条件的逻辑代码。

  1. def apply_tariff(kwh, hour): 
  2.     """计算每个小时的电费"""     
  3.     if 0 <= hour < 7: 
  4.         rate = 12 
  5.     elif 7 <= hour < 17: 
  6.         rate = 20 
  7.     elif 17 <= hour < 24: 
  8.         rate = 28 
  9.     else: 
  10.         raise ValueError(f'Invalid hour: {hour}') 
  11.     return rate * kwh 

然后使用for循环来遍历df,根据apply函数逻辑添加新的特征,如下:

  1. >>> # 不赞同这种操作 
  2. >>> @timeit(repeat=3, number=100) 
  3. ... def apply_tariff_loop(df): 
  4. ...     """Calculate costs in loop.  Modifies `df` inplace.""" 
  5. ...     energy_cost_list = [] 
  6. ...     for i in range(len(df)): 
  7. ...         # 获取用电量和时间(小时) 
  8. ...         energy_used = df.iloc[i]['energy_kwh'] 
  9. ...         hour = df.iloc[i]['date_time'].hour 
  10. ...         energy_cost = apply_tariff(energy_used, hour) 
  11. ...         energy_cost_list.append(energy_cost) 
  12. ...     df['cost_cents'] = energy_cost_list 
  13. ...  
  14. >>> apply_tariff_loop(df) 
  15. Best of 3 trials with 100 function calls per trial: 
  16. 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秒钟。接下来,你将看到一些改进的Pandas结构迭代解决方案。

使用itertuples() 和iterrows() 循环

那么推荐做法是什么样的呢?

实际上可以通过pandas引入itertuples和iterrows方法可以使效率更快。这些都是一次产生一行的生成器方法,类似scrapy中使用的yield用法。

.itertuples为每一行产生一个namedtuple,并且行的索引值作为元组的第一个元素。nametuple是Python的collections模块中的一种数据结构,其行为类似于Python元组,但具有可通过属性查找访问的字段。

.iterrows为DataFrame中的每一行产生(index,series)这样的元组。

(编辑:宜春站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读