Python 在另一个数据帧中搜索一个数据帧中的值

Python 在另一个数据帧中搜索一个数据帧中的值,python,pandas,dataframe,search,match,Python,Pandas,Dataframe,Search,Match,警告:您将看到一个非常严重的问题。非常糟糕的代码。我知道,我只是不知道如何修复它。我尝试过几种选择,但我缺乏在熊猫方面的经验(或者说numpy——也许这是一个更好的解释)。你被警告了 我有两个数据帧,我需要从数据帧2上存在的数据帧1中找到匹配信息。让我告诉你: # DataFrame 1 d1 = {'name': ['John Doe', 'Jane Doe'], 'email': ['john@example.com', 'jane@example.com'], 'phone': ['1

警告:您将看到一个非常严重的问题。非常糟糕的代码。我知道,我只是不知道如何修复它。我尝试过几种选择,但我缺乏在熊猫方面的经验(或者说numpy——也许这是一个更好的解释)。你被警告了

我有两个数据帧,我需要从数据帧2上存在的数据帧1中找到匹配信息。让我告诉你:

# DataFrame 1
d1 = {'name': ['John Doe', 'Jane Doe'], 
'email': ['john@example.com', 'jane@example.com'], 
'phone': ['15181111111', '15182222222']}

df1 = pd.DataFrame(data=d1)
###
# DataFrame 2
d2 = {'name': ['Fred Flinstone', 'Barney Rubble', 'Betty Rubble'], 
'email': ['john@example.com', 'barney@example.com', 'betty@example.com'], 
'Mobile': ['15183333333', '15182222222', '15184444444'], 
'LandLine': ['15181111111', '15182222222', '15185555555']}

df2 = pd.DataFrame(data=d2)

因此,我的目标是找出
df2
中的哪些行与
df1
(电子邮件、电话)中可用数据的每一部分(但名称)相匹配。当找到匹配项时,我需要保留来自两个数据帧的所有数据的记录

现在,开始咬指甲,深呼吸,看看我在做什么。它确实有效,但您会很快意识到问题是什么:

# Empty dataframe to store matches
df_found = pd.DataFrame(columns=['df1 Name', 'df1 email', 'df1 phone', 'df2 name', 'df2 email', 'df2 mobile', 'df2 landline'])

# Search for matches
for row_df1 in df1.itertuples():
    tmp_df = df2[df2['email'].str.contains(row_df1.email, na=False, case=False)]
    if(len(tmp_df) > 0):
        for row_df2 in tmp_df.itertuples():
            df_found.loc[len(df_found)] = [row_df1.name, row_df1.email, row_df1.phone, row_df2.name, row_df2.email, row_df2.Mobile, row_df2.LandLine]
    
    tmp_df = df2[df2['Mobile'].str.contains(row_df1.phone, na=False, case=False)]
    if(len(tmp_df) > 0):
        for row_df2 in tmp_df.itertuples():
            df_found.loc[len(df_found)] = [row_df1.name, row_df1.email, row_df1.phone, row_df2.name, row_df2.email, row_df2.Mobile, row_df2.LandLine]
    
    tmp_df = df2[df2['LandLine'].str.contains(row_df1.phone, na=False, case=False)]
    if(len(tmp_df) > 0):
        for row_df2 in tmp_df.itertuples():
            df_found.loc[len(df_found)] = [row_df1.name, row_df1.email, row_df1.phone, row_df2.name, row_df2.email, row_df2.Mobile, row_df2.LandLine]

#Drop duplicates - Yes of course there are many
df_found.drop_duplicates(keep='first',inplace=True)
好了,我在一个循环中有一系列循环,每个循环都遍历相同的数据,并使一个临时数据帧和一个匹配持有者数据帧变得更胖

最后我得到了我的结果:

但是速度太快了。我的真实数据帧第一列有29列,第二列有55列。第一个记录大约有10万条,第二个记录大约有50万条。现在,在我的i7中,在没有GPU和16GB RAM的情况下,这个过程大约需要四个小时

如果你已经可以呼吸了,并且不再把头撞在墙上,我会很感激你能想出一些正确的方法


多谢各位

尝试合并数据帧:

df_found = pd.merge(df1.loc[:, df1.columns != 'name'], df2.loc[:, df2.columns != 'name'], how='inner')
df_found = df_found.merge(df1)
O(n^2)操作 向数据帧中添加一行需要复制整个数据帧-因此一次创建一行数据帧是一个O(n^2)操作,而且速度非常慢。此外,Series.str.contains需要检查每个字符串值是否包含。因为要将每一行与每一行进行比较,所以这也是一个O(n^2)操作

通常,熊猫中的单行操作表示代码非常慢

将for循环替换为merge 您可以执行SQL样式的连接来执行您在这里尝试执行的操作

email\u merge=df1.merge(df2,on=[“email”],后缀=(“”,“\u right”))
mobile_merge=df1.merge(df2,左上=[“phone”],右上=[“mobile”],后缀=(“”,“\u right”))
固定线路合并=df1。合并(df2,左上=[“电话”],右上=[“固定线路”],后缀=(“”,“\u右”))
第一行在电子邮件字段之间进行连接。第二个连接针对第一种手机。第三个连接针对第二种手机。顺便说一句,你最终会有很多复制品这样做

然后,您可以将这些数据帧连接在一起:

print(pd.concat([email\u merge,landline\u merge,mobile\u merge],sort=True))
这给了我以下结果:

      LandLine       Mobile             email         email_right      name      name_right        phone
0  15181111111  15183333333  john@example.com                 NaN  John Doe  Fred Flinstone  15181111111
0  15181111111  15183333333  john@example.com    john@example.com  John Doe  Fred Flinstone  15181111111
1  15182222222  15182222222  jane@example.com  barney@example.com  Jane Doe   Barney Rubble  15182222222
0  15182222222  15182222222  jane@example.com  barney@example.com  Jane Doe   Barney Rubble  15182222222


谢谢你,亚历山德拉。有趣的是,在玩具数据集中,这种方法只找到一个匹配项。少了一对。但谢谢你,我会详细探讨的。谢谢你@Nick。我一定会试试看。我在探索合并,但我没有想到最后的concat!再次感谢!这一直进行得很顺利,直到我的内存用完:)。这是一个相当大的数据集。可能我需要使用的是一次做一个,并在每个步骤后释放内存。