使用Pandas以递归方式连接目录中的CSV文件

时间:2015-07-09 19:49:49

标签: python csv pandas merge concatenation

以下是上一篇文章中的link。我在下面引用P.R.'s回复。

 import pandas as pd
    import glob
    interesting_files = glob.glob("*.csv")
    df_list = []
    for filename in sorted(interesting_files):
        df_list.append(pd.read_csv(filename))
    full_df = pd.concat(df_list)

    full_df.to_csv('output.csv')

我想知道如何使用pandas修改上述内容。具体来说,我试图以递归方式遍历目录并连接所有CSV标头及其各自的行值,然后将其写入一个文件中。使用P.R&#39的方法,导致所有标题及其相应的值彼此堆叠。我的约束是:

  • 写出标题及其对应的值(没有"堆叠") - 基本上是一个接一个地连接

  • 如果一个文件中的列标题与另一个文件匹配,那么它们应该不重复。只有在将值写入一个CSV文件时才应附加值。

  • 由于每个文件都有不同的列标题和不同数量的列标题,因此应添加这些标题。什么都不应该删除。

我也尝试了以下内容:

import pandas as pd
import csv
import glob
import os

path = '.'
files_in_dir = [f for f in os.listdir(path) if f.endswith('csv')]

for filenames in files_in_dir:
    df = pd.read_csv(filenames)
    df.to_csv('out.csv', mode='a')

以下是两个示例CSV:

ID,Type,ACH,SH,LL,SS,LS,ISO,MID,Pass,TID,CID,TErrors
12821767,Query,,,,,,,,,,,

Type,ID,CC,CCD,Message,MemberIdentifier,NPass,UHB,UAP,NewAudioPIN,AType,ASuufix,Member,Share,Note,Flag,Card,MA,Preference,ETF,AutoT,RType,Locator,ISO,MID,Pass,TID,CID,Errors
UMember,12822909,True,10/31/2013 5:22:19 AM,,,,False,False,,,,,,,,,,,,,Member,,,,,,,

基于上述示例,输出应该是:

    ID,Type,ACH,SH,LL,SS,LS,ISO,MID,Pass,TID,CID,TErrors,CC,CCD,Message,MemberIdentifier,NPass,UHB,UAP,NewAudioPIN,AType,ASuufix,Member,Share,Note,Flag,Card,MA,Preference,ETF,AutoT,RType,Locator,Errors
12822909,UMember,,,,,,,,,,,,True,10/31/2013 5:22:19 AM,,,,False,False,,,,,,,,,,,,,Member,,
12821767,Query ,,,,,,,,,,,,,,,,,,,,,,,,, etc.

(第二个样本中的所有标题列都应填入分隔符',对于第一行中没有相应标题的第二行,

如您所见,第二个样本有更多列标题。还有一些 标题是相同的(但顺序不同)。我想把所有的东西结合起来 这些 - 以及它们的价值观,符合上述要求。我是 想知道最好的方法是合并或执行可自定义的功能 大熊猫的内置方法?

2 个答案:

答案 0 :(得分:1)

使用pandasOrderedDict模块的非基于csv的方法。

from glob import iglob
import csv
from collections import OrderedDict

files = sorted(iglob('*.csv'))
header = OrderedDict()
data = []
for filename in files:
    with open(filename, 'rb') as fin:
        csvin = csv.DictReader(fin)
        try:
            header.update(OrderedDict.fromkeys(csvin.fieldnames))
            data.append(next(csvin))
        except TypeError:
            print filename, 'was empty'
        except StopIteration:
            print filename, "didn't contain a row"

with open('output_filename.csv', 'wb') as fout:
    csvout = csv.DictWriter(fout, fieldnames=list(header))
    csvout.writeheader()
    csvout.writerows(data)

根据您的示例输入,这将为您提供:

ID,Type,ACH,SH,LL,SS,LS,ISO,MID,Pass,TID,CID,TErrors,CC,CCD,Message,MemberIdentifier,NPass,UHB,UAP,NewAudioPIN,AType,ASuufix,Member,Share,Note,Flag,Card,MA,Preference,ETF,AutoT,RType,Locator,Errors
12821767,Query,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
12822909,UMember,,,,,,,,,,,,True,10/31/2013 5:22:19 AM,,,,False,False,,,,,,,,,,,,,Member,,

答案 1 :(得分:-1)

在pandas中,您可以添加列名并轻松地重新排序数据框。请参阅this article on merging frames

要附加框架并重新排序,您可以使用以下内容。重新索引就像使用列表一样简单。还有更多解决方案here

import pandas,os

df = None
dfList=[]
for filename in [directory+x for x in os.listdir(path)]:
    dfList.append(pd.read_csv(filename))
df=pandas.concat(dfList)
df.to_csv('out.csv', mode='w')

使用列表理解,这将是:

import pandas,os    
pandas.concat([pd.read_csv(filename) for filename in [directory+x for x in os.listdir(path) if x.endswith("csv") is True]]).to_csv('out.csv', mode='w')

如果你想重新索引任何东西,只需使用一个清单。

cols=sorted(list(df.columns.values))
df=df[cols]
#or
df=df[sorted(list(df.columns.values))]