ChatGPT解决这个技术问题 Extra ChatGPT

将多个csv文件导入pandas并拼接成一个DataFrame

我想将目录中的几个 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)

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


T
Trenton McKinney

有关所有可用的 .read_ 方法,请参阅 pandas: IO tools

如果您的所有 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] 创建一个长度列表

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

或者

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

同样的事情更简洁,也许更快,因为它不使用列表:df = pd.concat((pd.read_csv(f) for f in all_files)) 此外,也许应该使用 os.path.join(path, "*.csv") 而不是 path + "/*.csv",这使得它独立于操作系统。
C
Community

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

@Mike @Sid 最后两行可以替换为:pd.concat((pd.read_csv(f) for f in all_files), ignore_index=True)。 Pandas 0.18.1 版需要内括号
我建议使用 glob.iglob 而不是 glob.glob;第一个返回和 iterator (instead of a list)
A
Asocia
import glob
import os
import pandas as pd   
df = pd.concat(map(pd.read_csv, glob.glob(os.path.join('', "my_files*.csv"))))

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

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

对于一些文件 - 1 班轮

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

这条设置 df 的 pandas 行利用了 3 个东西:

Python 的映射(函数,可迭代)向函数(pd.read_csv())发送可迭代(我们的列表),它是文件路径中的每个 csv 元素)。 Panda 的 read_csv() 函数正常读取每个 CSV 文件。 Panda 的 concat() 将所有这些都放在一个 df 变量下。


或者只是df = pd.concat(map(pd.read_csv, glob.glob('data/*.csv))
我尝试了@muon 规定的方法。但是,我有多个带有标题的文件(标题很常见)。我不希望它们在数据框中连接起来。你知道我该怎么做吗?我尝试了 df = pd.concat(map(pd.read_csv(header=0), glob.glob('data/*.csv)),但它给出了一个错误“parser_f() 缺少 1 个必需的位置参数:'filepath_or_buffer'”
你问了有一段时间了......但我更新了我的答案以包含没有标题的答案(或者如果你想将任何更改传递给 read_csv)。
m
marcelovca90

简单快捷

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

import glob
import pandas as pd

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

我们如何将参数传递给这种语法?
我的答案:stackoverflow.com/a/69994928/10358768,灵感来自这个特定的答案!
@delimiter,要将文件路径插入到您的文档中,请将“数据”一词替换为您的文件路径,并将 / 保留在末尾。
J
Jouni K. Seppänen

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 数据帧。


与此类似,pandas API 中应该有一个函数用于读取目录中的多个文件。显然它没有它,就像现在一样。
这也适用于 AWS S3 路径吗?
S
SKG

编辑:我用谷歌搜索进入 https://stackoverflow.com/a/21232849/186078。但是最近我发现使用 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 ---

有什么数字可以支持“加速”吗?具体来说,它比 stackoverflow.com/questions/20906474/… 快吗?
我没有看到 OP 要求一种方法来加快他的连接速度,这看起来就像是对预先存在的接受答案的修改。
如果数据具有混合列类型,那将不起作用。
@SKG 完美..这对我来说是唯一可行的解决方案。 2 秒内总共 500 个文件 400k 行。感谢您发布它。
5 秒内 1500 个文件和 750k 行。优秀@SKG
m
muon

一个使用 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 本身不允许您提供额外的参数。


t
toto_tico

如果要递归搜索(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,因为它返回的是 iterator 而不是列表。

编辑:多平台递归函数:

您可以将上述内容包装成一个多平台功能(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)

M
Milan

灵感来自 MrFunanswer

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)

笔记:

默认情况下,通过 glob.glob 生成的文件列表是不排序的。另一方面,在许多情况下,需要对其进行排序,例如,可能需要分析传感器帧丢弃数v/s 时间戳。在 pd.concat 命令中,如果未指定 ignore_index=True ,则它保留每个数据帧(即列表中的每个单独的 CSV 文件)的原始索引,并且主数据帧看起来像时间戳 id valid_frame 0 1 2 。 . . 0 1 2 。 . .使用ignore_index=True,它看起来像:timestamp id valid_frame 0 1 2。 . . 108 109 。 . . IMO,当人们可能想要手动创建帧丢弃数与一分钟(或任何其他持续时间)箱的直方图并希望基于第一个时间戳进行计算时,这很有帮助,例如 begin_timestamp = df['timestamp'] [0] 没有,ignore_index=True, df['timestamp'][0] 生成包含所有单个数据帧的第一个时间戳的系列,它不只给出一个值。


m
mjspier

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

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

S
Skippy le Grand Gourou

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

    

H
Henrik

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

P
Paul Rougieux

基于@Sid 的好答案。

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

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


G
Gonçalo Peres
import os

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

其中 NRFNR 表示正在处理的行号。

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

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


我敢打赌,这比使用 pandas concat 快得多!
C
Chasing Unicorn - Anshu

如果有人遇到未命名列问题,可以使用此代码沿 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")

n
neha

你也可以这样做:

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

w
westandskif

考虑使用 convtools 库,它提供了大量数据处理原语并在后台生成简单的临时代码。它不应该比 pandas/polars 快,但有时可以。

例如,您可以将 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 s10.9 spandas 在这里更快,因为它不需要压缩列来写回 em>)。


Y
YASH GUPTA
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)

S
Shaina Raza

这是在 Google Drive 上使用 Colab 的方法

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