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
jianghu52
V2EX  ›  Python

是我太菜了,还是 pandans 就是这么慢

  •  
  •   jianghu52 · 2024-06-06 22:00:36 +08:00 · 4785 次点击
    这是一个创建于 375 天前的主题,其中的信息可能已经有所发展或是发生改变。

    thinkpad T14 的机器,i7 的 cup ,32G 内存。 我有两个 excel ,一个 4 千行,6 列 名字叫 tb4k ,一个 6 千行,10 列,名字叫 tb6k 。 都用 pandas 接成 df 对象,然后循环两个 df 。最后保存成 excel 。

    伪代码 遍历 tb4k 的每一行,取前三列的内容: 遍历 tb6k: tb6k 的前三列一致: 将 tb6k 的后面第 5,8,10 行的内容赋值给 tb4k 的后三列 停止遍历 tb6k 保存 tb4k 到原 excel

    我执行段代码。tb4k 遍历每一行大概需要 1s 左右(包含 tb6k 的遍历)。导致我运行这段程序要接近 1 小时。 这速度也太慢了吧。还是我水平太菜了,没有用好 pandas ?

    41 条回复    2024-06-08 08:15:10 +08:00
    shinonome
        1
    shinonome  
       2024-06-06 22:40:42 +08:00
    4 千还是 4 千万呢,感觉你这数据量基本上是几秒就结束的吧,

    我还是怀疑代码问题

    Python 虽然慢,那也是相对而言的,对人来说应该是没有明显感知的
    yagamil
        2
    yagamil  
       2024-06-06 23:04:00 +08:00   ❤️ 3
    太菜。鉴定完毕。
    xgdgsc
        3
    xgdgsc  
       2024-06-06 23:13:52 +08:00
    按行循环应该考虑用 julia , io 可以调 python 完成 https://github.com/JuliaPy/PythonCall.jl ,数据处理部分用 julia 无脑循环
    jayeli
        4
    jayeli  
       2024-06-07 01:36:48 +08:00
    为什么不 merge 呢?
    Lycnir
        5
    Lycnir  
       2024-06-07 09:04:15 +08:00
    可以把代码发出来瞧瞧~
    wang93wei
        6
    wang93wei  
       2024-06-07 09:07:34 +08:00   ❤️ 1
    换成 polars 再试试,如果 polars 也慢说明你代码写的有问题。
    hackhu2019
        7
    hackhu2019  
       2024-06-07 09:07:58 +08:00   ❤️ 1
    df 对象每次迭代生成的对象开销很大,多半是你迭代的方法不对可以看看这个 https://stackoverflow.com/questions/16476924/how-can-i-iterate-over-rows-in-a-pandas-dataframe
    l1xnan
        8
    l1xnan  
       2024-06-07 09:12:35 +08:00
    哪怕自己调 Excel 包写循环也不会这么慢吧,想起来那些 Python 新手声称遇到 Python BUG 在网上提问的
    yy77
        9
    yy77  
       2024-06-07 09:20:59 +08:00   ❤️ 1
    Excel 的处理本来就是比较慢的。如果格式不重要的话,转成 csv 再用 pandas 处理,速度能上一个数量级。
    crackidz
        10
    crackidz  
       2024-06-07 09:27:38 +08:00
    你这速度明显是使用问题了...
    1462326016
        11
    1462326016  
       2024-06-07 10:30:52 +08:00
    每次循环都要重新遍历六千次,不可能快吧。把六千行那个 excel 的前三列和需要的数据做成 dict ,直接遍历四千行的那个 get 一下 dict ,一次完事,复杂度 O(1)
    算下来都不需要 pandas 吧,如果不会用 excel 读写相关库当我没说,好像好多人习惯用 pandas 读取 excel 。
    我习惯用 openpyxl 之类的读取 excel
    aka863
        12
    aka863  
       2024-06-07 10:52:20 +08:00
    建议使用 pandas.DataFrame.set_index(),把 DataFrame 的前 3 列设置为 MultiIndex ,再使用 pandas.DataFrame.join()。
    gauthier
        13
    gauthier  
       2024-06-07 10:55:32 +08:00
    你这数据量理论上应该是秒算完,就算是导出成 excel 也不会花太久。用 cProfile 看看时间耗费在哪了,找找有没有 pandas 自己的 api 调用
    aka863
        14
    aka863  
       2024-06-07 10:57:54 +08:00
    不建议用逐行遍历、比较的方法,
    那样的话,还不如在循环中用 python 的字典数据。
    sgld
        15
    sgld  
       2024-06-07 12:22:18 +08:00 via Android
    大概率代码问题,问题描述其实没太看明白,但是 pandas 中逐行遍历是效率最低的一种做法。可以考虑能不能使用矢量化的方法替代,没有代码也不清楚。

    stackoverflow 中有很多这方面的回答,可以去看看。
    sgld
        16
    sgld  
       2024-06-07 12:30:26 +08:00 via Android
    问题中提到 tb6k 后面第 5 8 10 行的内容赋值给 tb4k 后三列。这里是不是 5 8 10 列

    打错了的话,就两个表格 join 一下(前面有回答提到了),然后使用索引取需要的列。

    如果不是别无他法,遍历都是最次选,实在不行考虑 aplly 这些🤩
    sgld
        17
    sgld  
       2024-06-07 12:31:09 +08:00 via Android
    @sgld apply
    G64q9J89mN5KSgmE
        18
    G64q9J89mN5KSgmE  
       2024-06-07 12:33:13 +08:00   ❤️ 1
    打了一堆又删了
    你还是让 gpt 帮你写吧
    ipwx
        19
    ipwx  
       2024-06-07 12:38:33 +08:00   ❤️ 1
    你代码呢?

    首先,python 不能用 for loop 。

    其次,pandas 稍微一点细节,性能差别就很大。比如

    * .loc 或者直接索引比 .iloc 慢很多。
    * .iteritems() 可能比 .itertuples() 慢。
    * 不要按行取数据,因为 Pandas 是按列存的。你取出一行就有一行的临时对象。
    ipwx
        20
    ipwx  
       2024-06-07 12:39:46 +08:00
    实践中我千万级别的数据处理,很多操作也就 10 秒。

    每天 600 多万行的 1 分钟 A 股数据,按每只股票聚合成 5, 10, 15, 30 分钟也就 20 秒。
    ipwx
        21
    ipwx  
       2024-06-07 12:40:20 +08:00
    说错了 100 多万行的 1 分钟数据。
    Sawyerhou
        22
    Sawyerhou  
       2024-06-07 12:41:05 +08:00   ❤️ 1
    加 3 个辅助列 tb6k shift -5,-8,-10 ,将 tb4k 和 tb6k 的前 3 列设为 multiIndex ,然后 loc 拼接。
    目测你这个前三列应该没重复的,如果有,如楼上说用 join 替代 loc 。

    不要循环,用矩阵运算,1s 都用不了。
    datou06415
        23
    datou06415  
       2024-06-07 13:07:49 +08:00
    6 千行的数据的话,以你的机器配置,直接用 DataFrame 的 read_excel() 把 excel 数据读进来再处理都行,避免一行行的读文件。如果文件非常多行,再考虑分批次处理。

    想知道运行慢的具体原因,上 cProfile ,或者粗暴点,日志记录关键操作位置的起始时间。总之,性能调优,先上工具测量指标。
    cogitoxin
        24
    cogitoxin  
       2024-06-07 13:44:25 +08:00
    polars 你值得拥有
    Rorysky
        25
    Rorysky  
       2024-06-07 14:05:43 +08:00
    都放内存里,哪儿来这么多的时间
    jZEdn7k4
        26
    jZEdn7k4  
       2024-06-07 14:08:49 +08:00
    这个速度真是你代码太菜的问题。。。
    dbak
        27
    dbak  
       2024-06-07 14:11:01 +08:00
    pandas 有矢量化操作矩阵数据 你小子用的 for 循环吧
    zealotxxxx
        28
    zealotxxxx  
       2024-06-07 14:28:17 +08:00
    只能说是太菜,如果不是学习,你的需求建议用 excel

    另外,你 tb4k 直接走 df.loc 或者 ilock 都行,如果你用 loop 也只需要执行 4k 次。

    但是你如果数据唯一,完全可以走 join ,然后直接取要拿的列就行了
    zealotxxxx
        29
    zealotxxxx  
       2024-06-07 14:30:22 +08:00
    你不会是嵌套 loop 吧?

    4000 * 6000 = 2400 万次? 那不慢才怪
    psyer
        30
    psyer  
       2024-06-07 14:32:46 +08:00 via Android
    看下代码呢
    weidaizi
        31
    weidaizi  
       2024-06-07 14:52:44 +08:00
    看了一下,这慢很正常呀,帮大家格式化一下楼主的伪代码:
    ```
    for _, row_tb4k in df_tb4k.iterrows():
    for _, row_tb6k in df_tb6k.iterrows():
    if row_tb4k["c1"] == row_tb6k["c1"] and row_tb4k["c2"] == row_tb6k["c2"] and row_tb4k["c3"] == row_tb6k["c3"]:
    row_tb4k["c4“] = row_tb6k["c5"]
    row_tb4k["c5“] = row_tb6k["c8"]
    row_tb4k["c6“] = row_tb6k["c10"]
    ```

    * 首先,都用了 pandas 了,为啥手动遍历来合并?
    * 其次,即使徒手写,也需要建个索引来做呀,你这时间复杂度是 O(n^2) 了
    weidaizi
        32
    weidaizi  
       2024-06-07 14:56:56 +08:00
    @weidaizi = = 我晕,前面的空格没了
    encro
        33
    encro  
       2024-06-07 15:03:56 +08:00
    我用 pandas 计算 k 线指标,1 万跟 k 线,几十个指标也只要几秒钟。估计你用的 pandans 和我用的 pandas 不是一个东西。
    billbur
        34
    billbur  
       2024-06-07 15:05:50 +08:00
    djangovcps
        35
    djangovcps  
       2024-06-07 15:22:09 +08:00
    感觉你笛卡尔积的循环了,要不嗯循环几千行不肯能一小时
    kingbill
        36
    kingbill  
       2024-06-07 15:34:35 +08:00
    我觉得是 T14 的锅,是 U 结尾的 i7 吗?
    stiangao
        37
    stiangao  
       2024-06-07 16:47:57 +08:00
    前三列一样就合并一行的内容吧,

    按你的思路要遍历 4000*6000=2400w 次,那确实慢,

    按这个方法写,遍历一次 6000 行,前三列拼一个 key, 后三列拼 value ,生成一个 dict,
    遍历 4000 行的文件,从 dict 里查, 查到了就拼接,
    总共遍历数据 1w 次
    winglight2016
        38
    winglight2016  
       2024-06-07 16:51:40 +08:00
    太菜了,pandas 用成了 array

    另外,两个单词都拼错了,看着难受┑( ̄Д  ̄)┍
    henix
        39
    henix  
       2024-06-07 17:42:44 +08:00   ❤️ 1
    遍历 6000 行的 df 需要 1s 也太慢。你用没用 df.iterrows 遍历? iterrows 跟整数索引( for i in range(len(df)))的性能差别挺大的。
    一点建议:为啥非要用 excel 和 pandas ?因为 excel 不是文本格式,不方便程序处理。pandas 个人认为对初学者来说有很多坑。
    一个架构上的建议:先将你这两个 excel 另存为 csv 格式,然后用 Python 自带的 https://docs.python.org/zh-cn/3/library/csv.html 把每个文件读进来存成一个 list ,算法跟你现在的保持不变,说不定都比你现在的方式快。
    Laysan
        40
    Laysan  
       2024-06-07 21:50:50 +08:00
    show your code
    usiantein
        41
    usiantein  
       2024-06-08 08:15:10 +08:00
    talk is annoying, show your code
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1424 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 16:55 · PVG 00:55 · LAX 09:55 · JFK 12:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.