【问题标题】:Iterate over list elements in Pandas dataframe column and match with values in a different dataframe遍历 Pandas 数据框列中的列表元素并匹配不同数据框中的值
【发布时间】:2020-04-28 21:55:58
【问题描述】:

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

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

【问题讨论】:

  • 据我了解Companies 列表可能有不同的长度。在这种情况下应该是什么?您将拥有不同数量的列(Name_X)
  • 我认为这个问题与您的问题非常相似:stackoverflow.com/questions/53837685/… 如果df2.Companies in df.Companies,您正在寻找合并数据框。如果日期不在第二个日期之后,您将有一些额外的逻辑来删除输出 df 中的列。

标签: python pandas


【解决方案1】:

从更多的 pandasonic 方式开始在两个 DataFrame 中转换 Date 列 从 stringdatetime:

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)

结果如你所愿。

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

注意:Explode是一个比较新的功能,在Pandas版本中加入 0.25。如果您有旧版本的 Pandas,请从升级它开始。

根据 03:25:19Z 的评论进行编辑

df1 可以有更多列。

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

.drop(columns=['Xxx'])

(一般情况下,将 'Xxx' 替换为实际的附加列列表)。

为了检查输出列数不同的情况,我更改了 日期 对于 df22019-01-06Gold X 公司,这样该公司将 也包含在输出中。

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

  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_3Date_3 列。
  • 至于 df1 的第二行,只找到了 2 个匹配项, 这些列在此处包含 NaNNaTPandas 对应项 )。

【讨论】:

  • 哇,这是一个很好的答案,谢谢!只是一个问题,如果第一个数据框有更多列怎么办?有没有办法在添加名称和日期列时保留它们?
猜你喜欢
  • 2020-12-13
  • 1970-01-01
  • 2018-10-28
  • 2019-03-02
  • 1970-01-01
  • 2020-05-03
  • 1970-01-01
  • 2016-08-13
  • 1970-01-01
相关资源
最近更新 更多