python - 从一个 DataFrame 中的另一个 DataFrame 中搜索值

标签 python pandas dataframe search match

警告 : 你即将看到一个非常。非常糟糕的一段代码。我知道,我只是不知道如何解决它。我尝试了几种替代方案,但我缺乏 Pandas(或 numpy - 也许这是一个更好的替代方案)的经验。你被警告了!
我有两个数据帧,我需要从数据帧二上存在的数据帧一中找到匹配信息。让我演示给你看:

# 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)
你去吧,我在一个循环中有一系列循环,每个循环都遍历相同的数据并增肥一个临时数据帧和一个匹配持有者数据帧。
最后我得到了我的结果:
enter image description here
但是速度太可怕了。我的真实数据帧第一列有 29 列,第二列有 55 列。第一个大约有 10 万条记录,第二个大约有 50 万条记录。现在,在没有 GPU 和 16GB RAM 的 i7 上,这个过程大约需要四个小时。
如果您已经能够呼吸并停止用头撞墙,我会很感激有关如何正确执行此操作的一些想法。
非常感谢!

最佳答案

O(n^2) 操作
向数据帧添加一行需要复制整个数据帧 - 因此一次构建一行数据帧是 O(n^2) 操作,并且非常慢。此外, Series.str.contains 需要检查每个字符串值是否包含它。由于您将每一行与其他每一行进行比较,这也是 O(n^2) 操作。
一般来说,Pandas 中的单行操作表示代码非常慢。
用合并替换 for 循环
您可以执行 SQL 样式的连接来执行您在此处尝试执行的操作。

email_merge = df1.merge(df2, on=["email"], suffixes=("", "_right"))
mobile_merge = df1.merge(df2, left_on=["phone"], right_on=["Mobile"], suffixes=("", "_right"))
landline_merge = df1.merge(df2, left_on=["phone"], right_on=["LandLine"], suffixes=("", "_right"))
第一行在电子邮件字段之间进行连接。第二次加入针对第一种电话。第三次加入针对第二种手机。顺便说一下,你最终会得到很多重复的东西。
然后,您可以将这些数据帧中的每一个连接在一起:
print(pd.concat([email_merge, landline_merge, mobile_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

关于python - 从一个 DataFrame 中的另一个 DataFrame 中搜索值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64162453/

相关文章:

python - 在 Pandas 中保存 csv 文件时如何添加交替空行

python - 用 Pandas 中的另一个值替换某些列中的所有负值

python - 如何使我的类在 Python 中可打印?

python - 在深色主题笔记本上绘制的 Pandas 色轴标签

python - PySpark 中的特征选择

Python Pandas Pivot - 为什么失败

python - 将具有作为字典列表的值的字典转换为 pandas DataFrame

python - 在 pandas 中,如何读取列中包含列表的 csv 文件?

python - self 未在类方法参数中定义

python - 关联规则挖掘算法