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 · 167 天前 · 4226 次点击
    这是一个创建于 167 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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  
       167 天前
    4 千还是 4 千万呢,感觉你这数据量基本上是几秒就结束的吧,

    我还是怀疑代码问题

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

    stackoverflow 中有很多这方面的回答,可以去看看。
    sgld
        16
    sgld  
       167 天前 via Android
    问题中提到 tb6k 后面第 5 8 10 行的内容赋值给 tb4k 后三列。这里是不是 5 8 10 列

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

    如果不是别无他法,遍历都是最次选,实在不行考虑 aplly 这些🤩
    sgld
        17
    sgld  
       167 天前 via Android
    @sgld apply
    ddkk1112
        18
    ddkk1112  
       167 天前   ❤️ 1
    打了一堆又删了
    你还是让 gpt 帮你写吧
    ipwx
        19
    ipwx  
       167 天前   ❤️ 1
    你代码呢?

    首先,python 不能用 for loop 。

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

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

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

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

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

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

    但是你如果数据唯一,完全可以走 join ,然后直接取要拿的列就行了
    zealotxxxx
        29
    zealotxxxx  
       167 天前
    你不会是嵌套 loop 吧?

    4000 * 6000 = 2400 万次? 那不慢才怪
    psyer
        30
    psyer  
       167 天前 via Android
    看下代码呢
    weidaizi
        31
    weidaizi  
       167 天前
    看了一下,这慢很正常呀,帮大家格式化一下楼主的伪代码:
    ```
    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  
       167 天前
    @weidaizi = = 我晕,前面的空格没了
    encro
        33
    encro  
       167 天前
    我用 pandas 计算 k 线指标,1 万跟 k 线,几十个指标也只要几秒钟。估计你用的 pandans 和我用的 pandas 不是一个东西。
    billbur
        34
    billbur  
       167 天前
    djangovcps
        35
    djangovcps  
       167 天前
    感觉你笛卡尔积的循环了,要不嗯循环几千行不肯能一小时
    kingbill
        36
    kingbill  
       167 天前
    我觉得是 T14 的锅,是 U 结尾的 i7 吗?
    stiangao
        37
    stiangao  
       167 天前
    前三列一样就合并一行的内容吧,

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

    按这个方法写,遍历一次 6000 行,前三列拼一个 key, 后三列拼 value ,生成一个 dict,
    遍历 4000 行的文件,从 dict 里查, 查到了就拼接,
    总共遍历数据 1w 次
    winglight2016
        38
    winglight2016  
       167 天前
    太菜了,pandas 用成了 array

    另外,两个单词都拼错了,看着难受┑( ̄Д  ̄)┍
    henix
        39
    henix  
       167 天前   ❤️ 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  
       166 天前
    show your code
    usiantein
        41
    usiantein  
       166 天前
    talk is annoying, show your code
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3216 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 12:15 · PVG 20:15 · LAX 04:15 · JFK 07:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.