【问题标题】:Pandas, remove everything after last '_'熊猫,删除最后一个'_'之后的所有内容
【发布时间】:2020-03-03 10:39:11
【问题描述】:

我的专栏中有以下类型的字符串,如下所示。我想解析每个字符串的最后一个 _ 之后的所有内容,如果没有 _ 则保留字符串原样。 (因为我下面的尝试只会排除没有_ 的字符串)

到目前为止,我已经在下面尝试过,在这里看到:Python pandas: remove everything after a delimiter in a string。但它只是在第一个 _ 之后解析所有内容

d6['SOURCE_NAME'] = d6['SOURCE_NAME'].str.split('_').str[0]

以下是我的 SOURCE_NAME 列中的一些示例字符串。

Stackoverflow_1234
Stack_Over_Flow_1234
Stackoverflow
Stack_Overflow_1234

预期:

Stackoverflow
Stack_Over_Flow
Stackoverflow
Stack_Overflow

任何帮助将不胜感激。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    结合使用str.rsplitstr.get 以获得您想要的结果。 str.rsplit 只是从末尾拆分字符串,而 str.get 获取 pd.Series 对象中迭代器的第 n 个元素。


    回答

    d6['SOURCE_NAME'] = df['SOURCE_NAME'].str.rsplit('_', n=1).str.get(0)

    rsplit 中的 n 参数限制了输出中的拆分次数,因此您只保留最后一个“_”之前的所有内容。

    尽管使用pd.Series.apply 的解决方案几乎快了一半,但我喜欢这个解决方案,因为它的语法更具表现力。如果你想使用pd.Series.apply解决方案(更快)检查计时部分!

    pandas documentation.


    示例

    strs = ['Stackoverflow_1234',
            'Stack_Over_Flow_1234',
            'Stackoverflow',
            'Stack_Overflow_1234']
    df = pd.DataFrame(data={'SOURCE_NAME': strs})
    

    这会导致

    print(df)
                SOURCE_NAME
    0    Stackoverflow_1234
    1  Stack_Over_Flow_1234
    2         Stackoverflow
    3   Stack_Overflow_1234
    

    使用建议的解决方案:

    df['SOURCE_NAME'].str.rsplit('_', 1).str.get(0)
    
    0      Stackoverflow
    1    Stack_Over_Flow
    2      Stackoverflow
    3     Stack_Overflow
    Name: SOURCE_NAME, dtype: object
    

    时间

    有趣的是,使用pd.Series.str 不一定比使用pd.Series.apply 快:

    import pandas as pd
    
    df = pd.DataFrame(data={'SOURCE_NAME': ['stackoverflow_1234_abcd'] * 1000})
    
    %timeit df['SOURCE_NAME'].apply(lambda x: x.rsplit('_', 1)[0])
    497 µs ± 30.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    %timeit df['SOURCE_NAME'].str.rsplit('_', n=1).str.get(0)
    1.04 ms ± 4.27 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    # increasing the number of rows x 100
    df = pd.concat([df] * 100)
    
    %timeit df['SOURCE_NAME'].apply(lambda x: x.rsplit('_', 1)[0])
    31.7 ms ± 1.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    %timeit df['SOURCE_NAME'].str.rsplit('_', n=1).str.get(0)
    84.1 ms ± 6.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    

    【讨论】:

    • 嗨@excelguy。 n=1pd.Series.str.rsplit 方法的一个参数,它在原版 Python 上的对应物是 str.rsplit,原版参数是 maxsplit=1。这些参数只是限制拆分的数量,从右侧。请注意,这些参数的默认值为-1,这意味着限制拆分的数量。如果我说pd.Series.str.rsplit(sep='_', n=1) 我是说,在'' 上拆分并在它从右侧找到的第一个'' 上拆分。打开终端并尝试'x_k_c_d'.rsplit(sep='_', maxsplits=1)。为maxplits尝试不同的值
    【解决方案2】:

    您可以尝试这样应用 lambda:

    d6['SOURCE_NAME'] = df['SOURCE_NAME'].apply(lambda x: x.split('_')[0])
    

    希望有帮助!

    【讨论】:

      【解决方案3】:

      使用 rsplit() 返回您想要实现的目标,您可以告诉它拆分字符串的次数。

      s = "Stack_Over_Flow_1234"
      s.rsplit('_', 1)[0] # Split my string one time and get the first part of it
      

      然后返回'Stack_Over_Flow'

      【讨论】:

        【解决方案4】:

        您可以使用 string.split('_') 函数将字符串拆分为围绕每个下划线的子字符串列表,然后在没有最后一个元素的情况下重新组合它们。这是使用您的示例的 sn-p:

        a = ["Stackoverflow_1234", "Stack_Over_Flow_1234", "Stackoverflow", "Stack_Overflow_1234"]
        
        for e in a:
        
            # Split the string into a list, separated at '_'
            splitStr = e.split("_")
        
            # If there is only 1 element, we can use it directly
            if len(splitStr) == 1:
                print(splitStr[0])
        
            # Slice off the final substring and join the remaining 
            # substrings back together with underscores
            else:
                print("_".join(splitStr[:-1]))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-06-16
          • 2016-07-24
          • 2020-07-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多