Pandas Dataframe - 使用基于3个独立条件的部分字符串合并数据集

时间:2018-03-14 20:50:30

标签: python pandas dataframe merge

我试图在每个数据集中基于四位数代码连接两个数据集。一个数据集的代码按不同程度填充(2,3或全部4位数),并根据需要使用尾随零。

其他数据集的代码已完成所有四位数字。

如果CodeA的最后两位数字是00,那么我想加入任何前两位数相同的CodeB。如果只有CodeA的最后一位为0,那么我想加入所有具有相同前三位数的CodeB。如果CodeA全部有四位数字,那么我想加入CodeB中完全相同的代码。

示例:

CodeA data set

Example CodeA   Field1
1   2500    w
2   4110    x
3   2525    y
4   5345    z



CodeB data set
CodeB   Field2
1234    a
2525    b
4113    c
6543    d
5341    e
2522    f
4122    g
5345    h

我希望我的结果数据集如下所示:

Ex  CodeA   Field1  CodeB   Field2
1   2500    w   2525    b
1   2500    w   2522    f
2   4110    x   4113    c
3   2525    y   2525    b
4   5345    z   5345    h

2 个答案:

答案 0 :(得分:0)

如果您知道所有代码都是4位数且0不是有效数字(除了填充),您可以考虑将问题分成3个连接。一个4位数代码到4位代码,一个用于3到3,另一个用于2到2.您可以通过首先将CodeA数据集子集化为没有尾随0,1,0和2 0的数据集来实现此目的。然后将CodeA和CodeB字段分别分别为4位,3位和2位数。分别进行三个连接,然后连接。一个例子如下。 (数据与您的数据不完全相同)。

import pandas as pd

df = pd.DataFrame(data=[[2500, 1],
                         [2525, 2],
                         [5345, 3],
                         [2520, 4]],
                  columns=['CodeA', 'Field1'])
df_2 = pd.DataFrame(data=[[2525, 1],
                          [2532, 2],
                          [5345, 2]],
                    columns=['CodeB', 'Field2'])

df['CodeA'] = df['CodeA'].astype(str)
df_2['CodeB'] = df_2['CodeB'].astype(str)

df_2['CodeB2'] = df_2['CodeB'].str.slice(0, 2)
df_2['CodeB3'] = df_2['CodeB'].str.slice(0, 3)

df['CodeA2'] = df['CodeA'].str.slice(0, 2)
df['CodeA3'] = df['CodeA'].str.slice(0, 3)

df['Use2'] = df['CodeA'].str.slice(2) == '00'
df['Use3'] = (df['CodeA'].str.slice(3) == '0') & (~df['Use2'])

df_use_all = df[(~df['Use2']) & (~df['Use3'])]
df_use_2 = df[df['Use2']]
df_use_3 = df[df['Use3']]

df_use_all = df_use_all.merge(df_2, left_on=['CodeA'], right_on=['CodeB'], how='left')
df_use_2 = df_use_2.merge(df_2, left_on=['CodeA2'], right_on=['CodeB2'], how='left')
df_use_3 = df_use_3.merge(df_2, left_on=['CodeA3'], right_on=['CodeB3'], how='left')

df_all = pd.concat([df_use_all, df_use_2, df_use_3])

答案 1 :(得分:0)

这是collections.defaultdict的一个解决方案。三重合并方法(详见@scomes)是传统算法,但您可能会发现这个更容易维护。

在下面的解决方案中,df1是CodeA数据集,df2是CodeB数据集。

from collections import defaultdict
from itertools import chain

d = defaultdict(list)

# create full set from df2 and test set from df1
full_set = list(zip(df2['CodeB'].astype(str), df2['Field2']))
test_set = set(df1['CodeA'].astype(str).str.rstrip('0'))

# create dictionary of mapping (loopy)
for k in test_set:
    d[k].extend([i for i in full_set if i[0].startswith(k)])

# map dictionary
df1['Mapped'] = df1['CodeA'].astype(str).str.rstrip('0').map(d)

# expand column of list of tuples
lens = list(map(len, df1['Mapped']))

res = pd.DataFrame({'Example': np.repeat(df1['Example'], lens),
                    'CodeA': np.repeat(df1['CodeA'], lens),
                    'Field1': np.repeat(df1['Field1'], lens),
                    'Mapped': list(chain.from_iterable(df1['Mapped']))})

# split column of tuples
res[['CodeB', 'Field2']] = res['Mapped'].apply(pd.Series)

# drop helper column
res = res.drop('Mapped', 1)

<强>结果

   CodeA  Example Field1 CodeB Field2
0   2500        1      w  2525      b
0   2500        1      w  2522      f
1   4110        2      x  4113      c
2   2525        3      y  2525      b
3   5345        4      z  5345      h