在dataframe python列中搜索单词

在dataframe python列中搜索单词,python,regex,pandas,Python,Regex,Pandas,我有两个文本栏,我想知道一个栏中的单词是否出现在另一个栏中。我编写了下面的代码,它工作得很好,但是它可以检测字符串中是否存在单词。例如,它将在“ham”中找到“ha”。我想改用正则表达式,但我被卡住了。我遇到了这个问题,并查看了第二个答案,但我无法根据自己的目的修改它。我想做类似的事情 我将非常感谢您的帮助和/或任何指点 d = {'emp': ['abc d. efg', 'za', 'sdfadsf '], 'vendor': ['ABCD enterprise', 'za industri

我有两个文本栏,我想知道一个栏中的单词是否出现在另一个栏中。我编写了下面的代码,它工作得很好,但是它可以检测字符串中是否存在单词。例如,它将在“ham”中找到“ha”。我想改用正则表达式,但我被卡住了。我遇到了这个问题,并查看了第二个答案,但我无法根据自己的目的修改它。我想做类似的事情

我将非常感谢您的帮助和/或任何指点

d = {'emp': ['abc d. efg', 'za', 'sdfadsf '], 'vendor': ['ABCD enterprise', 'za industries', '' ]}
df = pd.DataFrame(data=d)
df['clean_empy_name']=df["emp"].str.lower().str.replace('\W', ' ')

def check_subset(vendor, employee):
    s = []
    for n in employee.split():
      # n=" " + n +"[^a-zA-Z\d:]"
      if ((str(n) in vendor.lower()) & (len(str(n))>1)):
        s.append(n)
    return s

check_subset("ABC-xy 54", "54 xy")

df['emp_name_find_in_vendor'] = df.apply(lambda row: check_subset(row['vendor'],row['clean_empy_name']), axis=1)
df
#########更新2 我更新了我的数据框,如下所示

d = {'emp': ['abc d. efg', 'za', 'sdfadsf ','abc','yuma'], 'vendor': ['ABCD enterprise', 'za industries', '','Person Vue\Cisco','U OF M CONTLEARNING' ]}
df = pd.DataFrame(data=d)
df['clean_empy_name']=df["emp"].str.lower().str.replace('\W', ' ')
我使用了第一个答案提供的代码,但失败了

  • 'Person Vue\Cisco'
    的情况下,它会抛出错误
    错误:错误转义\c
    。如果我在
    'Person Vue\Cisco'
    中删除\项,代码运行正常
  • 如果出现
    'U of M CONTLEARNING'
    时,当它们明显不匹配时,将返回
    U
    M

  • 是的,你可以!这将有点混乱,所以让我分几个步骤来构建:

    首先,让我们为
    check_子集(“ABC xy 54”,“54 xy”)
    的单个案例创建一个正则表达式:

    • 我们将使用
      re.findall(pattern,string)
      string
    • 正则表达式模式基本上会说“任意单词”:
      • 对于“any”,我们使用
        |
        (或)运算符
      • 为了构造单词,我们需要使用括号将单词分组。。。然而,括号
        (word)
        创建了一个跟踪的组,因此我们可以稍后调用重用这些组,因为我们不感兴趣,我们可以通过添加
        ?:
        创建一个非捕获组,如下所示:
        (?:word)
    重新导入
    关于findall('(?:54)|(?:xy)'ABC xy 54')
    #->['xy','54']
    
    现在,我们必须每次构造
    模式

    • 分词
    • 将每个单词包装在非捕获组中
      (?:)
    • 通过
      |
    re.findall(“|”).join([”(?:“+x+”)”表示“54 xy.split()”)中的x,'ABC xy 54')
    
    一个次要的问题是,由于最后一行的供应商是空的,并且您似乎不希望匹配(从技术上讲,空字符串与所有内容都匹配),因此我们必须添加一个次要检查。因此,我们可以将您的函数重写为:

    def check_subset_regex(vendor, employee):
        if vendor == '':
            return []
    
        pattern = '|'.join(['(?:'+x+')' for x in vendor.lower().split(' ')])
        return re.findall(pattern, employee)
    
    然后我们可以用同样的方法:

    df['emp_name_find_in_vendor_regex'] = df.apply(lambda row: check_subset_regex(row['vendor'],row['clean_empy_name']), axis=1)
    
    最后一点意见是,您的解决方案匹配部分单词,因此员工Tom Sawyer将“Tom”与供应商“Atomic S.A.”匹配。我在这里提供的正则表达式函数不会将此作为匹配项,如果您想这样做,正则表达式将变得更加复杂


    编辑:删除供应商的标点符号

    您可以像对clean_employee所做的那样添加一个新列,也可以简单地将删除操作添加到函数中(您需要
    导入字符串
    ,以获取
    字符串。标点符号
    ,或者只需在其中添加一个包含所有要替换符号的字符串):

    本着教鱼的精神:),在正则表达式中,
    []
    表示这些字符中的任何一个。。。因此,
    [abc]
    将与
    a | b | c
    相同

    因此,
    re.sub
    行将用
    '
    (其计算结果为
    !“\$%&\'()*+,-./:;?@[\]^ `{{124}
    )字符替换出现的
    '
    )字符(删除它们)


    EDIT2:在每个搜索词的末尾添加一个非字母数字字符:

    def check_subset_regex(vendor, employee):
        if vendor == '':
            return []
    
        clean_vnd = re.sub('[' + string.punctuation + ']', '', vendor)
    
        pattern = '|'.join(['(?:'+x+'[^a-zA-Z0-9]?)' for x in clean_vnd.lower().split(' ')])
        return re.findall(pattern, employee)
    
    在本例中,我们使用:
    -
    ^
    作为
    []
    (称为字符类)中的第一个字符,表示除字符类中指定的字符以外的任何字符,例如
    [^abc]
    将匹配任何非
    a
    b
    c
    (因此
    d
    ,或空白,或
    ) -和
    ,这意味着前面的符号是可选的


    所以,
    [^a-zA-Z0-9]?
    表示可选的单个非字母数字字符。

    我不希望在“原子”中找到“Tom”。您的解决方案看起来不错。让我理解它,我会接受它。感谢您的解释……这有助于……教我如何钓鱼!在
    检查子集正则表达式(“ABC xy 54!”,“54 xy”)的情况下,它不起作用
    …当我进行搜索时,我可以使用特殊字符,因为它们可能表示句子的结尾或问题的结尾等。@Ni_Tempe在这种情况下,它不匹配,因为我们尚未从供应商处清除标点符号。是否要清除所有标点符号?我们可以先清除所有特殊字符。但我很好奇我们可以做一些类似于
    “search\u word=”“+search\u word+”[^a-zA-Z\d:]“
    然后
    str.findall(search\u word)
    的事情吗?你的意思是在单词末尾添加特殊字符的可能性?当然可以,请参见EDIT2:)
    def check_subset_regex(vendor, employee):
        if vendor == '':
            return []
    
        clean_vnd = re.sub('[' + string.punctuation + ']', '', vendor)
    
        pattern = '|'.join(['(?:'+x+'[^a-zA-Z0-9]?)' for x in clean_vnd.lower().split(' ')])
        return re.findall(pattern, employee)