创建一个标准数据帧以从 Pandas 中的其他数据帧接收数据

Create a standard dataframe to receive data from other dataframes in Pandas

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

请注意,数据框的列名未标准化,某些行中可能包含 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]}

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

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

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

谁能推荐一个优雅的方法来做到这一点?

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]])

让我们尝试创建一个可以与 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