【问题标题】:Partial string match between dataframes, with no overwriting of existing data数据帧之间的部分字符串匹配,不覆盖现有数据
【发布时间】:2017-05-08 12:28:39
【问题描述】:

在我看来,这是一个困难的问题。基本上,我试图根据部分字符串匹配和来自另一个数据帧的分类对一个数据帧中的列进行分类。还有一个复杂的问题是我不想覆盖现有的分类。

我想在以下水果数据框中创建分类:

description                  classification
a phrase about bananas       NaN
a polemic on green apples    NaN
sentence about kumquats      NaN
paragraph about lemons       NaN
a treatise on kiwi fruit     NaN
a sentence on bananas        NaN
a soliloquy on apples        NaN

我正在使用分类数据框执行此操作,其形式为:

keyword          classification
bananas          vitamin K
green apples     too sharp
kiwi fruit       hairy
kumquats         basically inedible
lemons           G&T
apples           nice

我想从分类数据帧中取出关键字,并在水果数据帧描述的描述中搜索它。如果找到,我想将分类数据框中的适当分类添加到水果数据框中。

它变得更加复杂。有时一个关键字包含在另一个关键字中(例如,“apples”也包含在“green apples”中)。为了解决这个问题,我将首先匹配短语,然后是单独的关键字(我将遍历已排序的关键字列表,以便短语排在第一位)。这意味着当我将分类写入水果数据帧时,我需要检查是否已经存在分类,如果有,我将保持它在适当的位置而不是覆盖它。

最终,我会得到这个:

description                  classification
a phrase about bananas       vitamin K
a polemic on green apples    too sharp
sentence about kumquats      basically inedible
paragraph about lemons       G&T
a treatise on kiwi fruit     hairy
a sentence on bananas        vitamin K
a soliloquy on apples        nice

我可以很容易地做到这一点,虽然很混乱,但在程序上就足够了。如何以真正的 Pandas 方式做到这一点?

【问题讨论】:

    标签: python pandas


    【解决方案1】:
    In [95]: pat = '.*\b?({})\b?.*'.format(cl.keyword.str.cat(sep='|'))
    
    In [96]: pat
    Out[96]: '.*(bananas|green apples|kiwi fruit|kumquats|lemons|apples).*'
    
    In [97]: df['classification'] = \
                 df.description.str.replace(pat, r'\1') \
                   .map(cl.set_index('keyword')['classification'])
    

    结果:

    In [98]: df
    Out[98]:
                     description      classification
    0     a phrase about bananas           vitamin K
    1  a polemic on green apples                nice
    2    sentence about kumquats  basically inedible
    3     paragraph about lemons                 G&T
    4   a treatise on kiwi fruit               hairy
    5      a sentence on bananas           vitamin K
    6      a soliloquy on apples                nice
    

    分类 DF:

    In [99]: cl
    Out[99]:
            keyword      classification
    0       bananas           vitamin K
    1  green apples           too sharp
    2    kiwi fruit               hairy
    3      kumquats  basically inedible
    4        lemons                 G&T
    5        apples                nice
    

    【讨论】:

    • 谢谢!我会试试这个。如果关键字列表变大(比如说几千个),这有关系吗?
    • @user4896331,我认为你应该试一试。我自己从未尝试过使用那么大的 RegEx 字符串...
    【解决方案2】:

    我不确定这是否是真正的 Pandas 时尚,但我会将分类 DF 转换为形式为(关键字:分类)的字典,以便快速查找关键字。

    keyword_dict = dict(zip(class_df['keyword'], class_df['values']))
    

    那我就用apply方法填充分类栏:

    def search_keyword(row):
        phrase_words = row['description'].split(' ') # or find a smarter way to split words
        for word in phrase_words:
             if word in keyword_dict:
                 return keyword_dict[word]
    
    fruit_dataframe['classification'] = fruit_dataframe.apply(search_keyword, axis=1)
    

    【讨论】:

    • 谢谢!我会试一试。这种方法会匹配短语以及单个关键字吗?
    • 如果您正确拆分描述列,它可以。也可以尝试在描述中找到关键字,但会比较慢。
    【解决方案3】:

    我终于设法解决了。感谢@AndreyF 和@MaxU 的启发。

    首先,创建一个关键字列表,然后对列表进行排序以将最长的短语放在首位(这有助于处理“青苹果”和“苹果”问题,只要分类没有被覆盖)。

    keyword_list = classification_df['keyword'].tolist()
    keyword_list.sort(key=lambda x: len(x.split()), reverse=True)
    

    从分类_df创建关键字和描述的字典:

    keyword_dict = dict(zip(classification_df['keyword'], classification_df['classification']))
    

    遍历每个关键字,从关键字dict中得到对应的描述。然后将描述写入水果数据框中的适当部分:

    for current_keyword in keyword_list:
        current_description = keyword_dict[current_keyword]
        fruit_dataframe.loc[fruit_dataframe['description'].str.contains(current_keyword) & fruit_dataframe['classification'].isnull(), 'classification'] = current_description
    

    重要的部分是这一行:

    fruit_dataframe.loc[fruit_dataframe['description'].str.contains(current_keyword) & fruit_dataframe['classification'].isnull(), 'classification'] = current_description
    

    它使用两个布尔掩码。第一个查找与水果数据框中的描述匹配的描述,第二个查找为 NaN 的分类。通过在这两个掩码上使用逻辑 &,我最终确定了需要分类的行。

    它似乎有效。

    【讨论】:

      猜你喜欢
      • 2020-11-28
      • 2019-02-15
      • 1970-01-01
      • 1970-01-01
      • 2021-08-22
      • 2019-08-23
      • 2019-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多