【问题标题】:Merge all .csv files in folder by a common field present in each file通过每个文件中存在的公共字段合并文件夹中的所有 .csv 文件
【发布时间】:2021-10-18 15:00:32
【问题描述】:

所以,我有一个包含 .csv 文件的目录。例如:

a.csv

id,name
1,john
2,mary
3,alex

b.csv

id,birth
1,01.01.2001
2,05.06.1990

c.csv

id,death
2,01.02.2020
1,-

结果应该是一个字典,其中键是 id (int),值是文件中所有不同值的字典(字典的字典)。像这样的:

{
        1: {"id": 1, "name": "john", "birth": "01.01.2001", "death": -},
        2: {"id": 2, "name": "mary", "birth": "05.06.1990",
            "death": "01.02.2020"},
        3: {"id": 3, "name": "alex", "birth": None, "death": None},
}

到目前为止,我已经尝试将所有文​​件合并到一个数据框中:

from pathlib import Path
import os
import pandas as pd

files = Path(r'path').rglob('*.csv')

# read in all the csv files
all_csvs = [pd.read_csv(file) for file in files]

# lump into one table
all_csvs = pd.concat(all_csvs, axis=1)

但结果我得到了一个数据框,其中“id”在三列中重复。

任何帮助将不胜感激!

【问题讨论】:

    标签: python csv


    【解决方案1】:

    你想要merge 而不是concat。由于您需要合并多个 DataFrame,您可以这样做:

    import os
    from functools import reduce
    
    all_csvs = [pd.read_csv(file) for file in os.listdir() if file.endswith(".csv")]
    df = reduce(lambda left, right: pd.merge(left, right, how="outer", on="id"), all_csvs)
    
    >>> df
    
       id  name       birth       death
    0   1  john  01.01.2001         NaN
    1   2  mary  05.06.1990  01.02.2020
    2   3  alex         NaN         NaN
    
    #for dictionary output replacing nan with None
    my_dict = df.where(df.notnull(), None).set_index("id", drop=False).to_dict(orient="index")
    >>> my_dict
    
    {1: {'id': 1, 'name': 'john', 'birth': '01.01.2001', 'death': None},
     2: {'id': 2, 'name': 'mary', 'birth': '05.06.1990', 'death': '01.02.2020'},
     3: {'id': 3, 'name': 'alex', 'birth': None, 'death': None}}
    

    【讨论】:

      【解决方案2】:

      如果您愿意,您甚至可以不使用 pandas。首先,创建一个defaultdict 来保存您的所有 csv 数据。让这个字典的默认元素是一个表示“默认”人的字典,即所有键的值都为None

      import collections
      
      def default_person():
          return {'id': None, 'name': None, 'birth': None, 'death': None}
      all_csvs = collections.defaultdict(default_person)
      

      此字典中的键将是id 字段,值将是包含您想要的所有信息的字典。

      接下来,使用csv.DictReader 读取每个文件。 DictReader 将 csv 文件的每一行作为字典读取,键来自文件的标题。然后对于每个文件中的每一行,更新我们刚刚创建的defaultdict 中正确id 的字典值:

      import csv
      
      files = Path(r'path').rglob('*.csv')
      
      for file in files:
          with open(file, "r") as f_in:
              reader = csv.DictReader(f_in)
              for row_dict in reader:
                  p_id = row_dict['id'] = int(row_dict['id']) # Convert `id` to integer
                  all_csvs[p_id].update(row_dict)
      

      现在,all_csvs 看起来像这样:

      defaultdict(<function __main__.default_person()>,
                  {
                   1: {'id': 1, 'name': 'john', 'birth': '01.01.2001', 'death': '-'},
                   2: {'id': 2, 'name': 'mary', 'birth': '05.06.1990', 'death': '01.02.2020'},
                   3: {'id': 3, 'name': 'alex', 'birth': None, 'death': None}
                  })
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-03-08
        • 2022-11-22
        • 1970-01-01
        • 2011-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多