如果键是字符串/整数,则在字典中合并多个熊猫数据框

Posted

技术标签:

【中文标题】如果键是字符串/整数,则在字典中合并多个熊猫数据框【英文标题】:Merge multiple pandas data frames in a dictionary if keys are strings/integers 【发布时间】:2018-08-08 23:57:57 【问题描述】:

我使用的数据如下所示:

csv1 = pd.DataFrame('D': [1-10, 2-10, 3-10, 4-10,...], #dates
...:                'C': [#, #, #, #,...] #values

csv2 = pd.DataFrame('D': [3-10, 4-10, 5-10, 6-10,...], #dates
...:                'C': [#, #, #, #,...] #values

csv3 = pd.DataFrame('D': [5-10, 6-10, 7-10, 8-10,...], #dates
...:                'C': [#, #, #, #,...] #values
.
.
.
csv100 = pd.DataFrame('D': [5-10, 6-10, 7-10, 8-10,...], #dates
...:                'C': [#, #, #, #,...] #values

我想要这样的数据框:

df_merged = pd.DataFrame('D': [1-10,2-10,3-10,4-10,5-10,6-10...] #dates
...:                  'C1': [#, #, #, #, #, #...] #values
                      'C2': [#, #, #, #, #, #...] #values
                      'C3': [#, #, #, #, #, #...] #values
                      .
                      .
                      .
                      'C100': [#, #, #, #, #, #] #values

我一直在尝试合并多个数据框,大约 100 个,它们具有相同的列但不同的行(它们没有相同的顺序),我想按“日期”列(合并每行具有相同的日期)。因为数据帧的数量很大,并且随着时间的推移而变化(今天我可以有 110 个,明天我可以有 90 个......),使用循环合并每个数据帧的方法太慢了。通过研究解决方案,我发现共识是使用字典。我将此解决方案应用于我的代码,但出现错误,我不知道如何解决。代码如下

import pandas as pd
import subprocess
import os
from functools import reduce

path=r'C:\Users\ra\Desktop\Px\a' #Folder 'a' path

df =  #Dictionary of data frames from csv files in Folder 'a'
x = [#vector that contains the name of the csv file as string]
i = 0
for j in range(len(x)):
    df['df%s' %j] = (pd.read_csv(os.path.join(path,r'%s.csv' % x[i]))) #Assigns a key to the data frame Ex.:'df1' (the key is a string and I think this is the problem)
    df['df%s' %j].rename(columns='C': '%s' % x[i], inplace=True) #Renames the column 'C' of every data frame to the name of the file
    i += 1

df_merged = reduce(lambda  left,right: pd.merge(left,right,on=['D'],how='outer'),df) #Merges every data frame to a single data frame 'df_merged' by column 'D' that represents the date.

问题出在最后一行,输出如下:

---> df_merged = reduce(lambda  left,right: pd.merge(left,right,on=['D'],how='outer'),df)
.
.
.
ValueError: can not merge DataFrame with instance of type <class 'str'>

如果我将键从字符串更改为整数(通过将向量 x 更改为简单数字 'j'),我会得到以下输出:

---> df_merged = reduce(lambda  left,right: pd.merge(left,right,on=['D'],how='outer'),df)
.
.
.
ValueError: can not merge DataFrame with instance of type <class 'int'>

为了使代码正常工作,我试图找到一种将字符串键转换为名称的方法。但是,显然,这是一种罪过。此外,根据@AnkitMalik,'reduce' 方法不能与字典一起使用。如果字典中的键是字符串/整数,我如何以 Python 的方式将所有这些数据帧按列“D”合并?或者,如果数据帧的数量随时间变化,取决于文件夹“a”中 csv 文件的数量,我该如何制作数据帧的动态列表?

【问题讨论】:

请编辑您的帖子以包含Minimal, Complete, Verifiable Example 可能重复。检查这个:***.com/questions/23668427/… @ManishSaraswat 该链接显示以下列表:dfs = [df0, df1, df2, dfN]。我没有列表,我拥有的是一个看起来像这样的字典:dfs = 'df0', 'df1', 'df2',..., 'dfN'字典中的键是字符串,以便按照@AnkitMalik 的建议制作数据框列表,我必须知道数据帧的数量。但是,它们会随着时间的推移而变化,具体取决于文件夹 'a' 中的 csv 文件数量 为了避免错误,您只需要使用df.values() 而不是df 作为reduce 的最后一个参数。但最好使用pd.concat 代替@the_constant 在their answer 中所说的那样。它更便宜,而且你对列名的痛苦也会减少,因为pd.merge 会给你类似C_x C_y C_x C_y ... 的东西。 【参考方案1】:

reduce 可以处理列表而不是字典。

试试这个:

创建数据框列表 (df)

import pandas as pd
import subprocess
import os
from functools import reduce

path='C:\Users\ra\Desktop\Px\a\'

df = []
x = [#vector that contains the name of the csv files as string]
for j in x:
    df.append(pd.read_csv(path+j+'.csv')) 

df_merged = functools.reduce(lambda left, right: pd.merge(left, right, how= 'outer', on = ['D']), df)

【讨论】:

你能告诉我怎么做吗@Ankit Malik,如果这太简单了,我很抱歉,但我是新手 我已经编辑了我的答案。全部阅读后创建数据框列表。如果它适合您,请接受。 dataframe_list = [df1, df2, df3, .... df100] 这假设我知道我必须合并的数据帧的数量。但是,现实情况是 dataframe_list 将具有动态数量的数据帧,这些数据帧将随时间变化,具体取决于文件夹 a 中的文件数量。 您可以像创建df字典一样创建df列表。请查看最新编辑。 我试过你的代码,它允许我使用 reduce 方法。但是,我得到了一个MemoryError: 输出。在这种情况下,我认为我唯一的选择是连接数据框【参考方案2】:

合并或附加每个 DataFrame 非常昂贵,因此尽可能少地调用非常重要。

但是,您可以做的是,将每个 DataFrame 的日期列设为 DataFrame 的索引,将它们放在一个列表中,然后为所有这些调用 pandas.concat()

您当然必须摆弄列名及其代表的内容,因为除非您希望特定条目成为元组,否则您将拥有一些通用列。

例子:

>>> import pandas
>>> df_0 = pandas.DataFrame(
        
            'a': pandas.date_range('20180101', '20180105'), 
            'b': range(5, 10)
        , 
        index=range(5)
    )
>>> df_0
           a  b
0 2018-01-01  5
1 2018-01-02  6
2 2018-01-03  7
3 2018-01-04  8
4 2018-01-05  9
>>> df_1 = pandas.DataFrame(
        
            'a': pandas.date_range('20180103', '20180107'), 
            'b': range(5, 10)
        , 
        index=range(5)
    )
>>> df_2 = pandas.DataFrame(
        
            'a': pandas.date_range('20180105', '20180109'), 
            'b': range(5, 10)
        , 
        index=range(5)
    )
>>> df_0 = df_0.set_index('a')
>>> df_1 = df_1.set_index('a')
>>> df_2 = df_2.set_index('a')
>>> pandas.concat([df_0, df_1, df_2], axis=1)  # this is where the magic happens
              b    b    b
a
2018-01-01  5.0  NaN  NaN
2018-01-02  6.0  NaN  NaN
2018-01-03  7.0  5.0  NaN
2018-01-04  8.0  6.0  NaN
2018-01-05  9.0  7.0  5.0
2018-01-06  NaN  8.0  6.0
2018-01-07  NaN  9.0  7.0
2018-01-08  NaN  NaN  8.0
2018-01-09  NaN  NaN  9.0

【讨论】:

如果您必须连接多个数据帧以创建列表以使用pandas.concat,您会怎么做@NoticeMeSenpai。例如:如果在上午 11:00您有 90 个名为 [df1, df2,..., df90] 的数据框,在上午 11:10。您有 110 个名为 [df1, df2,..., df110] 的数据框(数据框数量的变化取决于不断更新的文件夹中 csv 文件的数量)。您将如何使用 python 自动创建这样一个动态数据框列表? 如果 df 一旦存在就不会改变(比如,1 总是保持 1,2 总是保持 2),我会编写一个 memoize 类来缓存看到的数据帧的结果,然后使用缓存结果以连接尚未见过的新df。如果 df 不断变化,您别无选择,只能每次重做该过程,而最佳解决方案取决于您拥有的资源(例如将计算并行映射成片段并利用多处理)【参考方案3】:

首先,我要感谢所有帮助我找到解决方案的人。我不得不说这是我第一次在 *** 中发布问题,体验非常好。我还要感谢@AnkitMalik 和@NoticeMeSenpai,因为他们的努力帮助我找到了一个非常好的解决方案。

我的问题是关于使用functools.reduce() 合并dictionary 中的数据框。但是,正如@AnkitMalik 所指出的,这仅适用于lists []。 @NoticeMeSenpai 建议使用 pandas.concat() 来完成这项工作。下面的代码对我有用:

import pandas as pd
import subprocess
import os

path='C:\Users\ra\Desktop\Px\a'

df = [] #makes a list of data frames
x = [#vector that contains the name of the csv files as strings]
for j in x:
    df.append((pd.read_csv(os.path.join(path,r'%s.csv' % j))).set_index('D').rename(columns='C':'%s' % j), axis=1)) #appends every csv file in folder 'a' as a data frame in list 'df', sets the column 'D' as index and renames the column 'C' as the name of csv file.

df_concat = pd.concat(df, axis=1) #concats every data frame in the list 'df'
df_concat.to_csv(os.path.join(path,r'xxx.csv')) # saves the concatenated data frame in the 'xxx' csv file in folder 'a'.

【讨论】:

以上是关于如果键是字符串/整数,则在字典中合并多个熊猫数据框的主要内容,如果未能解决你的问题,请参考以下文章

合并具有非唯一索引的多个熊猫数据集

按行分组时如何合并熊猫数据框的字典

将新的字典值列添加到熊猫数据框

字典列表中的熊猫数组

有效地合并熊猫中的多个数据框[重复]

从多个字典填充熊猫数据框