在单个文件中合并多个CSV文件,并在第一列中添加每个csv的列名

时间:2018-11-16 14:28:05

标签: python-3.x pandas

大家好,我正在尝试这段代码,但是我没有得到想要的输出,请帮助我获得正确的结果。

import os
import glob   
import pandas as pd


path = r'filespath'

all_files = glob.glob(os.path.join(path, "*.csv"))

names = [os.path.basename(x) for x in glob.glob(path+'\*.csv')]

df = pd.DataFrame()

for file_ in all_files:
    file_df = pd.read_csv(file_,sep=';', parse_dates=[0], infer_datetime_format=True,header=None )
    file_df['file_name'] = file_
    df = df.append(file_df)
    print(df)

我想在一个csv文件中添加多个CSV文件,并在第一列中添加csv文件名,如果有人有想法请分享.thanks

2 个答案:

答案 0 :(得分:2)

除非您提供所用csvs的结构和获得的结果,否则我无法完全理解您遇到的问题。

您能否提供一小段csv文件示例以及不想要的结果,以便我们了解问题所在?

举个小例子,您可以在两个示例csv文件上使用df.head(2)

更新

建议的解决方案

这是一个有效的示例,由给出的示例here

提供

我使用的示例是:

df1 = pd.DataFrame(np.asarray([[1, 1], [2, 2]]), columns=['A', 'B'])
df2 = pd.DataFrame(np.asarray([[3, 3], [4, 4]]), columns=['A', 'B'])
df3 = pd.DataFrame(np.asarray([[5, 5], [6, 6]]), columns=['A', 'B'])
df1.to_csv('1.csv')
df2.to_csv('2.csv')
df3.to_csv('3.csv')

生成的csvs:

   A  B
0  1  1
1  2  2

   A  B
0  3  3
1  4  4

   A  B
0  5  5
1  6  6

串联代码:

import os
import glob
import pandas as pd

path = r'.'
all_files = glob.glob(os.path.join(path, "*.csv"))
names = [os.path.basename(x) for x in glob.glob(path+'\*.csv')]
df = pd.DataFrame()

for file_ in all_files:
    file_df = pd.read_csv(file_, index_col=0, header=0)
    file_df['file_name'] = file_
    df = df.append(file_df)
print(df)

串联结果:

   A  B file_name
0  5  5   ./3.csv
1  6  6   ./3.csv
0  1  1   ./1.csv
1  2  2   ./1.csv
0  3  3   ./2.csv
1  4  4   ./2.csv

注意,与您的代码有两个区别:

  1. 标头参数设置为 0 而不是 None
  2. index_col参数设置为 0 而不是“ None”。

说明

我想您遇到的问题与这些参数有关,所以我将解释它们的用法。

假设您有以下csv文件:

,A,B
0,1,1
1,2,2

请注意,第一行是标题,第一行是索引。

使用pandas.read_csv(...)函数时,他们将得到以下结果:

   Unnamed: 0  A  B
0           0  1  1
1           1  2  2

这意味着熊猫将第一列(即索引列)作为常规数据列。 为避免这种情况,可以将 index_col 参数设置为0。
通过这种方式,大熊猫会知道将这一列解析为索引。 因此pandas.read_csv(..., index_col=0)的结果将是以下结果:

   A  B
0  1  1
1  2  2

现在,如果使用这种方法读取几个csv文件,则它们的连接将导致想要的外观,其中不包括它们以前的索引,如我提供的示例所示。

另外,如果我将 header 参数设置为None,则整个第一行将被视为数据,并且我们将收到以下不需要的结果:

     0  1  2
0  NaN  A  B
1  0.0  1  1
2  1.0  2  2

这也会在连接的数据框中导致不良结果。

更新2

(操作员提到,新列包含csv文件的路径,而不是文件的基本名称)

此问题的原因是因为在file_df['file_name'] = file_行中。
您使用了 file _ 来遍历 all_files
实际上, all_files 包含 csv文件的路径
您将文件的基本名称保留在 names 变量中,因此,为了在新列中仅获取csv文件的基本名称,我建议进行以下更改上面显示的代码:

path = r'.'
all_files = glob.glob(os.path.join(path, "*.csv"))
names = [os.path.basename(x) for x in all_files]
df = pd.DataFrame()

for file_, name in zip(all_files, names):
    file_df = pd.read_csv(file_, index_col=0)
    file_df['file_name'] = name
    df = df.append(file_df)
print(df)

我所做的更改是:

  1. 更正了基本名称names = [os.path.basename(x) for x in all_files]
  2. 的解析
  3. 在新列file_df['file_name'] = name中使用了基本名称

答案 1 :(得分:0)

我建议您创建一个读取和附加文件名的函数,然后可以遍历all_files

import pandas as pd
import numpy as np
import os
import glob

path = 'folder'
if not os.path.exists(path):
    os.makedirs(path)


def fun(fn):
    df = pd.read_csv(fn)
    # edit so file_name is the first col
    cols = df.columns.tolist()
    cols = ["file_name"] + cols
    # end edit
    df["file_name"] = fn
    return df[cols]

N = 100
for i in range(10):
    df = pd.DataFrame(np.arange(i*N, (i+1)*N))
    df.to_csv("{}/file_{:02}.csv".format(path, i), index=False)

all_files = sorted(glob.glob(os.path.join(path, "*.csv")))

dfs = [fun(fn) for fn in all_files]
df = pd.concat(dfs, ignore_index=True)
df.to_csv("single_file.csv", index=False)