【问题标题】:Looking up multiple dictionary keys in a Pandas Dataframe & return multiple values for matches在 Pandas Dataframe 中查找多个字典键并返回多个匹配值
【发布时间】:2018-08-13 18:16:30
【问题描述】:

第一次发帖,如果我的格式关闭,请提前道歉。

这是我的问题:

我创建了一个包含多行文本的 Pandas 数据框:

d = {'keywords' :['cheap shoes', 'luxury shoes', 'cheap hiking shoes']}
keywords = pd.DataFrame(d,columns=['keywords'])
In [7]: keywords
Out[7]:
        keywords
0  cheap shoes
1  luxury shoes
2  cheap hiking shoes

现在我有一个包含以下键/值的字典:

labels = {'cheap' : 'budget', 'luxury' : 'expensive', 'hiking' : 'sport'}

我要做的是找出字典中的键是否存在于数据框中,如果存在,则返回适当的值

我能够使用以下方法到达那里:

for k,v in labels.items():
   keywords['Labels'] = np.where(keywords['keywords'].str.contains(k),v,'No Match')

但是,输出缺少前两个键,仅捕获最后一个“远足”键

    keywords            Labels
0   cheap shoes         No Match
1   luxury shoes        No Match
2   cheap hiking shoes  sport

此外,我还想知道是否有办法在字典中捕获多个值,用 | 分隔,所以理想的输出应该是这样的

    keywords            Labels
0   cheap shoes         budget
1   luxury shoes        expensive
2   cheap hiking shoes  budget | sport

非常感谢任何帮助或指导。

干杯

【问题讨论】:

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


    【解决方案1】:

    这当然是可能的。这是一种方法。

    d = {'keywords': ['cheap shoes', 'luxury shoes', 'cheap hiking shoes', 'nothing']}
    
    keywords = pd.DataFrame(d,columns=['keywords'])
    
    labels = {'cheap': 'budget', 'luxury': 'expensive', 'hiking': 'sport'}
    
    df = pd.DataFrame(d)
    
    def matcher(k):
        x = (i for i in labels if i in k)
        return ' | '.join(map(labels.get, x))
    
    df['values'] = df['keywords'].map(matcher)
    
    #              keywords          values
    # 0         cheap shoes          budget
    # 1        luxury shoes       expensive
    # 2  cheap hiking shoes  budget | sport
    # 3             nothing                
    

    【讨论】:

    • 上述效果很好,但有一个跟进。您将如何编辑以上内容以仅捕获完全匹配?例如,如果标签更新为包含“便宜”:“预算”,并且第一个关键字更新为“最便宜的廉价鞋”。运行上述脚本会产生预算 |预算作为“最便宜的廉价鞋”的值
    • 字典可能会增长到容纳更多与单个值相关的单词变体。
    • 你应该使用集合来代替,例如return {labels[i] for i in labels if i in k}
    • 上述方法可以很好地从最终结果中删除重复值。不过,我仍然遇到部分匹配的奇怪错误。假设我将利物浦添加到关键字d = {'keywords': ['cheapest cheap shoes', 'luxury shoes', 'cheap hiking shoes', 'liverpool']} 和“池”到标签labels = {'cheape': 'budget','cheap': 'budget', 'luxury': 'expensive', 'hiking': 'sport', 'pool':'swimming'}
    • 会的。谢谢你的帮助,你肯定让我走得更远。非常感谢。
    【解决方案2】:

    您可以使用"|".join(labels.keys()) 获取re.findall() 使用的模式。

    import pandas as pd
    import re
    
    d = {'keywords' :['cheap shoes', 'luxury shoes', 'cheap hiking shoes']}
    keywords = pd.DataFrame(d,columns=['keywords'])
    labels = {'cheap' : 'budget', 'luxury' : 'expensive', 'hiking' : 'sport'}
    pattern = "|".join(labels.keys())
    
    def f(s):
        return "|".join(labels[word] for word in re.findall(pattern, s))
    
    keywords.keywords.map(f)
    

    【讨论】:

      【解决方案3】:

      坚持你的方法,你可以做例如

      arr = np.array([np.where(keywords['keywords'].str.contains(k), v, 'No Match') for k, v in labels.items()]).T
      keywords["Labels"] = ["|".join(set(item[ind if ind.sum() == ind.shape[0] else ~ind])) for item, ind in zip(arr, (arr == "No Match"))]
      
      Out[97]: 
                   keywords        Labels
      0         cheap shoes        budget
      1        luxury shoes     expensive
      2  cheap hiking shoes  sport|budget
      

      【讨论】:

        【解决方案4】:

        我喜欢先使用 replace 然后查找值的想法。

        keywords.assign(
            values=
            keywords.keywords.replace(labels, regex=True)
                    .str.findall(f'({"|".join(labels.values())})')
                    .str.join(' | ')
        )
        
                     keywords          values
        0         cheap shoes          budget
        1        luxury shoes       expensive
        2  cheap hiking shoes  budget | sport
        

        【讨论】:

          【解决方案5】:

          您可以将split 的字符串放入单独的列,然后将stack 放入一个多索引中,这样您就可以将map,标签字典中的值。然后groupby初始索引,concatenate属于每个索引的字符串

          keywords['Labels'] = keywords.keywords.str.split(expand=True).stack()\
                               .map(labels).groupby(level=0)\
                               .apply(lambda x: x.str.cat(sep=' | '))
          
          
          
                      keywords          Labels
          0         cheap shoes          budget
          1        luxury shoes       expensive
          2  cheap hiking shoes  budget | sport
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-07-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-08-14
            相关资源
            最近更新 更多