代码之家  ›  专栏  ›  技术社区  ›  mchd

如何将多个CSV文件按Python方式合并为一个[复制]

  •  0
  • mchd  · 技术社区  · 5 年前

    我想从目录中读取几个CSV文件到pandas中,并将它们连接成一个大的DataFrame。不过,我一直没能弄清楚。以下是我目前所掌握的:

    import glob
    import pandas as pd
    
    # Get data file names
    path = r'C:\DRO\DCL_rawdata_files'
    filenames = glob.glob(path + "/*.csv")
    
    dfs = []
    for filename in filenames:
        dfs.append(pd.read_csv(filename))
    
    # Concatenate all data into one DataFrame
    big_frame = pd.concat(dfs, ignore_index=True)
    

    我想我需要一些帮助 对于 循环?

    0 回复  |  直到 4 年前
        1
  •  779
  •   Trenton McKinney ivirshup    4 年前

    请参阅 pandas: IO tools 对于所有可用的 .read_ 方法。

    如果所有CSV文件都有相同的列,请尝试以下代码。

    我已添加 header=0 ,以便在读取CSV文件的第一行后,可以将其指定为列名。

    import pandas as pd
    import glob
    import os
    
    path = r'C:\DRO\DCL_rawdata_files' # use your path
    all_files = glob.glob(os.path.join(path , "/*.csv"))
    
    li = []
    
    for filename in all_files:
        df = pd.read_csv(filename, index_col=None, header=0)
        li.append(df)
    
    frame = pd.concat(li, axis=0, ignore_index=True)
    

    或者,归因于以下评论 Sid .

    all_files = glob.glob(os.path.join(path, "*.csv"))
    
    df = pd.concat((pd.read_csv(f) for f in all_files), ignore_index=True)
    

    • 通常需要识别每个数据样本,这可以通过在数据帧中添加一个新列来实现。
    • pathlib 本例将使用标准库中的。它将路径视为具有方法的对象,而不是要切片的字符串。

    导入和设置

    from pathlib import Path
    import pandas as pd
    import numpy as np
    
    path = r'C:\DRO\DCL_rawdata_files'  # or unix / linux / mac path
    
    # Get the files from the path provided in the OP
    files = Path(path).glob('*.csv')  # .rglob to get subdirectories
    

    选项1:

    • 添加一个具有文件名的新列
    dfs = list()
    for f in files:
        data = pd.read_csv(f)
        # .stem is method for pathlib objects to get the filename w/o the extension
        data['file'] = f.stem
        dfs.append(data)
    
    df = pd.concat(dfs, ignore_index=True)
    

    选项2:

    • 使用以下命令添加具有通用名称的新列 enumerate
    dfs = list()
    for i, f in enumerate(files):
        data = pd.read_csv(f)
        data['file'] = f'File {i}'
        dfs.append(data)
    
    df = pd.concat(dfs, ignore_index=True)
    

    选项3:

    • 使用列表理解创建数据帧,然后使用 np.repeat 添加新列。
      • [f'S{i}' for i in range(len(dfs))] 创建一个字符串列表来命名每个数据帧。
      • [len(df) for df in dfs] 创建长度列表
    • 此选项的归因于此绘图 answer .
    # Read the files into dataframes
    dfs = [pd.read_csv(f) for f in files]
    
    # Combine the list of dataframes
    df = pd.concat(dfs, ignore_index=True)
    
    # Add a new column
    df['Source'] = np.repeat([f'S{i}' for i in range(len(dfs))], [len(df) for df in dfs])
    

    选项4:

    df = pd.concat((pd.read_csv(f).assign(filename=f.stem) for f in files), ignore_index=True)
    

    或

    df = pd.concat((pd.read_csv(f).assign(Source=f'S{i}') for i, f in enumerate(files)), ignore_index=True)
    
        2
  •  363
  •   Community Mohan Dere    9 年前

    替代方案 darindaCoder's answer :

    path = r'C:\DRO\DCL_rawdata_files'                     # use your path
    all_files = glob.glob(os.path.join(path, "*.csv"))     # advisable to use os.path.join as this makes concatenation OS independent
    
    df_from_each_file = (pd.read_csv(f) for f in all_files)
    concatenated_df   = pd.concat(df_from_each_file, ignore_index=True)
    # doesn't create a list, nor does it append to one
    
        3
  •  114
  •   sahinakkaya    5 年前
    import glob
    import os
    import pandas as pd   
    df = pd.concat(map(pd.read_csv, glob.glob(os.path.join('', "my_files*.csv"))))
    
        4
  •  80
  •   Peter Mortensen Pieter Jan Bonestroo    4 年前

    这里几乎所有的答案要么不必要地复杂(glob模式匹配),要么依赖于额外的第三方库。您可以使用Pandas和Python(所有版本)已经内置的所有内容在两行中完成此操作。

    对于几个文件-一行

    df = pd.concat(map(pd.read_csv, ['d1.csv', 'd2.csv','d3.csv']))
    

    对于许多文件

    import os
    
    filepaths = [f for f in os.listdir(".") if f.endswith('.csv')]
    df = pd.concat(map(pd.read_csv, filepaths))
    

    无标题

    如果你想用pd.read_csv更改特定的东西(即没有标头),你可以创建一个单独的函数,并用你的map调用它:

    def f(i):
        return pd.read_csv(i, header=None)
    
    df = pd.concat(map(f, filepaths))
    

    这个设置df的pandas行使用了三件事:

    1. Python's map (function, iterable) 发送到函数( pd.read_csv() )可迭代对象(我们的列表)是每个CSV元素 在文件路径中)。
    2. 熊猫的 read_csv() 函数正常读取每个CSV文件。
    3. 熊猫的 concat() 将所有这些放在一个df变量下。
        5
  •  65
  •   Peter Mortensen Pieter Jan Bonestroo    4 年前

    简单快捷

    导入两个或多个CSV文件,而无需列出名称。

    import glob
    import pandas as pd
    
    df = pd.concat(map(pd.read_csv, glob.glob('data/*.csv')))
    
        6
  •  60
  •   Jouni K. Seppänen    5 年前

    Dask库可以从多个文件中读取数据帧:

    >>> import dask.dataframe as dd
    >>> df = dd.read_csv('data*.csv')
    

    (来源: https://examples.dask.org/dataframes/01-data-access.html#Read-CSV-files )

    Dask数据帧实现Pandas数据帧API的一个子集。如果所有数据都存储在内存中,您可以 call df.compute() 将数据帧转换为Pandas数据帧。

        7
  •  20
  •   Peter Mortensen Pieter Jan Bonestroo    4 年前

    我用谷歌搜索了一下 Gaurav Singh's answer .

    然而,最近我发现使用以下工具进行任何操作都会更快 NumPy 然后将其一次性分配给数据帧,而不是在迭代的基础上操纵数据帧本身,这似乎也适用于此解决方案。

    我真诚地希望任何访问此页面的人都能考虑这种方法,但我不想将这段巨大的代码作为注释附加,使其可读性降低。

    您可以利用NumPy来真正加快数据帧连接。

    import os
    import glob
    import pandas as pd
    import numpy as np
    
    path = "my_dir_full_path"
    allFiles = glob.glob(os.path.join(path,"*.csv"))
    
    
    np_array_list = []
    for file_ in allFiles:
        df = pd.read_csv(file_,index_col=None, header=0)
        np_array_list.append(df.as_matrix())
    
    comb_np_array = np.vstack(np_array_list)
    big_frame = pd.DataFrame(comb_np_array)
    
    big_frame.columns = ["col1", "col2"....]
    

    时间统计:

    total files :192
    avg lines per file :8492
    --approach 1 without NumPy -- 8.248656988143921 seconds ---
    total records old :1630571
    --approach 2 with NumPy -- 2.289292573928833 seconds ---
    
        8
  •  15
  •   Peter Mortensen Pieter Jan Bonestroo    4 年前

    一个使用 map ,但如果您想指定其他参数,可以这样做:

    import pandas as pd
    import glob
    import functools
    
    df = pd.concat(map(functools.partial(pd.read_csv, sep='|', compression=None),
                        glob.glob("data/*.csv")))
    

    注: 地图 这本身并不能让你提供额外的论据。

        9
  •  14
  •   toto_tico    8 年前

    如果你愿意 递归搜索 ( Python 3.5或更高版本 ),您可以执行以下操作:

    from glob import iglob
    import pandas as pd
    
    path = r'C:\user\your\path\**\*.csv'
    
    all_rec = iglob(path, recursive=True)     
    dataframes = (pd.read_csv(f) for f in all_rec)
    big_dataframe = pd.concat(dataframes, ignore_index=True)
    

    请注意,最后三行可以表示为一行 单线 :

    df = pd.concat((pd.read_csv(f) for f in iglob(path, recursive=True)), ignore_index=True)
    

    您可以找到以下文档 ** here 此外,我使用 iglob 而不是 glob ,因为它返回一个 迭代器 而不是列表。



    EDIT:多平台递归函数:

    你可以把上面的包裹成一个 多平台功能 (Linux、Windows、Mac),因此您可以执行以下操作:

    df = read_df_rec('C:\user\your\path', *.csv)
    

    功能如下:

    from glob import iglob
    from os.path import join
    import pandas as pd
    
    def read_df_rec(path, fn_regex=r'*.csv'):
        return pd.concat((pd.read_csv(f) for f in iglob(
            join(path, '**', fn_regex), recursive=True)), ignore_index=True)
    
        10
  •  9
  •   Milan    4 年前

    灵感来自 MrFun s answer :

    import glob
    import pandas as pd
    
    list_of_csv_files = glob.glob(directory_path + '/*.csv')
    list_of_csv_files.sort()
    
    df = pd.concat(map(pd.read_csv, list_of_csv_files), ignore_index=True)
    

    笔记:

    1. 默认情况下,通过生成的文件列表 glob.glob 未排序。另一方面,在许多情况下,需要对其进行排序,例如,可能需要分析传感器帧丢失次数v/s时间戳。

    2. In pd.concat 命令,如果 ignore_index=True 如果未指定,则保留每个数据帧(即列表中的每个单独的CSV文件)的原始索引,主数据帧如下

          timestamp    id    valid_frame
      0
      1
      2
      .
      .
      .
      0
      1
      2
      .
      .
      .
      

      与 ignore_index=真 ,它看起来像:

          timestamp    id    valid_frame
      0
      1
      2
      .
      .
      .
      108
      109
      .
      .
      .
      

      国际海事组织,当人们可能想手动创建一分钟(或任何其他持续时间)的帧数直方图,并希望基于第一个时间戳进行计算时,这很有帮助,例如。 begin_timestamp = df['timestamp'][0]

      没有, ignore_index=真 , df['timestamp'][0] 从所有单独的数据帧中生成包含第一个时间戳的序列,它不仅仅给出一个值。

        11
  •  7
  •   Peter Mortensen Pieter Jan Bonestroo    4 年前

    如果压缩了多个CSV文件,您可以使用 zip文件 全部阅读并连接如下:

    import zipfile
    import pandas as pd
    
    ziptrain = zipfile.ZipFile('yourpath/yourfile.zip')
    
    train = []
    
    train = [ pd.read_csv(ziptrain.open(f)) for f in ziptrain.namelist() ]
    
    df = pd.concat(train)
    
        12
  •  7
  •   Peter Mortensen Pieter Jan Bonestroo    4 年前

    另一个带有列表理解的单行线,允许使用参数 read_csv .

    df = pd.concat([pd.read_csv(f'dir/{f}') for f in os.listdir('dir') if f.endswith('.csv')])
    
        13
  •  6
  •   Henrik    7 年前

    替代使用 pathlib 图书馆(通常比 os.path ).

    这种方法避免了重复使用pandas concat() / apped() .

    来自pandas文档:
    值得注意的是,concat()(以及append())会创建数据的完整副本,并且不断重用此函数会对性能产生重大影响。如果需要在多个数据集上使用该操作,请使用列表理解。

    import pandas as pd
    from pathlib import Path
    
    dir = Path("../relevant_directory")
    
    df = (pd.read_csv(f) for f in dir.glob("*.csv"))
    df = pd.concat(df)
    
        14
  •  4
  •   Peter Mortensen Pieter Jan Bonestroo    4 年前

    基于 Sid's good answer .

    识别缺失或未对齐列的问题

    在连接之前,您可以将CSV文件加载到中间字典中,该字典根据文件名(格式为 dict_of_df['filename.csv'] ). 这样的字典可以帮助您识别异构数据格式的问题,例如列名不对齐时。

    导入模块并定位文件路径:

    import os
    import glob
    import pandas
    from collections import OrderedDict
    path =r'C:\DRO\DCL_rawdata_files'
    filenames = glob.glob(path + "/*.csv")
    

    注: OrderedDict 不是必需的,但它会保持可能对分析有用的文件顺序。

    将CSV文件加载到字典中。然后连接:

    dict_of_df = OrderedDict((f, pandas.read_csv(f)) for f in filenames)
    pandas.concat(dict_of_df, sort=True)
    

    密钥是文件名 f 值是CSV文件的数据帧内容。

    而不是使用 f 作为字典关键字,您还可以使用 os.path.basename(f) 或其他 os.path 将字典中的关键字大小减小到仅相关的较小部分的方法。

        15
  •  2
  •   Gonçalo Peres    5 年前
    import os
    
    os.system("awk '(NR == 1) || (FNR > 1)' file*.csv > merged.csv")
    

    在哪里? NR 和 FNR 表示正在处理的行的编号。

    FNR 是每个文件中的当前行。

    NR == 1 包含第一个文件的第一行(标题),而 FNR > 1 跳过每个后续文件的第一行。

        16
  •  2
  •   Peter Mortensen Pieter Jan Bonestroo    4 年前

    如果发生 未命名 列问题,使用此代码沿x轴合并多个CSV文件。

    import glob
    import os
    import pandas as pd
    
    merged_df = pd.concat([pd.read_csv(csv_file, index_col=0, header=0) for csv_file in glob.glob(
            os.path.join("data/", "*.csv"))], axis=0, ignore_index=True)
    
    merged_df.to_csv("merged.csv")
    
        17
  •  0
  •   neha    5 年前

    你也可以这样做:

    import pandas as pd
    import os
    
    new_df = pd.DataFrame()
    for r, d, f in os.walk(csv_folder_path):
        for file in f:
            complete_file_path = csv_folder_path+file
            read_file = pd.read_csv(complete_file_path)
            new_df = new_df.append(read_file, ignore_index=True)
    
    
    new_df.shape
    
        18
  •  0
  •   westandskif    4 年前

    考虑使用 convtools 库,它提供了大量的数据处理原语,并在后台生成简单的即席代码。 它不应该比熊猫/波兰更快,但有时确实可以。

    例如,您可以将csv文件合并为一个文件以供进一步重用-以下是代码:

    import glob
    
    from convtools import conversion as c
    from convtools.contrib.tables import Table
    import pandas as pd
    
    
    def test_pandas():
        df = pd.concat(
            (
                pd.read_csv(filename, index_col=None, header=0)
                for filename in glob.glob("tmp/*.csv")
            ),
            axis=0,
            ignore_index=True,
        )
        df.to_csv("out.csv", index=False)
    # took 20.9 s
    
    
    def test_convtools():
        table = None
        for filename in glob.glob("tmp/*.csv"):
            table_ = Table.from_csv(filename, header=False)
            if table is None:
                table = table_
            else:
                table = table.chain(table_)
    
        table.into_csv("out_convtools.csv", include_header=False)
    # took 15.8 s
    

    当然,如果你只想获得一个数据帧,而不想写入一个连接文件,这将需要 4.63 s 和 10.9 s 相应地( pandas在这里更快,因为它不需要压缩列来写回 ).

        19
  •  -2
  •   YASH GUPTA    6 年前
    import pandas as pd
    import glob
    
    path = r'C:\DRO\DCL_rawdata_files' # use your path
    file_path_list = glob.glob(path + "/*.csv")
    
    file_iter = iter(file_path_list)
    
    list_df_csv = []
    list_df_csv.append(pd.read_csv(next(file_iter)))
    
    for file in file_iter:
        lsit_df_csv.append(pd.read_csv(file, header=0))
    df = pd.concat(lsit_df_csv, ignore_index=True)
    
        20
  •  -2
  •   Peter Mortensen Pieter Jan Bonestroo    4 年前

    这就是你如何使用 Colaboratory 在 Google Drive :

    import pandas as pd
    import glob
    
    path = r'/content/drive/My Drive/data/actual/comments_only' # Use your path
    all_files = glob.glob(path + "/*.csv")
    
    li = []
    
    for filename in all_files:
        df = pd.read_csv(filename, index_col=None, header=0)
        li.append(df)
    
    frame = pd.concat(li, axis=0, ignore_index=True,sort=True)
    frame.to_csv('/content/drive/onefile.csv')