【问题标题】:Python: Combine multiple zipped files and output to multiple csv filesPython:组合多个压缩文件并输出到多个csv文件
【发布时间】:2020-01-24 09:22:20
【问题描述】:

编辑 2: 添加一些示例行以供参考。第一行是列名。

field 1|field 2|field3|id
123|xxx|aaa|118
123|xxx|aaa|56
124|xxx|aaa|184
124|yyy|aaa|156

编辑:

  • 对非 Python 解决方案开放(grep/awk 等都可以)

  • csv 文件是用竖线分隔的“|”

  • 我需要保留标题

我有 20 个 .gz 文件(每个 ~100MB,已压缩)。每个 .gz 文件中都有一个 csv 文件,其中包含许多列,包括索引列“id”。所有文件中大约有 250 个唯一 ID。

我需要将每个唯一 id 的所有行输出到每个 csv(即应该生成 250 个 csv 文件)。

我应该如何最好地做到这一点?

我目前正在使用 Python,但生成每个 csv 大约需要 1 分钟,我想知道是否有更快的解决方案。

output_folder = 'indiv_ids/'

# get list of files
list_of_files = [filename for filename in os.listdir() if filename.endswith(".gz")]

# get list of unique ids
for i in range(len(list_of_files)):
    df = pd.read_csv(list_of_files[i], sep='|', usecols=['id'], dtype=str, engine='c')
    id_list = df['id'].unique()

    if len(id_list) == 250:
        break

# load into a list for each id
list_df = {id:[] for id in id_list}

for filename in list_of_files:
    df = pd.read_csv(filename, sep='|', dtype=str, engine='c')

    for id in id_list:
        df_id = df[df['id'] == id]
        list_df[id].append(df_id)

for id in id_list:
    # join into one big df
    df_full = pd.concat(list_df[id], axis=0)
    df_full.to_csv(f'{output_folder}{id}.csv', sep="|", index=False)

【问题讨论】:

  • 我的回答解决了您的问题吗?如果是这样,请考虑接受它作为您的答案 - 通过单击计票旁边的空心对勾/复选标记。如果没有,请说出什么不起作用,以便我或其他人可以进一步为您提供帮助。谢谢。 meta.stackexchange.com/questions/5234/…
  • 嗨,很抱歉回复晚了 - 除了标题丢失之外,它还有效。如果有任何想法如何将标题保留在每个文件中,请不胜感激?如果没有解决方案,我会接受你的作为答案

标签: python-3.x csv awk grep gzip


【解决方案1】:

更新答案

现在我已经看到了您的数据的外观,我认为您想要这样:

gunzip -c *gz | awk -F'|' '$4=="id"{hdr=$0;next} hdr{f=$4; print hdr > f ".csv"; hdr=""} {print > f ".csv"}'

原答案

我认为您要求 “任何更快的解决方案” 允许非 Python 解决方案,所以我建议 awk

我生成了 4 个 1000 行的虚拟数据文件,如下所示:

for ((i=0;i<4;i++)) ; do
    perl -E 'for($i=0;$i<1000;$i++){say "Line $i,field2,field3,",int rand 250}' | gzip > $i.gz
done

这是其中一个文件的前几行。第四个字段在 0..250 之间变化,应该类似于您的 id 字段。

Line 0,field2,field3,81
Line 1,field2,field3,118
Line 2,field2,field3,56
Line 3,field2,field3,184
Line 4,field2,field3,156
Line 5,field2,field3,87
Line 6,field2,field3,118
Line 7,field2,field3,59
Line 8,field2,field3,119
Line 9,field2,field3,183
Line 10,field2,field3,90

那么你可以这样处理:

gunzip -c *gz | awk -F, '{ id=$4; print > id ".csv" }'

也就是说...... “解压缩所有.gz文件而不删除它们并将结果传递给awk。在awk中,字段分隔符是逗号。应该选择id从每行的第 4 个字段开始。每行应打印到名称为 id 后跟 .csv"的输出文件。

您应该会很快获得 250 个 CSV 文件。

注意:如果您用完打开的文件描述符,您可能需要提高限制。尝试运行以下命令:

help ulimit
ulimit -n 500

【讨论】:

  • 我建议使用BEGIN{FPAT = "([^,]*)|(\"[^\"]+\")"} (gnu.org/software/gawk/manual/html_node/…)
  • 你也丢失了 csv-header 所以可能改成gunzip -c *gz | awk -F, 'BEGIN{FPAT = "([^,]*)|(\"[^\"]+\")"} {if ($4 == "id") {h = $0;} else {id=$4; if (hh[id] != 1) print h &gt; id ".csv"; print &gt; id ".csv"} }'
  • 它返回一个错误:awk: 源代码第 1 行上下文的语法错误是 { id=$4; print > id >>> ".csv"
  • gunzip -c *gz | awk -F'|' '{ id=$4; print &gt; id }' 在没有“.csv”的情况下工作,但它会在完成大约 10 个 id 后停止并抛出错误:awk: 使打开的文件过多
  • gunzip -c *gz | awk -F'|' '{ id=$4; print&gt;&gt; id; close(id) }' 有效!已经运行了 5 分钟。现在要弄清楚如何获取标头... Lutz 的代码在 hh[id] 处引发错误
猜你喜欢
  • 1970-01-01
  • 2018-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-19
  • 2019-05-07
  • 1970-01-01
相关资源
最近更新 更多