按列合并多个 csv 文件的最快方法是啥?

Posted

技术标签:

【中文标题】按列合并多个 csv 文件的最快方法是啥?【英文标题】:What's the fastest way to merge multiple csv files by column?按列合并多个 csv 文件的最快方法是什么? 【发布时间】:2013-08-11 00:32:52 【问题描述】:

我有大约 50 个 CSV 文件,每个文件有 60,000 行,列数不等。我想按列合并所有 CSV 文件。我尝试在 MATLAB 中执行此操作,方法是转置每个 csv 文件并重新保存到磁盘,然后使用命令行连接它们。这花了我一个多星期的时间,最终结果需要再次转置!我必须再做一次,我正在寻找一个不会再花一周时间的解决方案。任何帮助将不胜感激。

【问题讨论】:

你懂 Perl,哪怕一点点? 不,根本没有。我知道 C 和 C++。 50 次 60000 行听起来并不多。数据的总大小是多少?它不适合内存吗? 每个文件有 60000 行和 100-200 列(因文件而异)。每个文件大约 40-50 MB。我的 MATLAB 代码只是将 csv 读入一个单元格数组,将其转置并保存回来。那花了一周时间。然后我连接了所有转置的 csv,这只是一两分钟。我不知道为什么它这么慢。我只是不想再在 MATLAB 中那样做。 【参考方案1】:

[...] 转置每个 csv 文件并重新保存到磁盘,然后使用命令行将它们连接起来 [...]

听起来像转置猫转置。使用paste 水平连接文件。

paste -d ',' a.csv b.csv c.csv ... > result.csv

【讨论】:

很好的解决方案 - 它甚至可以合并甚至不会加载到内存中的非常大的 csv 文件(例如在 python 中)。该操作是逐行完成的,因此没有内存问题。 如果需要第一列匹配,还有joinen.wikipedia.org/wiki/Join_(Unix)【参考方案2】:

可以设置 Python csv 模块,使每条记录都是一个以列名作为键的字典。您应该能够以这种方式读取所有文件作为字典,并将它们写入包含所有列的输出文件。

Python 易于使用,因此对于任何语言的程序员来说这应该是相当简单的。

如果您的 csv 文件没有列标题,那么这将是相当多的手动工作,所以它可能不是最好的解决方案。

由于这些文件相当大,最好不要一次将它们全部读入内存。我建议您首先打开它们只是为了将所有列名收集到一个列表中,然后使用该列表来创建输出文件。然后,您可以将每个输入文件连接到输出文件,而不必将所有文件都放在内存中。

【讨论】:

我的文件确实有标题。我只想水平连接所有文件。对于所涉及文件的大小,这是否可行? (检查对问题的评论)。 @ankit:是的,没问题。更新了答案。 (这是一个有趣的问题,如果我有时间我会为你做,但我没有,我必须迎合客户。:-)) 嘿Lennart,在你走之前,你能列出我需要的函数/方法的名称吗?我可以用谷歌搜索它们的用法,然后自己弄清楚其余的。谢谢:) @ankit:好吧,一切都在这里:docs.python.org/2/library/csv.html 不过,请确保您使用 Python 版本的文档。在 Python 2 和 Python 3 中使用它的方式存在细微差别。【参考方案3】:

水平连接真的很简单。考虑到您了解 C++,我很惊讶您使用 MATLAB。以您的方式处理大约 GB 的数据应该是几秒钟,而不是几天。

根据您的描述,实际上不需要 CSV 处理。最简单的方法是在 RAM 中进行。

vector< vector<string> > data( num_files );

for( int i = 0; i < num_files; i++ ) 
    ifstream input( filename[i] );
    string line;
    while( getline(input, line) ) data[i].push_back(line);

(进行明显的完整性检查,例如确保所有向量的长度相同...)

现在你有了一切,转储它:

ofstream output("concatenated.csv");

for( int row = 0; row < num_rows; row++ ) 
    for( int f = 1; f < num_files; f++ ) 
        if( f == 0 ) output << ",";
        output << data[f][row];
    
    output << "\n";

如果您不想使用所有 RAM,可以一次使用一行。您应该能够同时打开所有文件,并将ifstream 对象存储在向量/数组/列表中。在这种情况下,您只需从每个文件中一次读取一行并将其写入输出。

【讨论】:

据我了解,这涉及到一些 CSV 操作,这意味着您还必须解析 CSV。所以这还不够。【参考方案4】:
import csv
import itertools

# put files in the order you want concatentated
csv_names = [...whatever...] 

readers = [csv.reader(open(fn, 'rb')) for fn in csv_names]
writer = csv.writer(open('result.csv', 'wb'))

for row_chunks in itertools.izip(*readers):
    writer.writerow(list(itertools.chain.from_iterable(row_chunks)))

水平连接。假设所有文件的长度相同。内存开销低,速度快。

答案适用于 Python 2。在 Python 3 中,打开 csv 文件略有不同:

readers = [csv.reader(open(fn, 'r'), newline='') for fn in csv_names]
writer = csv.writer(open('result.csv', 'w'), newline='')

【讨论】:

【参考方案5】:

使用 Go:https://github.com/chrislusf/gleam

假设文件“a.csv”包含字段“a1, a2, a3, a4, a5”。

并假设文件“b.csv”具有字段“b1、b2、b3”。

我们想要连接 a1 = b2 的行。并且输出格式应该是“a1,a4,b3”。

package main

import (
    "os"

    "github.com/chrislusf/gleam"
    "github.com/chrislusf/gleam/source/csv"
)

func main() 

    f := gleam.New()
    a := f.Input(csv.New("a.csv")).Select(1,4) // a1, a4
    b := f.Input(csv.New("b.csv")).Select(2,3) // b2, b3

    a.Join(b).Fprintf(os.Stdout, "%s,%s,%s\n").Run()  // a1, a4, b3


【讨论】:

以上是关于按列合并多个 csv 文件的最快方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

从多个文件中读取大数据并在python中聚合数据的最快方法是啥?

使用 pandas 合并和附加多个 CSV/数据帧的最快方法

python 如何把多个文件内容合并到以一个文件

Pandas 按列将 CSV 拆分为多个 CSV(或 DataFrame)

python将两个csv文件按列合并为一个csv

读取 .csv 文件时在 Python 中解析日期的最快方法是啥?