【问题标题】:Create a standard dataframe to receive data from other dataframes in Pandas创建标准数据框以从 Pandas 中的其他数据框接收数据
【发布时间】:2021-08-01 19:32:28
【问题描述】:

我有一个算法可以在不同的数据库中发出请求并接收数据帧。但是,这些数据库可以彼此不同,并且只发送几列,如下例所示。

请注意,数据框的列名不是标准化的,它可以在某些行中包含 NaN 值。此外,某些列会出现在某些数据框中,而在其他数据框中则不会出现。

由于我需要执行可以连接不同数据库的数据框的操作,我的想法是创建一个标准数据框,其中包含所有可能的列并以 NaN 值开头,如下例所示。

因此,在每次请求时,我都会用接收到的数据帧的列填充标准数据帧。我考虑过通过字典将标准数据框的列名称与数据库数据框的可能名称相关联。

dict{A: [A_1, A_a, A_y], B: [B_3, B_b], C: [C_c, C_w], D: [D_5, D_d]}

字典的想法是因为我需要一种实用的方法来将可能的列名更新为标准数据框的列,因为可能有我尚未映射的新名称。

最后,如果我请求了上面的三个数据帧,我的结果将是以下数据帧。

或者以下,如果我只请求第一个数据帧。

谁能提出一个优雅的方法来做到这一点?

【问题讨论】:

  • 特定帧是否具有优先级,或者它们是否都包含与此处相同的值?
  • 不,最后它们应该被连接起来。值不重复。
  • 相互连接?在您的问题中包含您的预期输出将有助于理解您在寻找什么。
  • 感谢您的建议。我在我的问题中添加了预期的结果。我希望它变得更清楚。

标签: python pandas dataframe dictionary concatenation


【解决方案1】:

让我们尝试创建一个可以与 columns.map 一起使用的映射器:

import numpy as np
import pandas as pd

df1 = pd.DataFrame({'A_1': [1, np.nan, 3, 4, np.nan, 6],
                    'B_3': ['a', 'b', 'c', 'd', np.nan, 'f'],
                    'D_5': ['a', 'b', 'c', 'd', np.nan, 'f']})

df2 = pd.DataFrame({'A_a': [1, np.nan, 3, 4, 5, 6],
                    'B_b': ['a', np.nan, 'c', 'd', 'e', 'f'],
                    'C_c': [1, np.nan, 3, 4, np.nan, 6],
                    'D_d': ['a', np.nan, 'c', 'd', np.nan, 'f']})

df3 = pd.DataFrame({'A_y': [1, np.nan, 3, 4, 5, 6],
                    'C_w': [1, 2, 3, np.nan, 5, 6]})

alias_map = {'A': ['A_1', 'A_a', 'A_y'], 'B': ['B_3', 'B_b'],
             'C': ['C_c', 'C_w'], 'D': ['D_5', 'D_d']}
# Turn alias map into something that works for columns.map
mapper = {new_k: new_v for new_v, lst in alias_map.items() for new_k in lst}

# List of DFs
dfs = [df1, df2, df3]
# Rename Columns
for df in dfs:
    df.columns = df.columns.map(mapper)

# Have Empty DF First with All Columns
default_df = pd.DataFrame(columns=list(alias_map.keys()))

merged = pd.concat((default_df, *dfs)).reset_index(drop=True)
print(merged)

merged:

      A    B    C    D
0   1.0    a  NaN    a
1   NaN    b  NaN    b
2   3.0    c  NaN    c
3   4.0    d  NaN    d
4   NaN  NaN  NaN  NaN
5   6.0    f  NaN    f
6   1.0    a  1.0    a
7   NaN  NaN  NaN  NaN
8   3.0    c  3.0    c
9   4.0    d  4.0    d
10  5.0    e  NaN  NaN
11  6.0    f  6.0    f
12  1.0  NaN  1.0  NaN
13  NaN  NaN  2.0  NaN
14  3.0  NaN  3.0  NaN
15  4.0  NaN  NaN  NaN
16  5.0  NaN  5.0  NaN
17  6.0  NaN  6.0  NaN

只有 1 个 DF

merged = pd.concat((default_df, df1)).reset_index(drop=True)
print(merged)

merged:

     A    B    C    D
0  1.0    a  NaN    a
1  NaN    b  NaN    b
2  3.0    c  NaN    c
3  4.0    d  NaN    d
4  NaN  NaN  NaN  NaN
5  6.0    f  NaN    f

【讨论】:

  • 你的答案就差不多了。问题是我最终可能只请求 df1,并希望将其转换为默认格式。在这种情况下,您的代码不起作用。
  • 只需将 default_df 添加到包含所有必需列的 concat 的开头。见编辑。
  • 完美!这正是我一直在寻找的。谢谢!
【解决方案2】:

IIUC,你可以这样做:

import pandas as pd
import numpy as np
from functools import reduce

df1 = pd.DataFrame({'A_1':[1,np.nan,3,4,np.nan,6],
                   'B_3':['a','b','c','d',np.nan,'f'],
                   'D_5':['a','b','c','d',np.nan,'f']})


df2 = pd.DataFrame({'A_a':[1, np.nan,3,4,5,6],
                   'B_b':['a',np.nan,'c', 'd', 'e','f'],
                   'C_c':[1, np.nan, 3,4,np.nan,6],
                   'D_d':['a',np.nan,'c','d', np.nan,'f']})    

df3 = pd.DataFrame({'A_y':[1,np.nan,3,4,5,6],
                    'C_w':[1,2,3,np.nan,5,6]})

dd = {'A': ['A_1', 'A_a', 'A_y'], 'B': ['B_3', 'B_b'], 'C': ['C_c', 'C_w'], 'D': ['D_5', 'D_d']}

#Invert your custom dictionary 
col_dict = {}
for k, v in dd.items():
    for i in v:
        col_dict[i]=k

#Changed due to comment 
df_out = pd.concat([i.rename(columns=col_dict) for i in [df1,df2,df3]])

df_out 

输出:

     A    B    D    C
0  1.0    a    a  NaN
1  NaN    b    b  NaN
2  3.0    c    c  NaN
3  4.0    d    d  NaN
4  NaN  NaN  NaN  NaN
5  6.0    f    f  NaN
0  1.0    a    a  1.0
1  NaN  NaN  NaN  NaN
2  3.0    c    c  3.0
3  4.0    d    d  4.0
4  5.0    e  NaN  NaN
5  6.0    f    f  6.0
0  1.0  NaN  NaN  1.0
1  NaN  NaN  NaN  2.0
2  3.0  NaN  NaN  3.0
3  4.0  NaN  NaN  NaN
4  5.0  NaN  NaN  5.0
5  6.0  NaN  NaN  6.0

让我们使用切片符号获取第一个数据帧:

ldfs = [df1,df2,df3]        
        
df_out = pd.concat([i.rename(columns=col_dict) for i in ldfs[0:1]])

【讨论】:

  • 这不是我想要的,因为最后我需要连接数据帧。最终的数据框应该是 18 行,而不是相同的 6 行。另外,我测试了您的脚本,如果我只有 df1 并想将其转换为默认数据框,则它不起作用。
  • 但是,如果我只有一个数据框,它将无法工作......
  • @LucasOliveira 如果您只有 [df1] instad of [df1, df2, df3]。此代码仍在运行。
  • 它确实有效,但最终结果是一个没有所有列的数据框,因为 df1 没有 C 列。亨利的答案设法通过创建一个所有可能的默认数据框来解决这个问题列第一。
  • @LucasOliveira 太棒了,很高兴您解决了问题。快乐编码!保持安全并保持健康!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-02
  • 1970-01-01
  • 2017-10-01
  • 1970-01-01
相关资源
最近更新 更多