我想从目录中读取几个CSV文件到熊猫,并将它们连接到一个大的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)

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


所有可用的.read_方法参见pandas: IO工具。

如果所有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。重复此操作以添加新列。 [f' s {i}' for i in range(len(dfs))]创建一个字符串列表来命名每个数据帧。 [len(df) for df in dfs]创建一个长度列表 这个选项的归属归属于这个绘图答案。

# 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:

一行代码使用.assign创建新列,并将其归属于来自C8H10N4O2的注释

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

or

df = pd.concat((pd.read_csv(f).assign(Source=f'S{i}') for i, f in enumerate(files)), ignore_index=True)

我在谷歌上找到了高拉夫·辛格的答案。

然而,到最近为止,我发现使用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 ---

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

如果多个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)

import glob
import os
import pandas as pd   
df = pd.concat(map(pd.read_csv, glob.glob(os.path.join('', "my_files*.csv"))))

如果你想递归搜索(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)

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



编辑:多平台递归功能:

你可以把上面的内容包装成一个多平台函数(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)

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的一个子集。如果所有的数据都适合内存,你可以调用df.compute()将数据帧转换为Pandas数据帧。


这里几乎所有的答案要么是不必要的复杂(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(即,没有头),你可以创建一个单独的函数,并调用你的地图:

def f(i):
    return pd.read_csv(i, header=None)

df = pd.concat(map(f, filepaths))

这条pandas行,它设置了df,利用了三个东西:

Python的map (function, iterable)发送给函数(the pd.read_csv())迭代对象(我们的列表),它是每个CSV元素 在filepaths)。 Panda的read_csv()函数正常读取每个CSV文件。 Panda的concat()将所有这些都放在一个df变量下。


使用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")))

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


另一个带有列表理解的一行程序,允许使用read_csv参数。

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

简单快捷

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

import glob
import pandas as pd

df = pd.concat(map(pd.read_csv, glob.glob('data/*.csv')))

基于希德的好答案。

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

在连接之前,您可以将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.basename(f)。方法将字典中键的大小减少到仅相关的较小部分。


可选择使用pathlib库(通常优先于os.path)。

该方法避免了重复使用pandas concat()/ apping()。

从熊猫文档中可以看到: 值得注意的是,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)

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)

这是如何使用协作实验室谷歌驱动器:

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')

你也可以这样做:

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

import os

os.system("awk '(NR == 1) || (FNR > 1)' file*.csv > merged.csv")

其中NR和FNR表示正在处理的行号。

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

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


如果出现未命名列的问题,请使用此代码沿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")

灵感来自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)

注:

By default, the list of files generated through glob.glob is not sorted. On the other hand, in many scenarios, it's required to be sorted e.g. one may want to analyze number of sensor-frame-drops v/s timestamp. In pd.concat command, if ignore_index=True is not specified then it reserves the original indices from each dataframes (i.e. each individual CSV file in the list) and the main dataframe looks like timestamp id valid_frame 0 1 2 . . . 0 1 2 . . . With ignore_index=True, it looks like: timestamp id valid_frame 0 1 2 . . . 108 109 . . . IMO, this is helpful when one may want to manually create a histogram of number of frame drops v/s one minutes (or any other duration) bins and want to base the calculation on very first timestamp e.g. begin_timestamp = df['timestamp'][0] Without, ignore_index=True, df['timestamp'][0] generates the series containing very first timestamp from all the individual dataframes, it does not give just a value.


考虑使用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秒和10.9秒(pandas在这里更快,因为它不需要压缩列来写入回)。