V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
kingmo888
V2EX  ›  Python

这一行 Python 代码,如何更快的提高运算速度?

  •  
  •   kingmo888 · 2017-05-13 21:39:25 +08:00 · 3603 次点击
    这是一个创建于 2784 天前的主题,其中的信息可能已经有所发展或是发生改变。

    end <str>:'2013-01-22'

    window <num>:10

    tmp_data = data[data['date']<=end].tail(window*251)

    上述代码要进行差不多 2000 次循环,这部分代码的执行时间占比高达 85%+,求问,如何提高这一行代码的执行速度?

    某单次统计数据(单位:秒):

    循环总耗时 :107.49908785695135

    该条代码耗时:100.13774995734286

    代码耗时占比:93.152%

    PS:

    1、试过随着循环缩减 data 前面的数据,结果更慢了。

    2、原本 index 为 datetime,无厘头的将 date 赋值到 index,运算结束,然后再将原 index 赋值回去。速度提升一倍左右。如下:

    循环总耗时 :45.289391494105644

    该条代码耗时:37.87854096882086

    代码耗时占比:83.637%

    第 1 条附言  ·  2017-05-13 23:09:09 +08:00
    忘记说了,data 差不多是 100 多万行,10 列。
    15 条回复    2017-05-16 21:38:10 +08:00
    O14
        1
    O14  
       2017-05-13 22:24:22 +08:00 via Android
    按 date 字段排序,二分查找 end 位置,直接向前 slice。
    代码不全不好说,建议先不用 Pandas,看看瓶颈在哪。
    EmdeBoas
        2
    EmdeBoas  
       2017-05-13 22:48:12 +08:00
    ...不会用 v2 的贴图..直接上代码了 5000 次循环秒出 <br>
    import datetime
    import numpy as np

    if __name__ == '__main__':
    array = np.array([])
    for i in xrange(5000):
    year = np.random.randint(100) + 2000
    month = np.random.randint(12) + 1
    day = np.random.randint(27) + 1
    array = np.append(array, datetime.datetime(year, month, day))
    end = datetime.datetime(2050, 5, 3)
    print array[array[:]>end][-5:]
    kingmo888
        3
    kingmo888  
    OP
       2017-05-13 23:09:23 +08:00
    @EmdeBoas 你好,数据有 100 多万行
    kingmo888
        4
    kingmo888  
    OP
       2017-05-13 23:21:17 +08:00
    @O14 感觉瓶颈就是 data 行数实在太大。
    @EmdeBoas 并且 date 字段为 str,如果转 np.array,然后查找到匹配的数据集后再转换为 str,中间的时间损耗很大。
    herozhang
        5
    herozhang  
       2017-05-13 23:23:56 +08:00 via iPhone
    并行?
    kingmo888
        6
    kingmo888  
    OP
       2017-05-13 23:25:20 +08:00
    @herozhang 这其实是并行中子函数的一部分了。所以并行不再考虑
    EmdeBoas
        7
    EmdeBoas  
       2017-05-13 23:34:49 +08:00   ❤️ 1
    ...我把数据量调到了 100W 然后试的
    In [8]: def test():
    ...: array = []
    ...: for i in xrange(1000000):
    ...: year = np.random.randint(100) + 2000
    ...: month = np.random.randint(12) + 1
    ...: day = np.random.randint(28) + 1
    ...: array.append(datetime.datetime(year, month, day))
    ...: narray = np.array(array)
    ...: flag = datetime.datetime(2015, 5, 3)
    ...: print narray[narray[:]<=flag][-5:]
    ...:

    In [9]: %timeit test()
    [datetime.datetime(2012, 12, 11, 0, 0) datetime.datetime(2009, 5, 26, 0, 0)
    datetime.datetime(2014, 6, 12, 0, 0) datetime.datetime(2008, 11, 23, 0, 0)
    datetime.datetime(2010, 12, 12, 0, 0)]
    [datetime.datetime(2009, 4, 8, 0, 0) datetime.datetime(2013, 2, 10, 0, 0)
    datetime.datetime(2008, 2, 4, 0, 0) datetime.datetime(2010, 11, 2, 0, 0)
    datetime.datetime(2005, 8, 27, 0, 0)]
    [datetime.datetime(2004, 6, 19, 0, 0) datetime.datetime(2010, 5, 7, 0, 0)
    datetime.datetime(2012, 5, 15, 0, 0) datetime.datetime(2012, 6, 7, 0, 0)
    datetime.datetime(2000, 1, 5, 0, 0)]
    [datetime.datetime(2014, 11, 6, 0, 0) datetime.datetime(2005, 9, 15, 0, 0)
    datetime.datetime(2008, 11, 5, 0, 0) datetime.datetime(2007, 6, 9, 0, 0)
    datetime.datetime(2003, 11, 10, 0, 0)]
    1 loop, best of 3: 4.18 s per loop
    kingmo888
        8
    kingmo888  
    OP
       2017-05-13 23:40:47 +08:00
    @EmdeBoas 已感谢,还是无法大幅解决我的问题(可能我技术渣渣,嘿嘿),但还是感谢。

    data 是 pandas 中的 DataFrame 格式数据,牵扯到一个 df 切片的问题。目前我做这样的尝试:

    循环之前,a=np.array(data['date'])
    循环中,
    b=a[a<=end]

    index=len(b)

    利用其行号来查找:
    tmp_data = data.loc[data.index[index-window*251:index],:]

    这样速度提升了 8 秒左右。全部循环完差不多 36s+。
    kingmo888
        9
    kingmo888  
    OP
       2017-05-13 23:44:13 +08:00
    @EmdeBoas 给梯子就爬一下下(捂脸。。)
    不知有否联系方式?我把数据发一份给您?您看能优化到多久的耗时?
    sagaxu
        10
    sagaxu  
       2017-05-13 23:56:13 +08:00 via Android
    数据贴网盘里,明天看看
    EmdeBoas
        11
    EmdeBoas  
       2017-05-13 23:59:51 +08:00   ❤️ 1
    老哥 你别老复杂化问题啊.....loc 和 iloc 要少用 效率很低的
    In [17]: def test():
    ...: array = []
    ...: other = []
    ...: for i in xrange(1000000):
    ...: [TAB]other.append(i)
    ...: [TAB]year = np.random.randint(100) + 2000
    ...: [TAB]month = np.random.randint(12) + 1
    ...: [TAB]day = np.random.randint(28) + 1
    ...: [TAB]array.append(datetime.datetime(year, month, day))
    ...: narray = np.array(array)
    ...: flag = datetime.datetime(2015, 5, 3)
    ...: df = pd.DataFrame()
    ...: df['date'] = narray
    ...: df['other'] = other
    ...: print df[narray[:]<=flag][-5:]
    ...:

    In [18]: %timeit test()
    date other
    999979 2006-07-05 999979
    999980 2012-09-19 999980
    999981 2010-05-13 999981
    999990 2007-10-14 999990
    999996 2008-10-19 999996
    date other
    999979 2002-08-01 999979
    999983 2001-10-01 999983
    999984 2007-04-05 999984
    999988 2014-04-21 999988
    999991 2008-01-06 999991
    date other
    999977 2004-05-04 999977
    999981 2004-05-05 999981
    999990 2003-10-04 999990
    999991 2003-03-28 999991
    999992 2002-12-09 999992
    date other
    999964 2006-12-13 999964
    999970 2012-07-07 999970
    999971 2009-12-15 999971
    999976 2004-07-22 999976
    999982 2009-11-14 999982
    1 loop, best of 3: 4.58 s per loop

    In [19]:
    EmdeBoas
        12
    EmdeBoas  
       2017-05-14 00:01:40 +08:00
    @kingmo888 (⊙﹏⊙)....我不是做 python 的( python 的并行库我都没用过) 只是做数模比赛做多了对 numpy 和 pandas 熟悉一点.... java 的 hadoop 我可能还能帮你看看...
    herozhang
        13
    herozhang  
       2017-05-15 14:58:09 +08:00
    100w 数据量,在我的 mbp 上跑:
    单核:
    7.87 s ± 175 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    并行 4 核:
    1.88 s ± 9.23 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    herozhang
        14
    herozhang  
       2017-05-15 15:00:16 +08:00
    要进一步加速,可以考虑用 pypy ?
    ruoyu0088
        15
    ruoyu0088  
       2017-05-16 21:38:10 +08:00
    两千次循环中什么是变量?循环中进行了哪些计算?

    对于你贴出来的那一行代码,下面的方法可能更快。

    data.take(np.where((data["date"] <= end).values)[-window*251:][0])
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5326 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 07:53 · PVG 15:53 · LAX 23:53 · JFK 02:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.