如何高效处理分析大文件

题记:

我们可能会遇到需要对一个很大的文件的某一行进行去重,排序,或者对两个文件进行合并等。本文主要测试了几种不同的方案,并进行比较。

场景: 对4百万数据的CSV文件进行去重

测试环境:MacBook Pro Intel Core i9 16GB Memory

测试文件:

# total lines
$ wc -l test.csv
42013405 test.csv
$ ls -lh test.csv
-rw-r--r--@ 1 haofan  staff   448M Nov  6 22:29 test.csv
$ head -4 test.csv
id
202105261
202105261
202105262
  • 方案一:linux 命令,  用时:186s
    • time sort -u test.csv > deup.csv
      186.88s user 11.05s system 97% cpu 3:22.14 total
  • 方案二: Python pandas, 代码如下, 大概耗时60s, 其中大部分时间花在写数据到磁盘上,因为是I/O bound。
    • import pandas as pd
      import logging
      logging.basicConfig(level=logging.DEBUG,
                          format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
      
      logging.info("Start reading files...")
      
      table_file = "~/Desktop/test/test.csv"
      test_csv = pd.read_csv(table_file, encoding='utf_8', low_memory=False)
      
      logging.info("Start running dedup...")
      
      test_csv = test_csv.drop_duplicates()
      
      logging.info("Start output...")
      test_csv.to_csv('dedup.csv', sep=" ", header=False, index=False)
      # np.savetxt("numpytotxt.csv", test_csv.values, fmt='%d') # take 37s.
      # test_csv.to_pickle('dedup.csv') # take 1s
      test_csv.reset_index().to_feather('dedup.csv') # take 2s
      logging.info("Finish all...")
      
      # 运行结果:用时大概60s 主要耗时在写数据到disk上, disk 写入大概耗时30s
      python test.py
      2021-11-06 22:57:11,552 - test.py[line:10] - INFO: Start reading files...
      2021-11-06 22:57:16,900 - test.py[line:15] - INFO: Start running dedup...
      2021-11-06 22:57:29,343 - test.py[line:19] - INFO: Start output...
      2021-11-06 22:58:02,648 - test.py[line:21] - INFO: Finish all...
      

      也查过其他写数据到磁盘上更快的方式,测试代码如上, 结果如下。因为feather或pickle是经过压缩的数据格式,输出的文件是二进制文件,必须用python才可读。但是因为平台不支持这种feather或者pickle的数据格式,只能用csv的数据格式。

      • to_feather: 只耗时2s,就可以把数据写入磁盘

      • to_pickle: 只耗时1s,就可以把数据写入磁盘。

  • 方案三:导入本地mysql,通过sql命令去执行。发现import data 超级慢大概要十几分钟,import data后,执行一次count的query,要耗时1分钟。

    • # 启动mysql
      docker run --name mysql -v /Users/haofan/code/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=haofan -d mysql
      # login mysql
      docker exec -it mysql bash
      # create DB
      create DATABASE test;
      use test
      # create table
      CREATE TABLE IF NOT EXISTS `users`(
         `id` VARCHAR(40) NOT NULL,
         PRIMARY KEY ( `id` )
      )ENGINE=InnoDB DEFAULT CHARSET=utf8;
      
      # allow import data from disk
      SET GLOBAL local_infile=1;
      
      docker exec -it mysql bash
      # import data
      mysqlimport --ignore-lines=1 \
                  --fields-terminated-by='\t' \
                  --local -u root \
                  -p test \
                  users.csv
      
      
      mysql> select count(*) from users;
      +----------+
      | count(*) |
      +----------+
      | 42013405 |
      +----------+
      1 row in set (53.22 sec)
  • 终极方案:导入大数据平台,hadoop. 

总结

  1. 如果对小文件的内容进行排序,最方便直接用shell sort. 
  2. 再大点的文件可以用python pandas,pandas最耗时的部分是写文件到磁盘。所以最好用pickle后者feather的数据格式。
  3. 再大的文件,如果追求高效率,只能用大数据平台。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Frank范

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值