【问题标题】:Remove characters only from starting in a column of dataframe仅从数据框列中删除字符
【发布时间】:2021-11-28 08:44:51
【问题描述】:

我正在从两个输入 Excel 文件中获取数据,并在 pandas 数据框的帮助下对其进行处理。 Excel 具有大量数据和列数。但是我创建了简单的例子来说明这个问题

以下是第一个数据帧 df_s1(需要对零件编号列执行操作)-

以下是第二个数据帧 df_s2(这里提到了一些特殊字符,我必须从 df_s1['Part Number'] 的开头删除这些字符,这些字符非常大,包括 、2、 ((* 2)等......我提到了有限的) -

我想在 df_s2 的帮助下处理 df_s1 后的输出-

现在的问题是我必须从 df_s1(第一个数据帧)中的 Part Number 列的开头删除(删除)所有特殊字符。有关这些特殊字符的信息在 df_s2(second dataframe Special Character 列(大量字符包括(,*...)

我尝试了以下代码来实现它。我还在我的代码中准备了示例数据框,以便于解决)

#first dataframe and remove special charaters from starting of part number column

import pandas as pd
df_s1 = pd.DataFrame({'Part Number' : ['(2)CAB-ETHS-RJ45',' 2*VEDGE-CAB-C13-XXX','(4X)CAB-ETHXOVER','1*VEDGE-ABCD','2*73ETHER-387','4xCBTA-98CD','5xNBOC','(1)289RG7','2 CDXG59','(7x)29FG2ZT-AB','((*2)FGDT-X78','((4))RGD-RX78','EDXC-Y82','D92ZT-3A','FTZT-9A7'], 
                    'ID' : ['1','2','3','4','4','4','4','4','4','4','4','5','4','4','6']
                  })
#Following special charaters needs to remove from starting of part number column of first dataframe
df_s2 = pd.DataFrame({'Special Charater':['(2)','2*','(4X)','1*','4x','5x','(1)','2 ','(7x)','((*2)','((4))']})
for i in df_s2['Special Charater']:
    j=0
    for k in df_s1['Part Number']:
        if str(k).startswith(str(i)):
            df_s1['Part Number'][j] = str(k[len(i):])

        
        else:
            j+=1

df_s1

但是,除了 1 个部件号 2*VEDGE-CAB-C13-XXX 没有删除 2* 之外,我从上面的代码中得到了以下所需的输出

我在找-

  1. 我知道通过 pandas 完成这项任务不是标准方法。那么,您能否像df.str.findall().str.replace() 一样帮助我解决您的pandas python 解决方案。我无法将这种标准方法放在我的解决方案中。只是我们必须替换所有提到的字符,因为它是从第一个数据帧部件号列开始的第二个数据帧
  2. 我无法弄清楚为什么 2*VEDGE-CAB-C13-XXX 2* 在我的解决方案中没有从启动中删除,而其他特殊字符从启动中删除

希望我清楚并且非常积极地获得解决此问题的另一种方法

【问题讨论】:

    标签: python regex pandas dataframe str-replace


    【解决方案1】:

    1ts 尝试

    您可以使用 pandas 的extract。这将在字符串上应用正则表达式并为每个组返回一列。因为要全匹配,所以只需要colmn0中的第一组即可。

    df['Part Number'].str.extract('(([A-Z\d]+)+(-.*)?)$', expand=False)[0]
    

    (([A-Z\d]+)(-.*)?)$ 是做什么的?

    • $ 是字符串的结尾,所以我们只想要最后的组
    • (-.*)? 是一个组,匹配- 之后的所有字母。这个组可以被找到零次或多次,用?表示
    • ([A-Z\d]+) 是一个至少匹配一个大写字母或数字的组。

    这两组的组合就是你要外推的字符串。

    第二次尝试

    您可以定义正则表达式并使用 pandas replace 选项。 据我所知,您想替换星号*、空格 x 或右括号) 之前的所有元素。下面的代码尝试最多找到 1 个匹配项,从字符串的左侧开始。

    df_s1['Part Number'].str.replace('(.*[x| |\)|\*])', '', n=1)
    

    第三次尝试

    您可以尝试下面的代码,因为您知道要替换的所有字符串。在这种情况下,您会多次循环每个字符串,如果您发现不需要的子字符串,则将字符串替换为空字符串。

    def replace(x):
        for item in ['(2)','2*','(4X)','1*','4x','5x','(1)','2 ','(7x)','((*2)','((4))']:
            x = x.replace(item, '')
        return x
    
    df_s1['Part Number'].apply(replace)
    

    【讨论】:

    • 感谢您的回答。但是这里有两点需要注意。我只需要从每个单元格中存在的字符串的开头进行替换。特殊字符列中的第二点有数百行,很难在具有静态值的代码中绑定。有没有我的方法中描述的方法
    • 再次非常感谢您的回答。仍然 2*VEDGE-CAB-C13-XXX 对于此部件号更新的解决方案给出了空值
    • 我没有得到2*VEDGE-CAB-C13-XXX 的空字符串。你可以试试我的正则表达式here,看看匹配是否正确。
    • 谢谢。我已经检查了上面的链接,并且正则表达式完全匹配这种特殊情况 2*VEDGE-CAB-C13-XXX。它正在移除,我认为这可能是原因。你能检查一下吗
    • 您使用的正则表达式是什么?我的两个建议都有效。
    【解决方案2】:

    您可以尝试使用此代码作为替代解决方案:

    import re
    
    for sp_char in df_s2['Special Character']:
        df_s1['Part Number'] = df_s1['Part Number'].replace({'^'+re.escape(sp_char): ""}, regex=True)
    
    print(df_s1)
    

    re.escape() 专门用于为所有特殊字符添加反斜杠(这可能是您尝试的某些解决方案不起作用的原因)


    在进一步的工作中,我能够使用字典选项使代码更加优化。较早的带有 for 循环的方法大约需要 25-80ms,而字典方法大约需要 3-20ms。更新后的方法会占用更多内存,如果数据库很大,请牢记这一点。

    请注意,我还添加了^,这将使正则表达式仅匹配字符串开头的字符。

    import re
    
    replace_dict = {'^'+re.escape(sp_char): '' for sp_char in df_s2['Special Character']}
    df_s1['Part Number'] = df_s1['Part Number'].replace(replace_dict, regex=True)
    

    【讨论】:

    • 非常感谢您提供此解决方案和您宝贵的时间。如果有更优化的方式来完成指定的任务,那就太好了。我想提一件事,就是我们需要把这些字符从只开始。但是,替换将对完整字符串起作用,而不是仅从开始。希望我清楚这一点。谢谢
    • @VishavGupta 我添加了更优化的代码来实现解决方案。我仍在研究一种(简单)解决方案,仅从一开始就删除字符,并将尝试尽快更新帖子。
    • 再次更新了解决方案,现在它只在字符位于字符串开头时才有效
    • 注意到了。非常感谢您提供此解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 2017-07-27
    • 1970-01-01
    • 2021-10-13
    相关资源
    最近更新 更多