将多个csv文件导入pandas并连接到一个DataFrame中

jon*_*nas 319 python csv concatenation dataframe pandas

我想从目录中读取几个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)
Run Code Online (Sandbox Code Playgroud)

我想在for循环中需要一些帮助???

Gau*_*ngh 372

如果您的所有csv文件中都有相同的列,则可以尝试以下代码.我已添加,header=0以便在读取csv第一行后可以指定为列名.

import pandas as pd
import glob

path = r'C:\DRO\DCL_rawdata_files' # 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)
Run Code Online (Sandbox Code Playgroud)

  • 同样的事情更简洁,也许更快,因为它不使用列表:`df = pd.concat((pd_read_csv(f)for all_files中的f))另外,也许应该使用`os.path. join(path,"*.csv")`而不是`path +"/*.csv"`,这使得OS独立. (226认同)
  • @Sid已经做出了这个答案,以便当前的暴行可以失去领先地位. (10认同)
  • @curtisp你仍然可以用Sid的答案做到这一点,只需在生成器中使用`pandas.read_csv(f).assign(filename = foo)`.`assign`将返回整个数据帧,包括新列`filename` (4认同)
  • 这似乎是一种老式的又名手动做事方式,尤其是。由于 Hapood 生态系统有越来越多的工具,您可以直接在包含不同文件类型(csv、json、txt、数据库)的许多不同目录上直接执行 sql 查询,就好像它是一个数据源一样。python 中肯定有类似的东西,因为它在做“大数据”方面已经有 20 年的飞跃了。 (3认同)
  • 使用这个答案允许我添加带有文件名的新列,例如在for file_循环中使用`df ['filename'] = os.path.basename(file_)`..不确定Sid的答案是否允许这样做? (3认同)

Sid*_*Sid 257

替代darindaCoder的答案:

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
Run Code Online (Sandbox Code Playgroud)

  • 我建议使用`glob.iglob`而不是`glob.glob`; 第一个返回和[迭代器(而不是列表)](https://docs.python.org/3/library/glob.html#glob.iglob). (5认同)
  • @Mike @Sid 最后两行可以替换为:`pd.concat((pd.read_csv(f) for f in all_files), ignore_index=True)`。Pandas 版本 0.18.1 需要内括号 (3认同)

Jos*_*n H 45

import glob, os    
df = pd.concat(map(pd.read_csv, glob.glob(os.path.join('', "my_files*.csv"))))
Run Code Online (Sandbox Code Playgroud)

  • 另一方面,如果需要参数,可以使用lambdas:`df = pd.concat(map(lambda file:pd.read_csv(file,delim_whitespace = True),data_files)) (9认同)
  • 优秀的一个班轮,如果不需要read_csv参数,特别有用! (2认同)
  • ^ 或使用 `functools.partial`,以避免 lambda (2认同)

MrF*_*Fun 39

简单快捷

导入两个或多个csv's 而不必列出名称。

import glob
import pandas as pd

df = pd.concat(map(pd.read_csv, glob.glob('data/*.csv')))
Run Code Online (Sandbox Code Playgroud)

  • 我们如何将参数传递给这个语法? (4认同)

Jou*_*nen 25

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

>>> import dask.dataframe as dd
>>> df = dd.read_csv('data*.csv')
Run Code Online (Sandbox Code Playgroud)

(来源:http://dask.pydata.org/en/latest/examples/dataframe-csv.html)

Dask数据帧实现了Pandas数据帧API的子集.如果所有数据都适合内存,则可以调用df.compute()将数据帧转换为Pandas数据帧.


rob*_*smt 22

这里几乎所有的答案都是不必要的复杂(全局模式匹配)或依赖其他第三方库.您可以使用Pandas和python(所有版本)已经内置的所有内容在2行中执行此操作.

对于一些文件 - 1个班轮:

df = pd.concat(map(pd.read_csv, ['data/d1.csv', 'data/d2.csv','data/d3.csv']))
Run Code Online (Sandbox Code Playgroud)

对于许多文件:

from os import listdir

filepaths = [f for f in listdir("./data") if f.endswith('.csv')]
df = pd.concat(map(pd.read_csv, filepaths))
Run Code Online (Sandbox Code Playgroud)

这个设置df的pandas线使用了3个东西:

  1. Python的map(函数,iterable)向函数(the )发送 pd.read_csv()iterable(我们的列表),它是filepaths中的每个csv元素).
  2. Panda的read_csv()函数正常读入每个CSV文件.
  3. Panda的concat()将所有这些带到一个df变量下.

  • 或者只是`df = pd.concat(map(pd.read_csv, glob.glob('data/*.csv))` (3认同)

SKG*_*SKG 12

编辑:我用谷歌搜索到/sf/answers/1486299461/.然而,最近我发现使用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"....]
Run Code Online (Sandbox Code Playgroud)

时间统计:

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 ---
Run Code Online (Sandbox Code Playgroud)

  • 如果数据具有混合列类型,这将不起作用。 (3认同)
  • @SKG 完美..这是我唯一可行的解​​决方案。2 秒内总共 500 个文件 400k 行。感谢您发布它。 (2认同)
  • 5 秒内处理 1500 个文件和 750k 行。优秀@SKG (2认同)

muo*_*uon 12

一个班轮使用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")))
Run Code Online (Sandbox Code Playgroud)

注意:map它本身不允许您提供额外的参数。


tot*_*ico 10

如果要以递归方式搜索(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)
Run Code Online (Sandbox Code Playgroud)

请注意,最后三行可以用一行表示:

df = pd.concat((pd.read_csv(f) for f in iglob(path, recursive=True)), ignore_index=True)
Run Code Online (Sandbox Code Playgroud)

你可以在** 这里找到文档.此外,我使用iglob而不是glob,因为它返回迭代器而不是列表.



编辑:多平台递归函数:

您可以将上述内容包装到多平台功能(Linux,Windows,Mac)中,这样您就可以:

df = read_df_rec('C:\user\your\path', *.csv)
Run Code Online (Sandbox Code Playgroud)

这是功能:

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)
Run Code Online (Sandbox Code Playgroud)


Mil*_*lan 9

灵感来自MrFun回答

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)
Run Code Online (Sandbox Code Playgroud)

笔记:

  1. 默认情况下,生成的文件列表glob.glob是不排序的。另一方面,在许多场景中,需要对其进行排序,例如,人们可能想要分析传感器帧丢失的数量与时间戳。

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

        timestamp    id    valid_frame
    0
    1
    2
    .
    .
    .
    0
    1
    2
    .
    .
    .
    
    Run Code Online (Sandbox Code Playgroud)

    使用ignore_index=True,它看起来像:

        timestamp    id    valid_frame
    0
    1
    2
    .
    .
    .
    108
    109
    .
    .
    .
    
    Run Code Online (Sandbox Code Playgroud)

    IMO,当人们可能想要手动创建帧丢失数量与一分钟(或任何其他持续时间)箱的直方图并且想要基于第一个时间戳进行计算时,这很有帮助,例如 begin_timestamp = df['timestamp'][0]

    如果没有,ignore_index=Truedf['timestamp'][0]会生成包含所有单独数据帧的第一个时间戳的系列,它不仅仅给出一个值。


Nim*_*m J 5

如果多个 csv 文件被压缩,您可以使用 zipfile 读取全部并连接如下:

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)

    
Run Code Online (Sandbox Code Playgroud)


mjs*_*ier 5

另一个具有列表理解的在线,它允许使用 read_csv 的参数。

df = pd.concat([pd.read_csv(f'dir/{f}') for f in os.listdir('dir') if f.endswith('.csv')])
Run Code Online (Sandbox Code Playgroud)


Hen*_*rik 5

使用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)
Run Code Online (Sandbox Code Playgroud)