在Python中合并部分字符串匹配,如Excel VLOOKUP



我有两个数据集:Sales(用于公司名称)&市场营销(联系人和公司名称)。我希望将营销数据集中的公司名称与销售数据集中的公司名称进行匹配,即使(特别是如果)存在部分匹配。

示例数据
sales_df = pd.DataFrame({'CompanyName': ['EDF', 'EDF Business', 'L'Oreal France', 'L'oreal Produits De Luxe Belgilux - Be'],        
marketing_df = pd.DataFrame({'ContactName': ['Eddie', 'Antoine', 'Tracy', 'Iria'],
'Email': ['eddie@edf.fr', 'antoine.g@edf.fr', 'tracy@us.loreal.com', 'iria@loreal.com'],
'CompanyName': ['EDF', 'EDF', 'L'Oréal', 'L’Oreal Produit Luxe France''],
'Industry': ['Energy', 'Energy', 'CPG', 'CPG']})

最终,我将使用一种行为类似于Excel中的VLOOKUP的解决方案,在该解决方案中,我返回与销售数据集中的公司名称匹配或部分匹配的营销数据集的行。这样我就有了公司和联系方式(电子邮件地址&联系人姓名)数据,我可以使用这些数据来了解营销数据集中的哪些联系人属于销售数据集中的公司。

想要的结果

ContactName Email               CompanyName    Industry
0   Eddie       eddie@edf.fr        edf            Energy
1   Antoine     antoine.g@edf.fr    edf            Energy
2   Tracy       tracy@us.loreal.com loreal...      CPG
3   Iria        iria@loreal.com     loreal...      Energy

基本上,我想保留所有联系人级别的数据,只要联系人属于我的销售数据集中的公司。

在这里,我清理我的数据。

# import Pandas
import pandas as pd
# Convert spreadsheets into data frames
marketing_df = pd.read_csv('/Users/me/Desktop/Project Data/Country_MKTG_data.csv')
sales_df = pd.read_csv('/Users/me/Desktop/Project Data/Country_Sales_data.csv')
# Display all rows & drop null values in company name columns  
pd.set_option('display.max_rows', None)
marketing_df['CompanyMKTG'] = marketing_df['CompanyMKTG'].dropna()
sales_df['CompanySales'] = sales_df['CompanySales'].dropna()
# Make all company names lower case   
sales_df['CompanySales'] = sales_df['CompanySales'].str.lower()
marketing_df['CompanyMKTG'] = marketing_df['CompanyMKTG'].str.lower()
# Eliminate unwanted characters & words    
bad_characters = ['-', ',', '.', '?', '~', '/', 'france', 'ltd', 'uk', 'sa', 'sas', 'the', 'spain', 'japan', 'usa', 'la', 'le', 'de']
for element in bad_characters:
marketing_df['CompanyMKTG'] = marketing_df['CompanyMKTG'].str.replace(element, '', case=False)
sales_df['CompanySales'] = sales_df['CompanySales'].str.replace(element, '', case=False)
# Clean white space  
marketing_df['CompanyMKTG'] = marketing_df['CompanyMKTG'].str.rstrip().str.replace(' ', '')
sales_df['CompanySales'] = sales_df['CompanySales'].str.rstrip().str.replace(' ', '')

问题是,在清理数据后,我有麻烦合并我的数据框架使用部分字符串匹配。我尝试了许多不同的方法:合并,连接,使用difflib进行百分比匹配,转换到集合并找到两个集合的交集。

我最新的解决方案是检查两个数据集中的公司名称是否互为子字符串,然后将营销数据集中的公司名称替换为销售数据集中的公司名称。这样,我就可以导出一个新的数据框,其中包含只属于我的销售数据集中的公司的营销联系人。

# Replace company names in MKTG data set
real_comp = sales_df['CompanySales'].tolist()
for i in marketing_df:
if i['CompanyMKTG'].isin(real_comp):
if i['CompanyMKTG'].issubstring(real_comp[real_comp.get_index(i['CompanySales'])]):
if real_comp[real_comp.get_index(i['CompanySales'])].issubstring((i['CompanyMKTG'])):
marketing_df['CompanyMKTG'].replace(real_comp, inplace=True)
i['CompanySales'] = real_comp[real_comp.get_index(i['CompanyMKTG'])]

但是我一直得到TypeError:字符串索引必须是整数

或者使用pd.series.apply

返回部分字符串匹配的行
def get_match(x):
return marketing_df.loc[marketing_df['CompanyMKTG'].str.contains(x, na=False), 'EmailAddress'].iloc[0]
sales_df['Match'] = sales_df['CompanySales'].apply(get_match)
print(sales_df)

但是这样我得到IndexError: single position indexer out- bounds

您得到错误的原因是,当您使用for循环通过DF进行交互时,您以字符串格式获得列的名称,这就是为什么i['CompanyMKTG']抛出错误。

要避免此错误,可以使用iterrows方法遍历行。

for index , row in marketing_df.iterrows()

因为您想通过比较销售数据集公司名称从营销数据集中提取数据。在完成所有清洁过程后,您可以使用以下方法。

marketing_df[marketing_df['CompanyMKTG'].isin(sales_df)]

请注意,对于Dataframe或series,没有issubstring方法。请参考DOC—>https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.isin.html

在IF语句中使用isin()方法会抛出异常/错误,因为o/p是含糊的。如果您想使用多个条件,您可以使用以下命令来验证条件并打印结果营销数据集。

r=[]
for i, row in marketing_df.iterrows():
if row['CompanyMKTG'] in str(sales_df['CompanyMKTG']):
r.append(row['CompanyMKTG'])
marketing_df[marketing_df['CompanyMKTG'].isin(r)] 

最新更新