【问题标题】:Splitting an unordered csv file based on the values in the nth column/根据第 n 列中的值拆分无序的 csv 文件/
【发布时间】:2016-12-21 16:54:18
【问题描述】:

我有一个大型 csv 文件,其中包含代表几种不同物种的采样病原体的信息。我想按物种分割这个 csv 文件,所以每个物种都有一个 csv 文件。文件中的数据没有任何特定的顺序。我的 csv 文件如下所示:

maa_2015-10-07_15-15-16_5425_manifest.csv,NULL,ERS044420,EQUI0208,1336,Streptococcus equi,15/10/2010,2010,Belgium,Belgium
maa_2015-09-28_13-07-45_0098_manifest.csv,NULL,ERS852528,2789STDY5834916,154046,Hungatella hathewayi,2013,2013,United Kingdom,UK
maa_2015-09-28_13-07-45_0098_manifest.csv,NULL,ERS852530,2789STDY5834918,33039,Ruminococcus torques,2013,2013,United Kingdom,UK
maa_2015-09-28_13-07-45_0098_manifest.csv,NULL,ERS852533,2789STDY5834921,40520,Blautia obeum,2013,2013,United Kingdom,UK
maa_2015-09-28_13-07-45_0098_manifest.csv,NULL,ERS852535,2789STDY5834923,1150298,Fusicatenibacter saccharivorans,2013,2013,United Kingdom,UK
maa_2015-09-28_13-07-45_0098_manifest.csv,NULL,ERS852537,2789STDY5834925,1407607,Fusicatenibacter,2013,2013,United Kingdom,UK
maa_2015-09-28_13-07-45_0098_manifest.csv,NULL,ERS852540,2789STDY5834928,39492,Eubacterium siraeum,2013,2013,United Kingdom,UK
maa_2015-09-28_13-07-45_0098_manifest.csv,NULL,ERS852544,2789STDY5834932,292800,Flavonifractor plautii,2013,2013,United Kingdom,UK
maa_2015-09-28_13-07-45_0098_manifest.csv,NULL,ERS852551,2789STDY5834939,169435,Anaerotruncus colihominis,2013,2013,United Kingdom,UK
maa_2015-10-07_15-15-16_5425_manifest.csv,NULL,ERS044418,EQUI0206,1336,Streptococcus equi,05/02/2010,2010,Belgium,Belgium
maa_2015-10-07_15-15-16_5425_manifest.csv,NULL,ERS044419,EQUI0207,1336,Streptococcus equi,29/07/2010,2010,Belgium,Belgium

该物种的名称在索引 5 处。

我最初尝试过这个:

import csv
from itertools import groupby

for key, rows in groupby(csv.reader(open("file.csv")),
                         lambda row: row[5]):
    with open("%s.csv" % key, "w") as output:
        for row in rows:
            output.write(",".join(row) + "\n")

但这失败了,因为数据不是按物种排序的,并且输出没有附加争论(我知道),所以每次脚本遇到它已经拥有的物种的新条目时写入文件会覆盖第一个条目。

有没有一种简单的方法可以按物种对数据进行排序,然后执行上述脚本,或者有一种方法可以将上述脚本的输出附加到文件而不是覆盖它?

另外,我希望每个输出文件都以它们包含的物种命名。

谢谢。

【问题讨论】:

标签: python csv


【解决方案1】:

参考您的评论:“输出没有附加争论(我知道)”,您可以使用 'a' 而不是 'w' 来附加到文件,如:

with open("%s.csv" % key, "a")

这可能不是最好的方法,因为如果你运行代码两次,你会得到双倍的结果。

【讨论】:

  • 不错,但是 1) 你可以编辑你的帖子,让它看起来更好,如果你运行两次代码会发生什么?
  • 此外,感谢groupby(),数据已经被按键分组;因此,每个文件将只打开一次。
  • @Haroldo_OK 不完全正确:如果您不对数据进行排序,它会多次打开文件,这就是问题所在。
  • 如果文件很大,你说得对:sort 需要更多内存,而你的方法不需要。
  • 哦,我明白你的意思了。 docs.python.org/2/library/itertools.html#itertools.groupby ;通常情况下,必须在 RAM 消耗和磁盘访问量之间做出选择。
【解决方案2】:

您可以使用与 groupby operation 相同的 lambda 函数对 csv 文件进行排序:

import csv
from itertools import groupby

groupfunc = lambda row: row[5]

for key, rows in groupby(sorted(csv.reader(open("file.csv")),key=groupfunc),groupfunc):
    with open("%s.csv" % key, "w") as output:
        cw = csv.writer(output)
        cw.writerows(rows)

注意:

  1. 我重写了写入例程以使用csv 模块作为输出
  2. 我为您的 lambda 创建了一个变量,因此无需复制粘贴

请注意,如果您更改输入数据,则必须清理您的 csv 文件,因为如果新数据中没有一个物种,则旧的 csv 会保留在磁盘上。我会用一些代码来做到这一点:

import glob,os

for f in glob.glob("*.csv"):
   os.remove(f)

但要小心 *.csv 模式,因为它太宽了,而且对您的其他 csv 文件可能有点太有效了 :)

注意:此方法使用sort,因此更占用内存。您可以选择以附加模式打开每个文件,因为其他解决方案建议以节省内存,但执行更多文件 I/O。

【讨论】:

    猜你喜欢
    • 2017-10-10
    • 1970-01-01
    • 1970-01-01
    • 2015-03-06
    • 2020-05-20
    • 1970-01-01
    • 2012-04-14
    • 2021-07-25
    • 1970-01-01
    相关资源
    最近更新 更多