Pandas - 在加入/合并数据帧之前检查列

时间:2017-10-22 21:30:17

标签: python pandas join dataframe merge

我有一个包含用户的数据框,每个用户都有多个ID:

df_id = pd.DataFrame({'group': ['a','a','b','b','a','a','b','b','a','a','b','b'],
                      'id1': ['erd','hgf','ewr','fgv','nbg','axc','bcv','ijh','plh','wqe','mnf','iud'],
                      'id2': ['dfg','bcw','urz','fwq','nfg','dfo','hiy','fgl','vcw','erq','dfi','vcs']})

df_id

   group  id1  id2
0      a  erd  dfg
1      a  hgf  bcw
2      b  ewr  urz
3      b  fgv  fwq
4      a  nbg  nfg
5      a  axc  dfo
6      b  bcv  hiy
7      b  ijh  fgl
8      a  plh  vcw
9      a  wqe  erq
10     b  mnf  dfi
11     b  iud  vcs

包含部分用户ID的其他2个数据框:

df_1 = pd.DataFrame({'uid1': ['ewr','nbg','hiy','dfg','wqe'],
                   'q': [1,1,0,1,0]
                   })

df_1

   q uid1
0  1  ewr
1  1  nbg
2  0  hiy
3  1  dfg
4  0  wqe

df_2 = pd.DataFrame({'uid2': ['urz','nbg','axc','fgl','vcw'],
                   'q': ['low','high','low','high','high']
                   })

df_2

      q uid2
0   low  urz
1  high  nbg
2   low  axc
3  high  fgl
4  high  vcw

我想根据ID将所有3个合并在一起,但uidx可以匹配id1中的id2df_id,所以我无法加入单列。此外,df_id包含的用户数多于其他两个数据框中的任何一个,因此我预计会有很多NaN

我认为执行此合并/连接的唯一方法是遍历df_id并检查两个id列并手动添加其他数据帧中的值,但这非常慢。如果我要加入的值可以在id列中,那么合并/加入的正确方法是什么?

所需的输出是:

   group  id1  id2  q_1   q_2
0      a  erd  dfg  1.0   NaN
1      a  hgf  bcw  NaN   NaN
2      b  ewr  urz  1.0   low
3      b  fgv  fwq  NaN   NaN
4      a  nbg  nfg  1.0  high
5      a  axc  dfo  NaN   low
6      b  bcv  hiy  0.0   NaN
7      b  ijh  fgl  NaN  high
8      a  plh  vcw  NaN  high
9      a  wqe  erq  0.0   NaN
10     b  mnf  dfi  NaN   NaN
11     b  iud  vcs  NaN   NaN

我的实际数据每个数据框有数百列,其中列名称变化很大,因此我寻找一种不需要单独/手动处理每列的方法。换句话说,我正在寻找一种不需要我手动指定列/数据帧名称的通用方法

2 个答案:

答案 0 :(得分:1)

通常:

df_1 = df_1.set_index('uid1')
q_a = df_id.join(df_1,on='id1')
q_b = df_id.join(df_1,on='id2')
df_id['q_1'] = q_a['q'].fillna(q_b['q'])

在df_2上重复此操作,或者提取一个函数并将其应用于df_2。也许使用iloc来避免使用列名。

答案 1 :(得分:0)

这是一种避免多次合并每个数据帧的方法,方法是将原始数据框的多个id*列堆叠到一个id列中,然后将每个数据帧合并一次。我不能保证你的数据会比更直接的方法更快(但如果不是,请告诉我)。

import numpy as np

# Set some initial arguments (you might do this programmatically instead)
id_cols = ['id1', 'id2']
df_list = [df_1, df_2]
q_list = ['q_{0}'.format(n + 1) for n in range(len(df_list))]

# Make a new df stacking all the id columns
s = df_id[id_cols].stack()
s.name = 'id'
df = pd.DataFrame(s).reset_index()

# Merge each dataframe on the id column once
for n, df_n in enumerate(df_list):
    df_n.rename(columns={'q': 'q_{0}'.format(n + 1)}, inplace=True)
    df = df.merge(df_n, left_on='id', right_on='uid{0}'.format(n + 1), how='left')
    del df['uid{0}'.format(n + 1)]

# If there are multiple values that match, reconcile them
df = df.set_index(['level_0', 'level_1']).unstack(level=-1)
df = df.loc[:, q_list].groupby(level=0, axis=1).max(axis=1).replace({None: np.nan})

# Re-merge with the original dataframe
df_id.merge(df, left_index=True, right_index=True)

这给出了以下结果:

   group  id1  id2  q_1   q_2
0      a  erd  dfg  1.0   NaN
1      a  hgf  bcw  NaN   NaN
2      b  ewr  urz  1.0   low
3      b  fgv  fwq  NaN   NaN
4      a  nbg  nfg  1.0  high
5      a  axc  dfo  NaN   low
6      b  bcv  hiy  0.0   NaN
7      b  ijh  fgl  NaN  high
8      a  plh  vcw  NaN  high
9      a  wqe  erq  0.0   NaN
10     b  mnf  dfi  NaN   NaN
11     b  iud  vcs  NaN   NaN