【问题标题】:Remove partial string from dataframe with Pandas使用 Pandas 从数据框中删除部分字符串
【发布时间】:2018-11-16 19:21:28
【问题描述】:

如果我有这样的数据框:

id    str
01    abc_d(a)
02    ab_d(a)
03    abcd_e(a)
04    a_b(a)

我怎样才能得到如下的数据框?抱歉,我制作了这个数据框来代表我的实际问题。谢谢。

id    str
01    d
02    d
03    e
04    b

【问题讨论】:

  • 我试试,但我只能接受一个答案。当我点击其他人时,前一个变成灰色...

标签: python string pandas series


【解决方案1】:

使用extract

df['str']=df['str'].str.extract("\_(.*)\(",expand=True) 
df
Out[585]: 
   id str
0   1   d
1   2   d
2   3   e
3   4   b

【讨论】:

    【解决方案2】:

    也许你可以试试split类似于example

    df['str'] = df['str'].str.split('_').str.get(1).str[0]
    

    或者,

    df['str'] = df['str'].str.split('_').str.get(1).str.split('(').str[0]
    

    【讨论】:

      【解决方案3】:

      使用pd.Series.str.split。特定于您的特定格式。

      df['str'] = df['str'].str.split('_').str[-1].str[0]
      
      print(df)
      
         id str
      0   1   d
      1   2   d
      2   3   e
      3   4   b
      

      【讨论】:

        【解决方案4】:

        (错误答案)

        Series.str.split

        df['str'] = df['str'].str.split('(').str[0].str.split('_').str[-1]    
        df
        
           id str
        0   1   d
        1   2   d
        2   3   e
        3   4   b
        

        (不那么糟糕的答案)

        Series.str.extract

        df['str'] = df['str'].str.extract(r'_([^_]+)\(', expand=False)
        df
        
           id str
        0   1   d
        1   2   d
        2   3   e
        3   4   b
        

        正则表达式方法有相当一部分开销,str.extract 并没有做太多改进。


        (更好的答案)

        re.search 与列表组合

        import re
        
        p = re.compile(r'(?<=_)[^_]+(?=\()')
        df['str'] = [p.search(x)[0] for x in df['str'].tolist()] 
        df
        
           id str
        0   1   d
        1   2   d
        2   3   e
        3   4   b
        

        这应该比上述方法更快。我发现列表推导与大多数矢量化字符串 pandas 方法相比非常快,即使这确实使用了正则表达式。我提前预编译了模式以缓解一些性能问题。


        (也是一个更好的答案)

        str.split 与列表组合

        df['str'] = [
            x.split('(', 1)[0].split('_')[1] for x in df['str'].tolist()
        ]
        df
        
           id str
        0   1   d
        1   2   d
        2   3   e
        3   4   b
        

        这结合了两全其美,列表组合的性能和纯 Python 字符串拆分的速度。应该是最快的。


        性能

        df_test = pd.concat([df] * 10000, ignore_index=True)
        

        %timeit df_test['str'].str.extract(r'_([^_]+)\(', expand=False)
        %timeit df_test['str'].str.split('(').str[0].str.split('_').str[-1] 
        %timeit [p.search(x)[0] for x in df_test['str'].tolist()] 
        %timeit [x.split('(', 1)[0].split('_')[1] for x in df_test['str'].tolist()]
        
        70.4 ms ± 623 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
        99.6 ms ± 730 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
        31 ms ± 877 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
        30 ms ± 431 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)  # fastest but not by much
        

        【讨论】:

        • 再次冷速!如果您有时间,您能否简要说明如果答案传达相同的结果,是什么使答案好,坏或更好?我是初学者,看不到质量方面的直接差异,除了你的最佳答案对我来说似乎是可读性最差的(没有冒犯)
        • @sudonym 是的,请稍等,我会添加更多信息;-)
        • 像往常一样,我印象深刻 - 享受你的一天!
        • 我不知道你为什么会选择str.split('(').str[0].str.split('_').str[-1] 而不是str.split('_').str[-1].str[0]。这不会使您的其余答案无效,但没有必要让拆分方法看起来比实际更糟。
        • @jpp 的可读性不是很好,但在拆分次数较少方面可能更好,具体取决于您的字符串。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-03
        • 2021-11-30
        • 1970-01-01
        相关资源
        最近更新 更多