如何从Python中具有2000万行的特定列中删除重复项

问题描述 投票:0回答:3

我想从一个大的 csv 中删除重复项。我有这个 csv 格式的数据

client_id;gender;age;profese;addr_cntry;NAZOKRESU;prijem_AVG_6M_pasmo;cont_id;main_prod_id;bal_actl_am_pasmo
388713248;F;80;důchodce;CZ;Czech;;5715125;39775;
27953927;M;28;Dělník;CZ;Opavia;22;4427292;39075;

我需要删除 client_id 中的所有重复项。 我无法用 Pandas 在 python 中处理这个大文件。我尝试了 dask,但结果相同。只是无限的等待时间,什么也没发生。

这是我的最后一个版本的代码


import dask.dataframe as dd
import chardet
from dask.diagnostics import ProgressBar

with open('bigData.csv', 'rb') as f:
    result = chardet.detect(f.read())

df = dd.read_csv('bigData.csv', encoding=result['encoding'], sep=';')

total_rows = df.shape[0].compute()

df = df.drop_duplicates(subset=['client_id'], keep=False, Inplace=True)

df.to_csv('bigData.csv', sep=';', index=False)

total_duplicates = total_rows - df.shape[0].compute()

print(f'Was deleted {total_duplicates} duplicated rows.')

我用进度条尝试了一下,但什么也没发生。感谢您的帮助!

python csv bigdata
3个回答
1
投票

您也许可以使用一个非常简单的 Python 程序,该程序将它在字典中看到的每个新 ID 存储起来,如果发现该行的 ID 已在字典中,则跳过写入后续行。 它应该需要大约 2GB 的 RAM。

import csv

reader = csv.reader(open("input.csv", newline=""))
writer = csv.writer(open("output.csv", "w", newline=""))

writer.writerow(next(reader))  # transfer header, if you have one

ids = {}
for row in reader:
    if row[0] not in ids:
        writer.writerow(row)
        ids[row[0]] = None  # add ID to "list" of already written IDs

这个方法:

  • 使用字典
    ids
    来保存程序已经遇到并写入的所有ID; dicts 可以非常快速地查找/检查其键(您的 ID)。
  • 保持行的原始顺序。

我模拟了一个 CSV w/20M 行(随机生成的 ID 在 0 到 20M 之间),看起来像这样:

| id       | i |
|----------|---|
| 2266768  | 0 |
| 15245359 | 1 |
| 16304974 | 2 |
| 4801643  | 3 |
| 9612409  | 4 |
| 17659151 | 5 |
| 15824934 | 6 |
| 4101873  | 7 |
| 12282127 | 8 |
| 5172219  | 9 |

我通过该程序运行它,最终得到 1260 万行。 在我的 Macbook Air M1(双通道 SSD)上,耗时 14 秒,消耗 1.5GB RAM。 RAM 需要保存所有以前见过的 ID。

另外,我看到您首先读取整个文件以检测字符编码:

  • 您是否尝试过从命令行运行

    chardetect
    chardetect input.csv
    ,然后对返回的值进行硬编码?

  • 您是否尝试过读取文件的一小部分并查看获得的结果和信心?

    with open("input.csv", "rb") as f:
        input_enc = chardet.detect(f.read(1024 * 64))  # only read first 64K
    
    print(input_enc)  # {'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
    

1
投票

使用 AWK 执行相同的任务。这不是操作员要求的,只是为了完成上面的评论。 不接受作为答案。

BEGIN{
  FS=","   # set field separator to comma
}
!seen[$2]++ {    # is field 2 not seen before ? 
    print $0
}

样本数据:

RowNum,ID
1,5220607
2,8632078
3,8323076
..

运行为

c:\>awk -f script.awk  input.csv  > uniquevalues.csv

这会输出大约 12 mio 行,并在大约 18 秒内消耗 1,8GB 内存(i7 Windows)。

上面 @zach-young 的 python 脚本在同一台计算机和文件上大约需要 35 秒,但内存较少。


0
投票

使用 DuckDB 在一个 SQL 查询中可以非常高效地完成此操作

COPY (SELECT DISTINCT * FROM read_csv_auto('bigfile.csv')) TO 'dedupedFile.csv' (HEADER, DELIMITER ',');

也可以在Python中使用

© www.soinside.com 2019 - 2024. All rights reserved.