我有大约 50 个 CSV 文件,每个文件有 60,000 行,列数不等。我想按列合并所有 CSV 文件。我尝试在 MATLAB 中执行此操作,方法是转置每个 csv 文件并重新保存到磁盘,然后使用命令行连接它们。这花了我一个多星期的时间,最终结果需要再次转置!我必须再做一次,我正在寻找一个不会再花一周时间的解决方案。任何帮助,将不胜感激。
5 回答
[...] 转置每个 csv 文件并重新保存到磁盘,然后使用命令行连接它们 [...]
听起来像转置猫转置。使用粘贴水平连接文件。
paste -d ',' a.csv b.csv c.csv ... > result.csv
可以设置Pythoncsv
模块,以便每条记录都是以列名作为键的字典。您应该能够以这种方式读取所有文件作为字典,并将它们写入包含所有列的输出文件。
Python 易于使用,因此对于任何语言的程序员来说这应该是相当简单的。
如果您的 csv 文件没有列标题,那么这将是相当多的手动工作,所以它可能不是最好的解决方案。
由于这些文件相当大,最好不要一次将它们全部读入内存。我建议您首先打开它们只是为了将所有列名收集到一个列表中,然后使用该列表来创建输出文件。然后,您可以将每个输入文件连接到输出文件,而不必将所有文件都放在内存中。
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='')
水平连接确实是微不足道的。考虑到您了解 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
对象存储在向量/数组/列表中。在这种情况下,您只需从每个文件中一次读取一行并将其写入输出。
使用 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
}