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

Python 的大文件解析

  •  
  •   jiminjohn0402 · 2023-11-01 18:48:51 +08:00 · 2956 次点击
    这是一个创建于 386 天前的主题,其中的信息可能已经有所发展或是发生改变。
    今天做了一个 3gcsv 数据量 2100 万条的 csv 拆分,因为 csv 总提示数据超长,然后就导出为 xlsx ,但是非常慢,因为是初次接触,是不是哪里有什么问题。但是如果只是拆分 csv 不会很慢(都会先按一个字段进行排序)。
    想问下各位大佬对于这一类型的数据拆分和解析如何处理,有什么优化方案?用的是 mbp 19 16g 内存 intel i7
    第 1 条附言  ·  2023-11-07 10:57:01 +08:00

    大文件转为xlsx确实很慢,我自己什么不做,只是将csv拆开,然后转为xlsx,也很慢,240万数据,大概330s左右。 有4个日期字段,但是都做了预处理,感觉还是效果很小,用了engine=‘openpyxl’,仍然还是一样的速度

    import pandas as pd
    
    # 读取 CSV 文件
    chunksize = 500000  # 设置每个文件的行数
    reader = pd.read_csv('your_file.csv', chunksize=chunksize)  # 替换为你的 CSV 文件路径
    
    # 分割数据并导出为多个 Excel 文件
    file_number = 1
    for chunk in reader:
        output_file = f"output_{file_number}.xlsx"  # 设置导出文件名
        chunk.to_excel(output_file, index=False)
        file_number += 1
    
    print("数据已分割并导出为多个 Excel 文件")
    
    18 条回复    2023-11-02 16:15:03 +08:00
    l1xnan
        1
    l1xnan  
       2023-11-01 19:15:28 +08:00
    没明白你那个“因为..., 然后 ...” 的因果关系。如果是读 csv 慢,用最新版本的 pandas 或者 pyarrow 或者 duckdb ,都非常快,不要自己写 open/for 循环,如果是写 xlsx 慢,格式决定写速度可优化空间不多,xlsxwriter 相比 openpyxl 性能好点,用 constant_memory=optimised 参数,内存优化非常明显,速度会比 openpyxl 库快一点
    evemoo
        2
    evemoo  
       2023-11-01 20:54:22 +08:00
    一种思路
    ```python
    def list_split(source_list, n):
    return [source_list[i:i+n] for i in range(0, len(source_list), n)]

    while line := f.readline():
    do_something
    ```
    orangie
        3
    orangie  
       2023-11-01 22:07:20 +08:00
    感觉像是没用 pandas ,而是自己解析和处理 csv 。对于 pandas 来说 3GB 的文件不大。
    NoOneNoBody
        4
    NoOneNoBody  
       2023-11-02 04:05:23 +08:00
    你这个需要汇总么?不需要的话,读一行处理一行,添加到相应文件
    如果只是拆分,不需要计算的话,按这种方式纯文字处理很快的
    SuperXX
        5
    SuperXX  
       2023-11-02 04:37:53 +08:00 via iPhone
    拆分的闭着眼睛用 np.split
    读写慢 用 parquet 或者 DuckDB , 其实这个数据量才 3GB….

    楼主得好好提升一下自己的语文, 虽然不知道你到底要表达啥,我还是盲猜吧
    ho121
        6
    ho121  
       2023-11-02 07:10:08 +08:00 via Android
    不如试试 Access
    bianhui
        7
    bianhui  
       2023-11-02 08:13:03 +08:00
    没看明白啥意思,如果导出 xlsx excel 直接另存为不就行了吗。如果解析数据,read line ,不要 read lines 。
    hyperbin
        8
    hyperbin  
       2023-11-02 08:18:34 +08:00 via Android
    excel 最多 1048576 行
    missuo
        9
    missuo  
       2023-11-02 08:34:46 +08:00 via iPhone
    用 readline ,不要用 readlines ,不就行了
    jiminjohn0402
        10
    jiminjohn0402  
    OP
       2023-11-02 08:39:40 +08:00
    @l1xnan 确实说的有问题,是因为两个原因要拆分
    1 、文件太大,单独打开太慢
    2 、即便打开了提示字段超长,可能现实不全,但是转为 xlsx 不会有这个问题
    然后就开始想拆分方案,我自己参考网上的方案写了一份,感觉有点慢:

    import pandas as pd

    # 读取 CSV 文件
    data = pd.read_csv('customer.csv')

    # 按照“客户编号”列排序
    # 转换为字符串列排序
    data['客户编号'] = data['客户编号'].astype('str')
    sorted_data = data.sort_values(by='客户编号', ascending=False)

    # 将数据拆分为 30 个数据桢并保存为 CSV 文件
    num_files = 30
    chunk_size = len(sorted_data) // num_files

    for i in range(num_files):
    start_idx = i * chunk_size
    if i < num_files - 1:
    end_idx = (i + 1) * chunk_size
    else:
    end_idx = len(sorted_data)

    chunk = sorted_data.iloc[start_idx:end_idx]
    chunk.to_excel(f'chunk_{i + 1}.xlsx', index=False)
    laqow
        11
    laqow  
       2023-11-02 09:03:37 +08:00
    直接 bash 下用 head -l 拆不就行了?拆完每个文件加上第一个文件的第一行,然后用 python 或什么别的多进程转成 excel 。
    超过 10M 的文件都不要用 excel ,不然每次打开都要等半天,excel 还有各种自动转码的 feature ,长数字转 int 超长截断,反斜杠变日期之类的。reCSVEditor 之类的直接看 csv 要简单很多。
    Maerd
        12
    Maerd  
       2023-11-02 09:18:51 +08:00
    xlsx 自带压缩,基础数据类型也和 csv 不同,你在转出时首先要将数据格式转成 xlsx 的格式,然后再进行压缩,你想想这能快吗
    jiyan5
        13
    jiyan5  
       2023-11-02 11:29:07 +08:00
    吐槽下 excel 的后缀名是啥玩意,不如 doc ppt 的好记
    volvo007
        14
    volvo007  
       2023-11-02 11:36:41 +08:00
    @jiminjohn0402 有点慢是多慢?一般最新的 pandas 打开 3G 的 csv 应该和玩一样。如果慢,可能和你的数据类型有关,比如如果日期类比较多的话,pd 会用不同的日期格式去匹配,这个过程也是非常慢的。嫌慢也可以考虑基于 pyarrow 的 polars 去处理。arrow 是 Apache 的顶级框架之一,专门用来处理大数据的。此外,pd 是基于 numpy 的,而 numpy 本身不包含 string 类型,因为这不是 numpy 最关心的问题,它都是“数据”计算。所以如果文本类型比较多得话,还是考虑 pyarrow 这种原生支持 string 的库去处理才是合适的
    djangovcps
        15
    djangovcps  
       2023-11-02 12:02:35 +08:00
    众所周知 python 的各种库 写 excel 都是慢的,根本就没说到点子上,真的嫌慢,用 python3.11 有伪 jit 加速,写 xlsx 会快 80%,我试过的
    jiminjohn0402
        16
    jiminjohn0402  
    OP
       2023-11-02 13:13:07 +08:00 via iPhone
    @volvo007 大概花了两个小时分拆出 30 个文件,每个文件 80 多万条数据
    NoOneNoBody
        17
    NoOneNoBody  
       2023-11-02 13:14:42 +08:00
    @jiminjohn0402 #10
    首先看你写的,并不需要 pandas ,逐条读取,提取客户编号作为判断,然后写到 xlsx ,加几个计数器的事,当然这样没有排序,但可以不同客户编号用不同输出

    或者倒入 sqlite ,后面就不用说了

    然后说这段代码
    1.sort_values 应该加上 ignore_index=True ,重排 index
    2.你这个完全可以用 groupby ,不用 sort ,2000w 条为了分编号 sort 没必要
    3.有个 more_itertools.chunked ,不用自己算切片
    4.也可以用 while + dataframe.head ,每次 drop 已完成的部分

    看整个流程关键点是排序,而且你这个也仅仅是客户编号排序而已,如果这不是必须的,选择方式就很多了
    volvo007
        18
    volvo007  
       2023-11-02 16:15:03 +08:00
    @jiminjohn0402 这个速度非常不正常,可能的话再多给一些数据结构的信息吧,或者直接上代码,做个列名的脱敏处理。30 个文件,每个才 100 M ,这种估计 2-5 分钟完成比较正常
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   986 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 21:17 · PVG 05:17 · LAX 13:17 · JFK 16:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.