【问题标题】:Pandas or Python method for removing unwanted string elements in a column, based on strings in another column用于根据另一列中的字符串删除列中不需要的字符串元素的 Pandas 或 Python 方法
【发布时间】:2020-12-14 17:45:05
【问题描述】:

我有问题similar to this question

我正在为一个项目将一个大的 .csv 文件导入 pandas。数据框中的一列最终包含 4 列连接数据(我无法控制收到的数据)、品牌名称(我要删除的内容)、产品描述、产品尺寸和 UPC。请注意,Item_UPC 中的品牌描述并不总是 == 品牌。

例如

import pandas as pd
df = pd.DataFrame({'Item_UPC': ['fubar baz dr frm prob onc dly wmn ogc 30vcp 06580-66-832',
 'xxx stuff coll tides 20 oz 09980-66-832',
 'hel world sambucus elder 60 chw 0392-67-491',
 'northern cold ultimate  180 sg 06580-66-832',
 'ancient nuts  boogs 16oz 58532-42-123 '], 
                   'Brand': ['FUBAR OF BAZ',
 'XXX STUFF',
 'HELLO WORLD',
 'NORTHERN COLDNITES',
 'ANCIENT NUTS']}) 

我想从Item_UPC 列中删除品牌名称,因为这是其他问题中的多余信息。目前我有一个函数,它获取新的 df 并拉出 UPC 并清理它以匹配在瓶子上找到的内容和我为单个品牌拥有的另一个数据库,减去最后一个校验和数字。

def clean_upc(df):
    #take in a dataframe, expand the number of columns into a temp
    #dataframe
    temp = df["Item_UPC"].str.rsplit(" ", n=1, expand = True)
    #add columns  to main dataframe from Temp
    df.insert(0, "UPC", temp[1])
    df.insert(1, "Item", temp[0])

    #drop original combined column
    df.drop(columns= ["Item_UPC"], inplace=True)
    #remove leading zero on and hyphens in UPC. 
    
    df["UPC"]= df["UPC"].apply(lambda x : x[1:] if x.startswith("0") else x)
    df["UPC"]=df["UPC"].apply(lambda x :x.replace('-', ''))
    col_names = df.columns
    #make all columns lower case to ease searching
    for cols in col_names:
        df[cols] = df[cols].apply(lambda x: x.lower() if type(x) == str else x)

运行后,我有一个包含三列的数据框 UPC, Item, Brand

数据框中有超过 30 万行和 2300 个独特品牌。他们也没有一致的方式来缩短名称。当我运行以下代码时

temp = df["Item"].str.rsplit(" ", expand = True)

temp 的形状为

temp.shape 
 (329868, 13)

当第 9-13 列的大部分内容为空时,手动管理会很痛苦。 目前我的逻辑是首先将品牌拆分为 2,同时将第一列放入 temp

brand = df["brand"].str.rsplit(" ",  n=1,expand = True) #produce a dataframe of two columns
temp.drop(columns= [0], inplace=True)

然后在 temp[1] 上进行字符串替换,以查看它是否在品牌 [1] 中包含正则表达式,然后将其替换为 " " 或反之亦然,然后将 temp 重新连接在一起(

temp["combined"] = temp[1] + temp[2]....+temp[13]

并用combined 列替换现有的Item

df["Item"] = temp["combined"]

或者有更好的方法吗?有很多品牌只有一个名字,这可能会让一切变得更快。我一直在用正则表达式苦苦挣扎,从逻辑上讲,这似乎会更快,我只是很难思考使它起作用的语法。

【问题讨论】:

  • 你能澄清你的确切问题吗?是否有您正在寻找的解决方案或您希望优化的行为?
  • 例如,我想将最后一行“古代坚果 boogs 16oz 58532-42-123”更改为“boogs 16oz”。我的移除和清洁 UPC 的功能运行良好,但我不知道如何从该行或任何其他品牌名称中移除“古代坚果”。

标签: python-3.x regex pandas string


【解决方案1】:

由于输入不遵循任何明确定义的规则,这看起来更像是一个优化问题。您可以从去除完全匹配开始:

df["Item_cleaned"] = df.apply(lambda x: x.Item_UPC.lstrip(x.Brand.lower()), axis=1)

输出:

                                            Item_UPC               Brand                                    Item_cleaned
0  fubar baz dr frm prob onc dly wmn ogc 30vcp 06...        FUBAR OF BAZ  dr frm prob onc dly wmn ogc 30vcp 06580-66-832
1            xxx stuff coll tides 20 oz 09980-66-832           XXX STUFF                   coll tides 20 oz 09980-66-832
2        hel world sambucus elder 60 chw 0392-67-491         HELLO WORLD               sambucus elder 60 chw 0392-67-491
3        northern cold ultimate  180 sg 06580-66-832  NORTHERN COLDNITES                   ultimate  180 sg 06580-66-832
4             ancient nuts  boogs 16oz 58532-42-123         ANCIENT NUTS                        boogs 16oz 58532-42-123

此方法应该会去除所有完全匹配并输出到新列Item_cleaned。如果您的输入是缩写的,您应该应用更复杂的模糊字符串匹配算法。然而,这可能非常缓慢。在这种情况下,我建议采用两步法,保存所有已通过上述方法清理的行,并根据需要进行第二次更复杂的清理。

【讨论】:

  • 这是我要做的最后一件事是有原因的。 Item_UPC 中的许多(尽管不是全部)品牌与 Brand 相同。感谢您的一般方法和答案。你更喜欢 x.Brand.lower() 而不是 x["Brand"].lower() 吗?据我所知,没有一个列名是 pandas 方法,所以应该没有冲突。
  • 所以这对我的合成数据集非常有效,我更改了品牌名称。但是在我的真实数据集上,它的行为并不完全相同。例如,在行索引 3 中,在 .lstrip(x.Brand.lower()) 之后,它从 northern cold ultimate 180 sg 06580-66-832 条带化到 mate 180 sg,它应该是 ultimate 180 sg。那是在我运行我的 clean_upc() 函数之后。但是对于ancient nuts,它工作得很好。如此完美的匹配是完美的,否则它有我需要解决的问题。 (在这里大声思考)
猜你喜欢
  • 1970-01-01
  • 2022-01-25
  • 2023-04-09
  • 2020-04-05
  • 2019-07-20
  • 2016-04-18
  • 1970-01-01
  • 2014-03-10
  • 1970-01-01
相关资源
最近更新 更多