我想从目录中读取几个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循环中需要一些帮助?
灵感来自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.
基于希德的好答案。
识别列缺失或未对齐的问题
在连接之前,您可以将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)。方法将字典中键的大小减少到仅相关的较小部分。
这里几乎所有的答案要么是不必要的复杂(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变量下。
如果你想递归搜索(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)