我有两个数据框,仅当第一个数据框的日期在第二个数据框的日期之后出现时,我要遍历“公司”列中每个列表中的元素,并将其与第二个数据框中的公司名称匹配。我想要两列用于名称匹配,两列用于返回日期匹配。
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
答案 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 的旧版本,请从升级开始。
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
因此,如您所见: