遍历Pandas数据框列中的列表元素,并与其他数据框中的值匹配

时间:2020-01-11 14:35:54

标签: python pandas

我有两个数据框,仅当第一个数据框的日期在第二个数据框的日期之后出现时,我要遍历“公司”列中每个列表中的元素,并将其与第二个数据框中的公司名称匹配。我想要两列用于名称匹配,两列用于返回日期匹配。

df = pd.DataFrame(columns=['Customer','Companies', 'Date'])
df = df.append({'Customer':'Gold', 'Companies':['Gold Ltd', 'Gold X', 'Gold De'], 'Date':'2019-01-07'}, ignore_index=True)
df = df.append({'Customer':'Micro', 'Companies':['Microf', 'Micro Inc', 'Micre'], 'Date':'2019-02-10'}, ignore_index=True)


Customer    Companies                     Date
0   Gold    [Gold Ltd, Gold X, Gold De] 2019-01-07
1   Micro   [Microf, Micro Inc, Micre]  2019-02-10


df2 = pd.DataFrame(columns=['Companies', 'Date'])
df2 = df2.append({'Companies':'Gold Ltd', 'Date':'2019-01-01'}, ignore_index=True)
df2 = df2.append({'Companies':'Gold X', 'Date':'2020-01-07'}, ignore_index=True)
df2 = df2.append({'Companies': 'Gold De', 'Date':'2018-07-07'}, ignore_index=True)
df2 = df2.append({'Companies':'Microf', 'Date':'2019-02-18'}, ignore_index=True)
df2 = df2.append({'Companies':'Micro Inc', 'Date':'2017-09-27'}, ignore_index=True)
df2 = df2.append({'Companies':'Micre', 'Date':'2018-12-11'}, ignore_index=True)

Companies         Date
0   Gold Ltd    2019-01-01
1   Gold X      2020-01-07
2   Gold De     2018-07-07
3   Microf      2019-02-18
4   Micro Inc   2017-09-27
5   Micre       2018-12-11


def match_it(d1, d2):
    for companies in d1['Companies']:
        for company in companies:
            if d2['Companies'].str.contains(company).any():
                mask = d1.Companies.apply(lambda x: company in x)
                dff = d1[mask]
                date1 = datetime.strptime(dff['Date'].values[0], '%Y-%m-%d').date()
                date2 = datetime.strptime(d2[d2['Companies']==company]['Date'].values[0], '%Y-%m-%d').date()

                if date2 < date1:
                    print(d2[d2['Companies']==company])
                    new_row = pd.Series([d2[d2['Companies']==company]['Date'], d2[d2['Companies']==company]['Companies']])
                    return new_row

所需的输出:

Customer    Companies                 Date       Name_1       Date_1      Name_2      Date_2    
Gold    [Gold Ltd, Gold X, Gold De] 2019-01-07   Gold Ltd   2019-01-01  Gold De      2018-07-07
Micro   [Microf, Micro Inc, Micre]  2019-02-10   Micro Inc  2017-09-27  Micre       2018-12-11

1 个答案:

答案 0 :(得分:1)

从更多的pandasonic方法开始,转换两个DataFrame中的 Date 列 从 string 执行 datetime

df.Date = pd.to_datetime(df.Date)
df2.Date = pd.to_datetime(df2.Date)

然后继续进行以下操作:

df3 = df.explode('Companies')
df3 = df3.merge(df2, on='Companies', suffixes=('_x', ''))
df3 = df3[df3.Date_x > df3.Date].drop(columns='Date_x')
df3.rename(columns={'Companies': 'Name'}, inplace=True)
df3['idx'] = df3.groupby('Customer').cumcount()
df3 = df3.pivot(index='Customer',columns='idx')
df3 = df3.swaplevel(axis=1)
df3 = df3.sort_index(axis=1, ascending=[True, False])
cols = []
for i in range(1, df3.columns.size // 2 + 1):
    cols.extend(['Name_' + str(i), 'Date_' + str(i)])
df3.columns = cols
result = df.merge(df3, how='left', left_on='Customer', right_index=True)

结果随心所欲。

要了解详细信息,请分别运行每个指令并打印结果。 最好自己看结果而不是阅读说明。

警告:爆炸是一个相对较新的功能,已在 Pandas 版本中添加 0.25 。如果您使用的是 Pandas 的旧版本,请从升级开始。

按照截至03:25:19Z的评论进行编辑

df1 可以有更多列。

为了测试它,我在 df1 中添加了 Xxx 列。 在这种情况下,所需的唯一更改是阻止这些附加列 从复制到 df3 。为此,第一条指令应附加:

.drop(columns=['Xxx'])

(通常将'Xxx'替换为其他列的实际列表)。

要检查输出列数不同的情况,我更改了 Date 适用于 df2 中的 Gold X 公司至 2019-01-06 ,以便该公司 也包含在输出中。

对于您的数据,经过上述更改,结果为:

  Customer                    Companies       Date   Xxx     Name_1     Date_1  Name_2     Date_2   Name_3     Date_3
0     Gold  [Gold Ltd, Gold X, Gold De] 2019-01-07  Xxx1   Gold Ltd 2019-01-01  Gold X 2019-01-06  Gold De 2018-07-07
1    Micro   [Microf, Micro Inc, Micre] 2019-02-10  Xxx2  Micro Inc 2017-09-27   Micre 2018-12-11      NaN        NaT

因此,如您所见:

  • 结果还包含添加的列( Xxx )。
  • 输出还包含 Name_3 Date_3 列。
  • 对于 df1 中的第二行,仅找到2个匹配项, 这些列在此处包含 NaN NaT Pandas 表示)。