【问题标题】:Find matching similar keywords in Python Dataframe在 Python Dataframe 中查找匹配的相似关键字
【发布时间】:2020-07-31 23:59:06
【问题描述】:
joined_Gravity1.head()
Comments
____________________________________________________
0   Why the old Pike/Lyrik?
1   This is good
2   So clean
3   Looks like a Decoy
Input: type(joined_Gravity1)
Output: pandas.core.frame.DataFrame

以下代码允许我选择包含关键字的字符串:“ender”

joined_Gravity1[joined_Gravity1["Comments"].str.contains("ender", na=False)]

输出:

Comments
___________________________
194 We need a new Sender ????
7   What about the sender
179 what about the sender?????

如何修改代码以包含类似于“Sender”的单词,例如“snder”、“bender”?

【问题讨论】:

    标签: python python-3.x regex list regex-group


    【解决方案1】:

    我看不出contains 函数中的regex=True 在这里不起作用的原因。

    joined_Gravity1[joined_Gravity1["Comments"].str.contains(pat="ender|snder|bndr", na=False, regex=True)]
    

    我只使用过"ender|snder|bnder"。你可以列出所有这样的词,比如list_words,然后在上面的contains函数中传入pat='|'.join(list_words)

    https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.contains.html

    【讨论】:

      【解决方案2】:

      这些单词中的字母组合可能会出现大量可能性。您要做的是 2 个字符串之间的模糊匹配。我可以推荐使用以下 -

      #!pip install fuzzywuzzy
      from fuzzywuzzy import fuzz, process
      
      word = 'sender'
      others = ['bnder', 'snder', 'sender', 'hello']
      
      process.extractBests(word, others)
      
      [('sender', 100), ('snder', 91), ('bnder', 73), ('hello', 18)]
      

      基于此,您可以决定选择哪个阈值,然后将高于阈值的阈值标记为匹配项(使用您上面使用的代码)

      这是在您的确切问题陈述中使用函数执行此操作的方法 -

      df = pd.DataFrame(['hi there i am a sender', 
                         'I dont wanna be a bnder', 
                         'can i be the snder?', 
                         'i think i am a nerd'], columns=['text'])
      
      #s = sentence, w = match word, t = match threshold
      def get_match(s,w,t):
          ss = process.extractBests(w,s.split())
          return any([i[1]>t for i in ss])
      
      #What its doing - Match each word in each row in df.text with 
      #the word sender and see of any of the words have a match greater 
      #than threshold ratio 70.
      df['match'] = df['text'].apply(get_match, w='sender', t=70)
      print(df)
      
      
                            text  match
      0   hi there i am a sender   True
      1  I dont wanna be a bnder   True
      2      can i be the snder?   True
      3      i think i am a nerd  False
      

      如果您想要更精确的匹配,则将 t 值从 70 调整到 80,或者更轻松地匹配更低。

      终于可以过滤掉了-

      df[df['match']==True][['text']]
      
                            text
      0   hi there i am a sender
      1  I dont wanna be a bnder
      2      can i be the snder?
      

      【讨论】:

      • df['match'] = df['text'].apply(get_match, w='sender', t=70) 是否可以在位置 w?我尝试了以下方法: 1. df['match'] = df['text'].apply(get_match, w=('sender','slx'), t=70) 2. df['match'] = df['text'].apply(get_match, w=['sender','slx'], t=70) 3. w = ['sender','slx','clx'] df['match'] = df['text'].apply(get_match, w, t=70) 这三个都不起作用。这里的“发件人”是可以进一步细分为产品类型的产品类别。
      • 我不确定您在这里需要什么。您想按 Sender 或 Slx 分隔句子吗?或者您想要句子中同时包含发件人和 Slx 部分的句子?
      • 此外,它不会匹配ofcourse,因为fuzzywuzzy文档清楚地说明它使用目标词来匹配选择列表。它不会将单词列表与选择列表匹配。您可以轻松修改函数以操作单词列表而不是 1
      【解决方案3】:
      from difflib import get_close_matches 
      
      def closeMatches(patterns, word): 
           print(get_close_matches(word, patterns)) 
      
       list_patterns = joined_Gravity1[joined_Gravity1["Comments"].str.contains("ender", na=False)]
      
       word = 'Sender'
       patterns = list_patterns
       closeMatches(patterns, word) 
      

      【讨论】:

      • 这没有达到 OP 的要求。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-24
      • 1970-01-01
      • 2021-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多