Pandas系列4-数据矢量化

作者: geekpy | 来源:发表于2018-06-21 19:51 被阅读89次

问题

我们在处理数据问题时,经常会遇到的问题是要将原有数据进行转化,比如在原有数据的基础上+1操作,或者将原有数据的字符串全部转化为小写字符,更复杂的是要将原有数据的一部分提取出来使用。这些问题都是数据转化问题,即原有的数据不能直接使用,而要进一步转化后才能使用。

示例

这里举一个笔者在实际项目中遇到的例子来说明。

笔者项目中需要收集的app version信息,原始信息如下:

In [167]: df
Out[167]:
        app_version  uid
0  7.23.1-180522122    1
1  7.20.1-180502135    2
2  7.23.1-180522122    3
3  7.23.1-180522122    4
4  7.16.7-180411077    5

但是实际上,我们只需要"-"之前的版本号,而且后续比较的时候要用'-'之前的数字进行比较,因此这样就涉及到了将原版本数据进行转化,即只提取'-'之前的数字,而舍弃后边的数字。

迭代

一个显而易见的做法是通过遍历的方式来逐行修改,如下图所示:

In [178]: %%timeit
     ...: for index, row in df.iterrows():
     ...:     df.iloc[index, 0] = row['app_version'].split('-')[0]
     ...:
2.34 ms ± 47.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [179]: df
Out[179]:
  app_version  uid
0      7.23.1    1
1      7.20.1    2
2      7.23.1    3
3      7.23.1    4
4      7.16.7    5

再进一步,我们可以使用apply方法,如下:

In [181]: df
Out[181]:
        app_version  uid
0  7.23.1-180522122    1
1  7.20.1-180502135    2
2  7.23.1-180522122    3
3  7.23.1-180522122    4
4  7.16.7-180411077    5

In [182]: %%timeit
     ...: df['app_version'] = df['app_version'].apply(lambda x: x.split('-')[0])
     ...:
247 µs ± 11.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [183]: df
Out[183]:
  app_version  uid
0      7.23.1    1
1      7.20.1    2
2      7.23.1    3
3      7.23.1    4
4      7.16.7    5

我们可以发现使用apply不仅使得代码更加简洁,而且速度也有了较明显的提升。但是以上方法本质上都是通过迭代的方式一条一条的修改,那么我们能否进一步提升性能呢?

矢量化

In [197]: df
Out[197]:
        app_version  uid
0  7.23.1-180522122    1
1  7.20.1-180502135    2
2  7.23.1-180522122    3
3  7.23.1-180522122    4
4  7.16.7-180411077    5

In [198]: %%timeit
     ...: df['app_version'] = df['app_version'].str.split('-').str.get(0)
     ...:
424 µs ± 11.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

这里发现矢量化貌似不能提高性能啊,这是为什么?

这里我猜测是由于我们的矢量化代码是分为两步操作,且在数据量较小的情况下就会显得慢

为了验证这个假设,我做了如下实验:
先将原数据concat为2560条记录,然后再计算时间

2557  7.23.1-180522122    3
2558  7.23.1-180522122    4
2559  7.16.7-180411077    5

[2560 rows x 2 columns]

In [232]: df3 = df

In [233]: %%timeit
     ...: df['app_version'] = df['app_version'].apply(lambda x: x.split('-')[0])
     ...:
1.36 ms ± 35.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# 矢量化方式
In [250]: %%timeit
     ...: df['app_version'] = df['app_version'].str.split("-").str.get(0)
     ...:
2.61 ms ± 113 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

发现单纯的数据量增大并没有影响结果,那么用其它转化来测试下,这里获取字符串长度的转化进行实验

In [253]: %%timeit
     ...: df['length'] = df['app_version'].str.len()
     ...:
901 µs ± 17.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [254]: %%timeit
     ...: df3['length'] = df3['app_version'].apply(lambda x: len(x))
     ...:
     ...:
1.16 ms ± 14.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

我们看到在这里就体现出了矢量化的优势,因为这里大家都是一步。

结论:当矢量化步数只有一步时,其性能还是要比apply方式好的,但当需要多步的时候,不一定好于apply方式。

那么,我们能否将其转化为一步呢?后发现有extract这样的函数,使用如下:

In [312]: df
Out[312]:
        app_version  uid
0  7.23.1-180522122    1
1  7.20.1-180502135    2
2  7.23.1-180522122    3
3  7.23.1-180522122    4
4  7.16.7-180411077    5

In [313]: %%timeit
     ...: df['app_version'] = df['app_version'].str.extract(r"([0-9\.]+)-[0-9]+", expand=Fal
     ...: se)
     ...:
247 µs ± 8.95 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

通过extract终于实现了一步的矢量化。而且性能上也是最优的。

这里需要注意的是,如果使用timeit, 由于多次操作,会导致后续df中'app_version'的值变为NaN。当我们只操作一次的时候则不存在此问题。

References

相关文章

  • Pandas系列4-数据矢量化

    问题 我们在处理数据问题时,经常会遇到的问题是要将原有数据进行转化,比如在原有数据的基础上+1操作,或者将原有数据...

  • Pandas 系列之Series类型数据

    Pandas 系列之Series类型数据 本文开始正式写Pandas的系列文章,就从:如何在Pandas中创建数据...

  • Pandas-2019-03-14

    Pandas Pandas 介绍 Pandas主要处理的数据结构 ·系列(Series)·数据帧(DataFram...

  • 你在Pandas中使用Apply吗?有一个更快600倍的方法

    你在Pandas中使用Apply吗?有一个更快600倍的方法通过利用矢量化和数据类型,你可以大规模地加快Panda...

  • pandas使用技巧系列总览

    数据分析 | pandas | python 简介:本系列教程主要讲解了数据分析库pandas的使用方法,内容参考...

  • 记录21个Pandas技巧

    介绍 Pandas是一个易于使用且功能强大的数据库分析库。与NumPy一样,它可以矢量化大多数基本操作,即使在CP...

  • Python-pandas库 -上篇

    1、导入panda库 2、创建系列 3、索引系列 4、创建数据帧 5、索引数据帧 6、操作数据帧 7、pandas...

  • Pandas 01 数据结构

    一、数据结构 Pandas的三种数据结构: 系列(Series) 数据帧(DataFrame) 面板(Panel)...

  • pandas常用操作

    pandas读取数据: pandas查看数据: pandas删除行、列: pandas排序: pandas合并列表...

  • Pandas中选择数据的子集 第二部分

    在Pandas中选择数据的子集 第二部分第二部分:布尔索引这是关于如何从pandas数据框架或系列中选择数据子集的...

网友评论

本文标题:Pandas系列4-数据矢量化

本文链接:https://www.haomeiwen.com/subject/nobcyftx.html