Python 将多个CSV文件中的列合并到单个文件中

Python 将多个CSV文件中的列合并到单个文件中,python,csv,Python,Csv,我有一堆CSV文件(在下面的示例中只有两个)。每个CSV文件有6列。我想进入每个CSV文件,复制前两列,并将它们作为新列添加到现有CSV文件中 到目前为止,我已经: import csv f = open('combined.csv') data = [item for item in csv.reader(f)] f.close() for x in range(1,3): #example has 2 csv files, this will be automated n=0

我有一堆CSV文件(在下面的示例中只有两个)。每个CSV文件有6列。我想进入每个CSV文件,复制前两列,并将它们作为新列添加到现有CSV文件中

到目前为止,我已经:

import csv

f = open('combined.csv')
data = [item for item in csv.reader(f)]
f.close()

for x in range(1,3): #example has 2 csv files, this will be automated
    n=0
    while n<2:
        f=open(str(x)+".csv")
        new_column=[item[n] for item in csv.reader(f)]
        f.close()
        #print d

        new_data = []

        for i, item in enumerate(data):
            try:
                item.append(new_column[i])
                print i
            except IndexError, e:
                item.append("")
            new_data.append(item)

        f = open('combined.csv', 'w')
        csv.writer(f).writerows(new_data)
        f.close()
        n=n+1
2.csv看起来像

5,e
6,f
7,g
8,h
9,i
组合的.csv文件应该如下所示

1,a,5,e
2,b,6,f
3,c,7,g
4,d,8,h
,,9,i
下面是一个示例(为了简单起见,我使用字符串io而不是文件,但这不是必需的):

对于真实文件(名为1.csv、2.csv等),主循环如下所示:

for n in range(...):
    with open(str(n) + '.csv') as fp:
        d = list(csv.reader(fp))
        t = len(d) - len(data)
        data = d if not data else [
            x + y for x, y in itertools.izip_longest(
                expand(data, t), expand(d, -t))]

这是我为解决你的问题而写的一个程序。它创建了一个类,该类保存有关要读取的每个CSV文件的信息,包括要从中读取的列。然后就是一个要读取的CSV文件列表,并且从每个CSV文件中读取一行

因为您说过它需要一直返回行,直到所有输入文件都被读取,所以它会返回到达末尾的输入文件的伪值。它会一直读取行,直到完成所有输入文件

而且,这个程序一次只需要在内存中保存一行。因此,它甚至可以在不需要太多内存的情况下处理大型CSV文件

最初,对于丢失的数据,我有一个伪值-1。现在我看到你添加了一个例子,你只是不想要任何价值。我已经将程序从使用-1改为在没有数据时使用空字符串

设计目标之一是使其可扩展。现在需要前两列,但如果以后需要其中一个文件中的第0、3和7列,该怎么办?因此,每个文件都有一个列表,其中包含要获取的列

我实际上没有编写将输出文件重命名为原始文件名的代码,但这很容易添加

理想情况下,整个过程将被包装到一个类中,在这个类中,您可以迭代一个类实例,并使用所有输入文件中的列返回一行。我没有花额外的时间去做这件事,但是如果你要长期使用它,你可能会想这样做。而且,我从来没有费心关闭任何输入文件,因为我认为程序在我们编写输出文件后会结束,然后所有东西都会关闭;但理想情况下,我们应该在使用完所有文件后关闭它们

import csv

fname_in = "combined.csv"
fname_out = "combined.tmp"

lst_other_fnames = [str(x) + ".csv" for x in range(1, 3)]

no_data = ''
def _no_data_list(columns):
    return [no_data for _ in columns]

class DataCsvFile(object):
    def __init__(self, fname, columns=None):
        self.fname = fname
        self.f = open(fname)
        self.reader = csv.reader(self.f)
        self.columns = columns
        self.done = False
    def next_columns(self):
        if self.done:
            return _no_data_list(self.columns)

        try:
            item = next(self.reader)
        except StopIteration:
            self.done = True
            return _no_data_list(self.columns)

        return [item[i] for i in self.columns]

# want all columns from original file
data_csv_files = [DataCsvFile(fname_in, range(5))]

# build list of filenames and columns: want first two columns from each
data_csv_files.extend(DataCsvFile(fname, range(2)) for fname in lst_other_fnames)


with open(fname_out, "w") as out_f:
    writer = csv.writer(out_f)

    while True:
        values = []
        for df in data_csv_files:
            columns = df.next_columns()
            values.extend(columns)
        if not all(df.done for df in data_csv_files):
            writer.writerow(values)
        else:
            break

其中行的行
。izip_longest(*读卡器,fillvalue=['']*2):
可以通过一个例子来理解:

In [1]: import itertools as IT

In [2]: readers = [(1,2,3), ('a','b','c','d'), (10,20,30,40)]

In [3]: list(IT.izip_longest(readers[0], readers[1], readers[2]))
Out[3]: [(1, 'a', 10), (2, 'b', 20), (3, 'c', 30), (None, 'd', 40)]
正如您所见,它的行为非常类似于
zip
,只是它在最长的iterable被消费之前不会停止。默认情况下,它使用
None
填充缺少的项目

现在,如果
读卡器中的项目超过3个,会发生什么情况?
我们想写

list(IT.izip_longest(readers[0], readers[1], readers[2], ...))
但是这很费劲,如果我们事先不知道
len(readers)
,我们甚至无法用明确的东西来替换省略号(

Python有一个解决方案:

请注意,结果
Out[4]
与结果
Out[3]
相同

*readers
告诉Python将
readers
中的项目解包,并将它们作为单个参数发送到
IT.izip\u

这就是Python允许我们向函数发送任意数量的参数的方式。

如今,似乎有人必须为Python中的任何数据处理问题提供基于的解决方案。这是我的:

import pandas as pd

to_merge = ['{}.csv'.format(i) for i in range(4)]
dfs = []
for filename in to_merge:
    # read the csv, making sure the first two columns are str
    df = pd.read_csv(filename, header=None, converters={0: str, 1: str})
    # throw away all but the first two columns
    df = df.ix[:,:1]
    # change the column names so they won't collide during concatenation
    df.columns = [filename + str(cname) for cname in df.columns]
    dfs.append(df)

# concatenate them horizontally
merged = pd.concat(dfs,axis=1)
# write it out
merged.to_csv("merged.csv", header=None, index=None)
哪些是文件

~/coding/pand/merge$ cat 0.csv 
0,a,6,5,3,7
~/coding/pand/merge$ cat 1.csv 
1,b,7,6,7,0
2,c,0,1,8,7
3,d,6,8,4,5
4,e,8,4,2,4
~/coding/pand/merge$ cat 2.csv 
5,f,6,2,9,1
6,g,0,3,2,7
7,h,6,5,1,9
~/coding/pand/merge$ cat 3.csv 
8,i,9,1,7,1
9,j,0,9,3,9
给予


我认为这是正确的路线

所有文件的行数都相同吗?不,行数是可变的。您能否提供(即使是模拟的)输入/输出示例…感谢您更新您的问题-我的回答是:干得好+1。这些文件有多大?它们很小。每个文件有6列,每列少于30行。我有大约200个这样的文件——没有什么像“但那不是必要的”这样的文件会让人觉得自己很愚蠢:)。您介意编辑以用于文件吗?@Styleze:我添加了一个带有文件的示例谢谢您的解决方案。我接受了你的,因为我最了解代码。但是,您是否介意解释一下“对于IT.izip_longest(*readers,fillvalue=['']*2)中的行”是什么意思?尤其是“*读者”让我困惑。。。
list(IT.izip_longest(readers[0], readers[1], readers[2], ...))
In [4]: list(IT.izip_longest(*readers))
Out[4]: [(1, 'a', 10), (2, 'b', 20), (3, 'c', 30), (None, 'd', 40)]
import pandas as pd

to_merge = ['{}.csv'.format(i) for i in range(4)]
dfs = []
for filename in to_merge:
    # read the csv, making sure the first two columns are str
    df = pd.read_csv(filename, header=None, converters={0: str, 1: str})
    # throw away all but the first two columns
    df = df.ix[:,:1]
    # change the column names so they won't collide during concatenation
    df.columns = [filename + str(cname) for cname in df.columns]
    dfs.append(df)

# concatenate them horizontally
merged = pd.concat(dfs,axis=1)
# write it out
merged.to_csv("merged.csv", header=None, index=None)
~/coding/pand/merge$ cat 0.csv 
0,a,6,5,3,7
~/coding/pand/merge$ cat 1.csv 
1,b,7,6,7,0
2,c,0,1,8,7
3,d,6,8,4,5
4,e,8,4,2,4
~/coding/pand/merge$ cat 2.csv 
5,f,6,2,9,1
6,g,0,3,2,7
7,h,6,5,1,9
~/coding/pand/merge$ cat 3.csv 
8,i,9,1,7,1
9,j,0,9,3,9
In [21]: !cat merged.csv
0,a,1,b,5,f,8,i
,,2,c,6,g,9,j
,,3,d,7,h,,
,,4,e,,,,

In [22]: pd.read_csv("merged.csv", header=None)
Out[22]: 
    0    1  2  3   4    5   6    7
0   0    a  1  b   5    f   8    i
1 NaN  NaN  2  c   6    g   9    j
2 NaN  NaN  3  d   7    h NaN  NaN
3 NaN  NaN  4  e NaN  NaN NaN  NaN