映射 str.contains 跨 pandas DataFrame

Posted

技术标签:

【中文标题】映射 str.contains 跨 pandas DataFrame【英文标题】:map str.contains across pandas DataFrame 【发布时间】:2018-07-13 09:58:17 【问题描述】:

python 初学者 - 我正在寻找创建字符串的字典映射,以及相关的值。我有一个数据框,想创建一个新列,如果字符串匹配,它将列标记为 x。

df = pd.DataFrame('comp':['dell notebook', 'dell notebook S3', 'dell notepad', 'apple ipad', 'apple ipad2', 'acer chromebook', 'acer chromebookx', 'mac air', 'mac pro', 'lenovo x4'],
              'price':range(10))

例如,我想使用上面的df 并创建一个新列df['company'] 并将其设置为字符串映射。

我正在考虑做类似的事情

product_map = 'dell':'Dell Inc.',
               'apple':'Apple Inc.',
               'acer': 'Acer Inc.',
               'mac': 'Apple Inc.',
               'lenovo': 'Dell Inc.'

然后我想遍历它以检查df.comp 列并查看每个条目是否包含这些字符串之一,并将df.company 列设置为字典中的值。

但不确定如何正确执行此操作。

【问题讨论】:

类似:***.com/questions/48510405/… @pault 我将更新我的示例,因为您的解决方法不是我要解决的问题。不过谢谢你的建议。 所以 'dell notebook' 应该替换为 'Dell Inc.'还是“戴尔公司笔记本”? 不应该被替换,新列df['Company']应该填充Dell Inc.,因为key在字符串dell notebook 以下@aquil.abdullah 的解决方案不能实现您的目标吗? 【参考方案1】:

有很多方法可以做到这一点。一种方法如下:

def like_function(x):
    group = "unknown"
    for key in product_map:
        if key in x:
            group = product_map[key]
            break
    return group

df['company'] = df.comp.apply(like_function)

【讨论】:

这很接近但并不完全正确,因为我正在寻找 key, value 对中的 value 作为输出结果。 您可能已经猜到了,但我疯狂地更改为返回值而不是 product_map 的键。【参考方案2】:

这是一个有趣的方法,特别是如果你正在学习 python。您可以继承 dict 并覆盖 __getitem__ 以查找部分字符串。

class dict_partial(dict):
    def __getitem__(self, value):
        for k in self.keys():
            if k in value:
                return self.get(k)
        else:
            return self.get(None)

product_map = dict_partial('dell':'Dell Inc.', 'apple':'Apple Inc.',
                            'acer': 'Acer Inc.', 'mac': 'Apple Inc.',
                            'lenovo': 'Dell Inc.')

df['company'] = df['comp'].apply(lambda x: product_map[x])

               comp  price     company
# 0     dell notebook      0   Dell Inc.
# 1  dell notebook S3      1   Dell Inc.
# 2      dell notepad      2   Dell Inc.
# 3        apple ipad      3  Apple Inc.
# 4       apple ipad2      4  Apple Inc.
# 5   acer chromebook      5   Acer Inc.
# 6  acer chromebookx      6   Acer Inc.
# 7           mac air      7  Apple Inc.
# 8           mac pro      8  Apple Inc.
# 9         lenovo x4      9   Dell Inc.

我对这种方法唯一的烦恼是子类化dict 不会同时覆盖dict.get[] 语法。如果这是可能的,我们可以摆脱lambda 并使用df['comp'].map(product_map.get)。似乎没有明显的解决方案。

【讨论】:

我认为您的dict - 'mac': 'Apple Inc.' 中缺少一个元素。 @pault,再次修复(我认为)。它的美妙之处在于类实例易于创建和重用。很遗憾你不能完全使用它,即dict.get 不起作用。 是的,现在我只使用 python,在我的 C++ 时代,我怀念的为数不多的事情之一就是函数重载。【参考方案3】:

受MaxU 对similar problem 的解决方案启发的矢量化解决方案。

x = df.comp.str.split(expand=True)
df['company'] = None
df['company'] = df['company'].fillna(x[x.isin(product_map.keys())]\
                                     .ffill(axis=1).bfill(axis=1).iloc[:, 0])
df['company'].replace(product_map, inplace=True)
print(df)
#               comp  price     company
#0     dell notebook      0   Dell Inc.
#1  dell notebook S3      1   Dell Inc.
#2      dell notepad      2   Dell Inc.
#3        apple ipad      3  Apple Inc.
#4       apple ipad2      4  Apple Inc.
#5   acer chromebook      5   Acer Inc.
#6  acer chromebookx      6   Acer Inc.
#7           mac air      7  Apple Inc.
#8           mac pro      8  Apple Inc.
#9         lenovo x4      9   Dell Inc.

【讨论】:

【参考方案4】:

据我所知,pandas 没有“子字符串映射”方法。 .map() 方法不支持子字符串,.str.contains() 方法仅适用于正则表达式(不能很好地扩展)。

你可以通过编写一个简单的函数来达到你想要的结果。然后,您可以使用 .apply()lambda function 来生成所需的“公司”列。额外的好处是它使您的代码保持可读性并且您可以重用该功能。希望对您有所帮助。

这应该会为您提供所需的“公司”列:

def map_substring(s, dict_map):
    for key in dict_map.keys():
        if key in s: 
            return dict_map[key]
    return np.nan
df['company'] = df['product'].apply(lambda x: map_substring(x, product_map))

【讨论】:

注意——在上面的例子中,我假设值只能映射到一个子字符串。

以上是关于映射 str.contains 跨 pandas DataFrame的主要内容,如果未能解决你的问题,请参考以下文章

pandas:如何限制 str.contains 的结果?

如何在 pandas str.contains 中使用 \b 单词边界?

python pandas 中的 Str.contains 也标记为空白

Pandas Series contains 判断

在 Pandas str.contains() 的正则表达式中使用变量

当有前导空格时,为啥 Pandas series.str.contains 方法无法检测到匹配?