根据特定列合并多个 CSV 文件 - Python

Posted

技术标签:

【中文标题】根据特定列合并多个 CSV 文件 - Python【英文标题】:Merging multiple CSV files based on specific column - Python 【发布时间】:2021-04-28 04:33:35 【问题描述】:

我正在尝试在 Pandas 中合并大约 101 个 CSV 文件。每个文件都有 2 个时间列和一个“值”列。我想保留 2 次列,因为它们在 CSV 文件中是相同的,然后将 101 个 CSV 中的每一个的“值”列合并到一个新的 CSV 文件中。

使用 pd.merge 我可以使用以下合并 2 个文件

data1 = 'time': ['00:00','01:00','02:00'], 
        'local_time': ['09:30','10:30','11:30'],
        'value': ['265.591','330.766','360.962']

data2 = 'time': ['00:00','01:00','02:00'], 
        'local_time': ['09:30','10:30','11:30'],
        'value': ['521.217','588.034','588.034']

df_1 = pd.DataFrame(data1)
df_2 = pd.DataFrame(data2)
locs = ['_A11','_B10']

df_test = pd.merge(df_1,df_2, on=['time','local_time'], how='inner', suffixes = (locs)
)

print(df_test)

这会产生:

    time local_time value_A11 value_B10
0  00:00      09:30   265.591   521.217
1  01:00      10:30   330.766   588.034
2  02:00      11:30   360.962   588.034

但是,我不太确定如何组合接下来的 99 个 csv 文件,或者这是否是完成这项任务的最佳方式。

我的目标是:

    time local_time value_A11 value_B10 value_B11 ...
0  00:00      09:30   265.591   521.217       123 ...
1  01:00      10:30   330.766   588.034       456 ...
2  02:00      11:30   360.962   588.034       789 ...

任何帮助将不胜感激!

编辑 1:

Colin 的示例有效,但是我一直在将数据帧加载到这样的数组中:

import glob
import os

# create and sort list of file names in folder
fl = glob.glob('*.csv')
sorted_fl = sorted(fl)

# open csv files from list and store in df
df_list = [pd.read_csv(f, header=3) for f in sorted_fl]

#test df
df_list[0]

我想知道如何修改 for 循环以便它可以为数组提供数据?再次感谢!

编辑 2:从答案到编辑 1 的错误

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-144-772c1d15f228> in <module>
     14 # loop through each dataframe and merge it with existing one
     15 for i, df in enumerate(df_list[1:]):
---> 16   df_output = pd.merge(df_list[0], df, on=['time','local_time'], how='inner', suffixes = (['_' + str(i), '_' + str(i+1)]))

~/opt/anaconda3/lib/python3.7/site-packages/pandas/core/reshape/merge.py in merge(left, right, how, on, left_on, right_on, left_index, right_index, sort, suffixes, copy, indicator, validate)
     79         copy=copy,
     80         indicator=indicator,
---> 81         validate=validate,
     82     )
     83     return op.get_result()

~/opt/anaconda3/lib/python3.7/site-packages/pandas/core/reshape/merge.py in __init__(self, left, right, how, on, left_on, right_on, axis, left_index, right_index, sort, suffixes, copy, indicator, validate)
    628         # validate the merge keys dtypes. We may need to coerce
    629         # to avoid incompat dtypes
--> 630         self._maybe_coerce_merge_keys()
    631 
    632         # If argument passed to validate,

~/opt/anaconda3/lib/python3.7/site-packages/pandas/core/reshape/merge.py in _maybe_coerce_merge_keys(self)
   1136                     inferred_right in string_types and inferred_left not in string_types
   1137                 ):
-> 1138                     raise ValueError(msg)
   1139 
   1140             # datetimelikes must match exactly

ValueError: You are trying to merge on object and float64 columns. If you wish to proceed you should use pd.concat

编辑 3

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-3-cce982321079> in <module>
     11 
     12 # change datatype to datetime for first df
---> 13 df['local_time'] = pd.to_datetime(df_list[0]['local_time'])
     14 df['time'] = pd.to_datetime(df_list[0]['time'])
     15 

NameError: name 'df' is not defined

【问题讨论】:

【参考方案1】:

这似乎是一个不错的方法。我只是设置了一些不同的合并和后缀,这样你就可以遍历每个数据帧,如下所示。每个新值列都将合并到 df_test。

编辑:更新代码以配合 OP 的编辑

编辑 2: 修复了 OP 错误的数据类型

import pandas as pd    
import glob
import os

# create and sort list of file names in folder
fl = glob.glob('*.csv')
sorted_fl = sorted(fl)

# open csv files from list and store in df
df_list = [pd.read_csv(f, header=3) for f in sorted_fl]

# change datatype to datetime for first df
df['local_time'] = pd.to_datetime(df_list[0]['local_time'])
df['time'] = pd.to_datetime(df_list[0]['time'])


# loop through each dataframe and merge it with existing one
for i, df in enumerate(df_list[1:]):

  # change datatype to datetime
  df['local_time'] = pd.to_datetime(df['local_time'])
  df['time'] = pd.to_datetime(df['time'])

  df_output = pd.merge(df_list[0], df, on=['time','local_time'], how='inner', suffixes = (['_' + str(i), '_' + str(i+1)]))

#print(df_output)
'''
    time local_time  value_0  value_1  value_2  value_3
0  00:00      09:30  738.591  265.591  521.217  856.217
1  01:00      10:30  217.766  330.766  588.034  346.034
2  02:00      11:30  295.962  360.962  588.034  645.034
'''

【讨论】:

感谢科林。有效!但是,我确实没有提到我正在将所有数据帧加载到一个名为 df_list 的数组中。我需要在 for 循环中进行哪些更改才能使其与数组一起使用?我已经编辑了我的问题以获取完整的详细信息和我的代码。感谢您的帮助! Aaron,我更新了代码以使用您的列表。让我知道它是否有效。 嘿科林,再次感谢您的帮助!我从您提供的代码中得到了很多错误。我已在原始问题的编辑 2 中粘贴了错误,以向您展示我得到了什么。 Aaron,我添加了四行应该可以解决您的错误。确保你只是 pd.to_datetime 的时间和 local_time 的第一个 df 和通过循环的每次迭代 嗨科林。我收到一个新错误,但看起来更好。我尝试定义“df”并将其更改为不同的变量,但没有任何成功。我已将新错误发布到另一个编辑。非常感谢您的帮助!

以上是关于根据特定列合并多个 CSV 文件 - Python的主要内容,如果未能解决你的问题,请参考以下文章

Python中根据文件名和后缀合并csv文件

使用 Python 字典在 Python 中合并 CSV 文件

使用Python Dictionary在Python中合并CSV文件

如何将多个csv按行合并?(不是首尾相接的按列合并)

如何使用 Python Pandas 合并多个 CSV 文件

在 Python 中将 CSV 与不同的列合并