【问题标题】:Split csv file thousands of times based on groupby基于groupby拆分csv文件千次
【发布时间】:2020-07-25 00:29:17
【问题描述】:

(改编自大卫·埃里克森的问题here

给定一个包含 A、B 和 C 列以及一些值的 CSV 文件:

echo 'a,b,c' > file.csv
head -c 10000000 /dev/urandom | od -d | awk 'BEGIN{OFS = ","}{print $2, $3, $4}' | head -n 10000 >> file.csv

我们想按列 a 和 b 排序:

sort -t ',' -k1,1n -k2,2n file.csv > file_.csv
head -n 3 file_.csv
>a,b,c
3,50240,18792
7,54871,39438

然后为每个唯一对 (a, b) 创建一个名为 '{a}_Invoice_{b}.csv' 的新 CSV。

主要挑战似乎是写入数千个文件的 I/O 开销 - 我开始尝试使用 awk,但遇到了 awk: 17 makes too many open files

在 awk、Python 或其他一些脚本语言中是否有更快的方法来执行此操作?

附加信息:

  • 我知道我可以在 Pandas 中做到这一点 - 我正在寻找一种使用文本处理的更快方法
  • 虽然我使用urandom 生成样本数据,但实际数据具有重复值的运行:例如a=3, b=7 的几行。如果是这样,这些应该保存为一个文件。 (这个想法是复制 Pandas 的 groupby -> to_csv)

【问题讨论】:

  • 你可以尝试用 pandas 加载你的原始文件,按 (a,b) 排序并从那里存储。见python-splitting-dataframe-into-multiple-dataframes-based-on-column-values-and。正如你的问题是题外话并使用多种语言。
  • 如果您只关心前两列,为什么不在排序和.csv 文件创建之前删除第 3 列?
  • @rtx13 此示例中 C 列的数据仍然相关。它只是不是基于 A 列和 B 列的动态文件名的一部分。从原始链接问题中,我发现我在 python 中的方法生成 .csv 文件的速度有点慢,我想知道是否有更快的方法在蟒蛇。 JoshFriedlander 认为这可能是 awk 非常快的事情。

标签: python csv awk


【解决方案1】:

在python中:

import pandas as pd

df = pd.read_csv("file.csv")
for (a, b), gb in df.groupby(['a', 'b']):
    gb.to_csv(f"{a}_Invoice_{b}.csv", header=True, index=False)

在 awk 中,您可以像这样拆分,您需要将标题放回每个结果文件:

awk -F',' '{ out=$1"_Invoice_"$2".csv"; print >> out; close(out) }' file.csv

加上标题行:

awk -F',' 'NR==1 { hdr=$0; next } { out=$1"_Invoice_"$2".csv"; if (!seen[out]++) {print hdr > out} print >> out; close(out); }' file.csv

最后一个示例的好处是输入 file.csv 不需要排序,只需一次处理即可。

【讨论】:

  • 是的,Python 是原始问题中的方法。使用 awk,它看起来不错 - 但是如果有多个相同的值,它会起作用吗?例如,a 和 b 相同的几个连续行,所需的输出是包含这些行的单个文件。
  • 是的,awk 将附加到现有文件。您可以通过复制示例输入来测试它。
  • 您不需要单独的 shell 循环来打印标题行以输出文件,您的 awk 脚本中的一个简单的!seen[out]++{print hdr > out} 就可以做到这一点。您仍然需要更新现有脚本以跳过或以其他方式处理第一行,例如NR==1{hdr=$0;next}.
【解决方案2】:

由于您的输入将按关键字段进行排序,因此您只需要:

sort -t ',' -k1,1n -k2,2n file.csv |
awk -F ',' '
NR==1 { hdr=$0; next }
{ out = $1 "_Invoice_" $2 ".csv" }
out != prev {
    close(prev)
    print hdr > out
    prev = out
}
{ print > out }
'

【讨论】:

  • 这很好用,谢谢!你会期望它比 Python 中的同类产品更快吗?
  • 不客气。是的,但没有那么健壮,因为它在验证 CSV 格式方面做的工作不如 Python,所以如果你的第一个字段可以被引用并包含逗号,那么我希望使用 CSV 阅读器的 Python 脚本可以正确处理我发布的 awk 脚本不会。请参阅 whats-the-most-robust-way-to-efficiently-parse-csv-using-awk 了解如何使用 awk 稳健地处理 CSV。
猜你喜欢
  • 2014-07-04
  • 2023-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多