【问题标题】:Using Pandas to concatenate CSV files in directory, recursively使用 Pandas 以递归方式连接目录中的 CSV 文件
【发布时间】:2015-09-28 09:15:41
【问题描述】:

这是上一篇文章中的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')

我想知道如何使用熊猫修改上述内容。具体来说,我试图递归地移动目录并将所有 CSV 标头及其各自的行值连接起来,然后将其写入一个文件中。使用 P.R 的方法,导致所有标题及其对应的值相互堆叠。我的限制是:

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

  • 如果一个文件中的列标题与另一个文件匹配,则它们不应重复。在写入一个 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.

(第二个示例中的所有标题列都应使用分隔符','填充第一个示例中没有对应标题的第二行)

可以看到,第二个示例有更多的列标题。此外,一些 标题相同(但顺序不同)。我正在尝试结合所有 这些 - 以及它们的值,遵循上述要求。我是 想知道最好的方法是在一个 pandas的内置方法?

【问题讨论】:

  • 对于您发布的示例,期望的结果是什么?
  • 你有什么特别的理由想在这里使用pandas - 我想没有它会更容易......(有趣的新名字@HappyLeapSecond!)
  • @HappyLeapSecond 我试图用要点来说明这一点——如果不把它画出来就很难解释。所有标题都应位于一个“行”/“行”中,而值应位于随后的“行”中。常见的标题不应重复,但应添加与每个标题对应的值。应保持顺序,不应删除任何标题或值。应自动添加任何新标头(连同其值)。
  • @JonClements 我认为 pandas 将是最有效的方法。如果您有其他建议,我欢迎您的想法。
  • @890319ahlusar 每个 CSV 文件只有一个数据行吗?

标签: python csv pandas merge concatenation


【解决方案1】:

一种非基于pandas 的方法,它使用OrderedDictcsv 模块。

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,,

【讨论】:

  • 我有一个与您上述非 Pandas 方法非常相似的解决方案。需要注意的是,在其他 csv 文件中重复的所有键/列名称(并且具有不同的相应行值)不是按顺序附加的。例如,在上述两个示例中,列标题“Type”有两个不同的值:UMember 和 Query。理想情况下,应在 UMember 之后附加查询。如果还有其他类似的列标题,那么它们的值应该遵循相同的规则。其他要求仍受控制。
  • @890319ahlusar 你真的需要花一些时间用输入示例的确切预期输出来更新你的问题......
  • 我会立即这样做@JonClements
  • @890319ahlusar 必须弹出 - 根据我认为是您的要求进行更新...
  • @890319ahlusar 会透露这个错误是什么? :p
【解决方案2】:

在 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))]

【讨论】:

  • 将 df 从每个 csv 读取到一个列表中,然后连接列表中的所有 df,而不是连接每个 df,性能会更好
  • @EdChum - 你可以提供一个例子
  • @890319ahlusar 阅读文章也会解释更复杂的函数,但 concat 应该涵盖所有内容
  • @AndrewScottEvans 感谢您提供参考资料。我已经彻底审查了这些。但是,似乎一次只能合并两个数据帧。是否有您推荐的子函数允许我检查相同的标头,然后在检查为真时附加该标头的相应值?我想了解熊猫的肠子:)
  • @890319ahlusar 像 pandas.concat([df1,df2,df3]) 这样将它们附加到一个列表中。 stackoverflow.com/questions/15819050/…">这篇文章就是最好的例子。我刚看到代码。它还讨论了 append v. concat。
猜你喜欢
  • 2020-01-20
  • 1970-01-01
  • 2012-10-30
  • 1970-01-01
  • 2016-10-03
  • 1970-01-01
  • 1970-01-01
  • 2018-10-26
  • 2016-07-11
相关资源
最近更新 更多