Pandas:使用循环和分层索引将多个CSV文件导入数据框架

12
我希望能够从目标文件夹中读取多个CSV文件(列数不同),将它们合并成一个Python Pandas DataFrame以便高效地搜索和提取数据。
示例文件:
Events 
1,0.32,0.20,0.67
2,0.94,0.19,0.14,0.21,0.94
3,0.32,0.20,0.64,0.32
4,0.87,0.13,0.61,0.54,0.25,0.43 
5,0.62,0.21,0.77,0.44,0.16

以下是我目前的进展:

# get a list of all csv files in target directory
my_dir = "C:\\Data\\"
filelist = []
os.chdir( my_dir )
for files in glob.glob( "*.csv" ) :
    filelist.append(files)

# read each csv file into single dataframe and add a filename reference column 
# (i.e. file1, file2, file 3) for each file read
df = pd.DataFrame()
columns = range(1,100)
for c, f in enumerate(filelist) :
    key = "file%i" % c
    frame = pd.read_csv( (my_dir + f), skiprows = 1, index_col=0, names=columns )
    frame['key'] = key
    df = df.append(frame,ignore_index=True)

索引不正常工作。

基本上,下面的脚本完全符合我的要求(经过尝试和测试),但需要循环遍历10个或更多的CSV文件:

df1 = pd.DataFrame()
df2 = pd.DataFrame()
columns = range(1,100)
df1 = pd.read_csv("C:\\Data\\Currambene_001y09h00m_events.csv", 
                  skiprows = 1, index_col=0, names=columns)
df2 = pd.read_csv("C:\\Data\\Currambene_001y12h00m_events.csv", 
                  skiprows = 1, index_col=0, names=columns)
keys = [('file1'), ('file2')]
df = pd.concat([df1, df2], keys=keys, names=['fileno'])

我找到了很多相关的链接,但是我仍然不能让它正常运行:


pandas.concat 可以让你使用一个包含任意长度的 DataFrame 列表。将第一个参数设置为一个包含所有文件的单个列表,就不必再循环脚本了。 - dmvianna
1个回答

15

您需要决定要在哪个轴上添加文件。Pandas 将始终尝试按照以下方式正确处理:

  1. 假设每个文件中的每列都不同,并在必要时向跨文件具有相似名称的列追加数字,以避免混淆;
  2. 属于不同文件中相同行索引的项目会并排放置在各自的列下面。

高效地添加文件的技巧是将它们旋转,以便所得到的行为与 pandas.concat 所执行的行为匹配。这是我的建议:

from pandas import *
files = !ls *.csv # IPython magic
d = concat([read_csv(f, index_col=0, header=None, axis=1) for f in files], keys=files)

请注意,read_csv 使用 axis=1 进行转置,因此它将在列轴上连接,并保留其名称。如果需要,您可以使用 d.T 将结果 DataFrame 转置回来。

编辑:

对于每个源文件中的列数不同的情况,您需要提供一个标题。我知道您的源文件中没有标题,因此让我们使用一个简单的函数创建一个标题:

def reader(f):
    d = read_csv(f, index_col=0, header=None, axis=1)
    d.columns = range(d.shape[1])
    return d

df = concat([reader(f) for f in files], keys=files)

当每行具有相同数量的列时,它可以完美地工作。对于不同的列长度,有什么建议吗?d = pd.concat([(read_csv((TP_dir + f), index_col=0, header=0).T) for f in filelist], keys=filelist) - mellover
1
这是一个不错的IPython技巧!... 你不能使用axis=1来进行连接以避免.T吗? - Andy Hayden
@mellover,请为它添加一个标题。可以从文件中获取,也可以像你的脚本一样作为范围。 - dmvianna
@AndyHayden,是的!当我尝试使用concataxis=1时失败了,可能是因为我使用的是pandas 0.12版本或者其他错误。现在它可以工作了。 :) - dmvianna
调整后完美运行。谢谢。 - mellover

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接