【问题标题】:Need to match string considering two or more columns instead of one column需要考虑两列或多列而不是一列来匹配字符串
【发布时间】:2022-01-04 06:14:45
【问题描述】:

输入: df1:

Flow Order
Bananas
White Peach 
White Nectarine

df2

Subcategory_Description     Segment_Description     Flow
POTATO                      POTATOES P/P            PP Potato White 4kg
POTATO                      POTATOES P/P            PP Potato White 1.5kg
POTATO                      POTATOES P/P            PP Potato White 2kg
BANANA                      BANANAS OTHER (INC P/P) 5pk Kids Banana
STONE FRUIT                 PEACHES P/P             PP Peach White
STONE FRUIT                 NECTARINES P/P          PP Nectarine White
MANGOES                     KENSINGTON PRIDE        Mango Kp
BANANA                      BANANAS CAVENDISH       Banana
STONE FRUIT                 PEACHES LOOSE           Peach White
STONE FRUIT                 NECTARINES LOOSE        Nectarine
STONE FRUIT                 NECTARINES LOOSE        Nectarine White

场景: 必须从 df2 中获取所有匹配流,以 df1 作为基本流。我已经使用 python 中的 Fuzzywuzzy 库来执行此操作,但这里的问题是它也在考虑部分匹配。例如,在 Flow 的预期输出 - 'White Peach' 中,此处考虑了 White Potato(这不应该发生)。

直到上述场景的 Python 代码如下:

import pandas as pd
from fuzzywuzzy import process

# converting to pandas dataframes
dframe1 = pd.DataFrame(df1['Flow Order'])
dframe2 = pd.DataFrame(df2['Flow'])

# empty lists for storing the matches later
mat1 = []
mat2 = []
p = []

# printing the pandas dataframes
print("First dataframe:\n", dframe1,
    "\nSecond dataframe:\n", dframe2)

# converting dataframe column to list
# of elements
# to do fuzzy matching
list1 = dframe1['Flow Order'].tolist()
list2 = dframe2['Flow'].tolist()

# taking the threshold as 82
threshold = 82

# iterating through list1 to extract
# it's closest match from list2
for i in list1:
    mat1.append(process.extract(i, list2, limit=5))
dframe1['matches'] = mat1

# iterating through the closest matches
# to filter out the maximum closest match
for j in dframe1['matches']:
    for k in j:
        if k[1] >= threshold:
            p.append(k[0])
    mat2.append(",".join(p))
    p = []


# storing the resultant matches back to dframe1
dframe1['matches'] = mat2
print("\nDataFrame after Fuzzy matching:")
print("dframe1:", dframe1)

以上代码输出: dframe1

Flow Order          matches
Bananas             Banana,5pk Kids Banana
White Peach         PP Peach White,Peach White,PP Potato White 4kg,PP Potato White 1.5kg,PP Potato White 2kg
White Nectarine     PP Nectarine White,Nectarine White,Nectarine,PP Potato White 2kg,PP Potato White 1kg 

因此,要包含在上述代码中的想法是考虑 df2 中的“Subcategory_Description”和“Segment_Description”,以单独获得完美匹配流。这两列可用于取出主要名称以使用 fuzzywuzzy 匹配字符串。但我不确定如何包含这些内容。

预期输出:

Flow Order          matches
Bananas             Banana,5pk Kids Banana
White Peach         PP Peach White,Peach White
White Nectarine     PP Nectarine White,Nectarine White,Nectarine

请帮帮我。提前致谢!

【问题讨论】:

    标签: python python-3.x pandas string-matching fuzzywuzzy


    【解决方案1】:

    您可以尝试使用记分器token_sort_ratio(查看code),它会尝试解释类似的乱序字符串。结合您的阈值,它应该可以工作:

    from fuzzywuzzy import fuzz
    process.extract('White Peach', ['PP Peach White','Peach White','PP Potato White 4kg',
                                    'PP Potato White 1.5kg','PP Potato White 2kg'], 
                    scorer=fuzz.token_sort_ratio)
    

    这将给

    [('Peach White', 100),
     ('PP Peach White', 88),
     ('PP Potato White 4kg', 53),
     ('PP Potato White 2kg', 53),
     ('PP Potato White 1.5kg', 50)]
    

    【讨论】:

      【解决方案2】:

      您可以将thefuzz(原fuzzywuzzy 的新名称)与process.extractOne 一起使用。要改进匹配,请使用scorer=fuzz.token_sort_ratio 并设置足够高的截止值(此处为:score_cutoff=80)。理想的截止值应根据经验确定。

      我使用df1df2 作为数据框名称。

      from thefuzz import process, fuzz
      
      match = df2['Flow'].apply(lambda x: out[0] if
                                         (out:=process.extractOne(x, df1['Flow Order'],
                                                                  scorer=fuzz.token_sort_ratio,
                                                                  score_cutoff=80))
                                          else None)
      
      df2.groupby(match).agg(matches=('Flow', ','.join))
      

      输出:

                                                  matches
      Flow                                               
      Bananas                                      Banana
      White Nectarine  PP Nectarine White,Nectarine White
      White Peach              PP Peach White,Peach White
      

      为了帮助确定理想的截止值,您可以运行:

      df2.join(df2['Flow'].apply(lambda x: process.extractOne(x, df1['Flow Order'], 
                                                              scorer=fuzz.token_sort_ratio)
                                 )
                          .rename('match')
               )
      

      输出:

         Subcategory_Description      Segment_Description                   Flow                      match
      0                   POTATO             POTATOES P/P    PP Potato White 4kg       (White Peach, 53, 1)
      1                   POTATO             POTATOES P/P  PP Potato White 1.5kg       (White Peach, 50, 1)
      2                   POTATO             POTATOES P/P    PP Potato White 2kg       (White Peach, 53, 1)
      3                   BANANA  BANANAS OTHER (INC P/P)        5pk Kids Banana           (Bananas, 64, 0)
      4              STONE FRUIT              PEACHES P/P         PP Peach White       (White Peach, 88, 1)
      5              STONE FRUIT           NECTARINES P/P     PP Nectarine White   (White Nectarine, 91, 2)
      6                  MANGOES         KENSINGTON PRIDE               Mango Kp           (Bananas, 27, 0)
      7                   BANANA        BANANAS CAVENDISH                 Banana           (Bananas, 92, 0)
      8              STONE FRUIT            PEACHES LOOSE            Peach White      (White Peach, 100, 1)
      9              STONE FRUIT         NECTARINES LOOSE              Nectarine   (White Nectarine, 75, 2)
      10             STONE FRUIT         NECTARINES LOOSE        Nectarine White  (White Nectarine, 100, 2)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-04-28
        • 2013-05-20
        • 2021-03-02
        • 2018-09-25
        • 1970-01-01
        • 1970-01-01
        • 2021-08-15
        相关资源
        最近更新 更多