从列中的字符串中删除不需要的部分

2024-09-30 18:25:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在寻找一种有效的方法来删除数据帧列中字符串中不需要的部分。

数据如下:

    time    result
1    09:00   +52A
2    10:00   +62B
3    11:00   +44a
4    12:00   +30b
5    13:00   -110a

我需要将这些数据修剪为:

    time    result
1    09:00   52
2    10:00   62
3    11:00   44
4    12:00   30
5    13:00   110

我试过.str.lstrip('+-')str.rstrip('aAbBcC'),但得到一个错误:

TypeError: wrapper() takes exactly 1 argument (2 given)

任何指点都将不胜感激!


Tags: 数据方法字符串time错误resultargumentwrapper
3条回答

我会使用熊猫替换功能,非常简单和强大,因为你可以使用正则表达式。下面我将使用regex\D来删除任何非数字字符,但很明显,您可以使用regex获得相当多的创造性。

data['result'].replace(regex=True,inplace=True,to_replace=r'\D',value=r'')

How do I remove unwanted parts from strings in a column?

在最初的问题发布6年后,pandas现在拥有大量的“矢量化”字符串函数,可以简洁地执行这些字符串操作。

这个答案将探索其中一些字符串函数,提出更快的替代方案,并在最后进行计时比较。


^{}

指定要匹配的子字符串/模式,以及要用其替换的子字符串。

pd.__version__
# '0.24.1'

df    
    time result
1  09:00   +52A
2  10:00   +62B
3  11:00   +44a
4  12:00   +30b
5  13:00  -110a

df['result'] = df['result'].str.replace(r'\D', '')
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

如果需要将结果转换为整数,可以使用^{}

df['result'] = df['result'].str.replace(r'\D', '').astype(int)

df.dtypes
time      object
result     int64
dtype: object

如果不想就地修改df,请使用^{}

df2 = df.assign(result=df['result'].str.replace(r'\D', ''))
df
# Unchanged

^{}

用于提取要保留的子字符串。

df['result'] = df['result'].str.extract(r'(\d+)', expand=False)
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

对于extract,需要指定至少一个捕获组。expand=False将返回一个系列,其中包含从第一个捕获组捕获的项。


^{}^{}

拆分工作假设所有字符串都遵循这种一致的结构。

# df['result'] = df['result'].str.split(r'\D').str[1]
df['result'] = df['result'].str.split(r'\D').str.get(1)
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

如果你正在寻找一般的解决方案,不要推荐。


If you are satisfied with the succinct and readable str accessor-based solutions above, you can stop here. However, if you are interested in faster, more performant alternatives, keep reading.


优化:列表理解

在某些情况下,列表理解应该优先于pandas字符串函数。原因是字符串函数本身就很难矢量化(在单词的真正意义上),所以大多数字符串和正则表达式函数只是循环的包装器,开销更大。

我写的For loops with pandas - When should I care?更详细。

可以使用re.sub重新编写str.replace选项

import re

# Pre-compile your regex pattern for more performance.
p = re.compile(r'\D')
df['result'] = [p.sub('', x) for x in df['result']]
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

这个str.extract示例可以使用re.search的列表理解重新编写

p = re.compile(r'\d+')
df['result'] = [p.search(x)[0] for x in df['result']]
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

如果不匹配或不匹配是可能的,您将需要重新编写上述内容以包括一些错误检查。我是用函数来做的。

def try_extract(pattern, string):
    try:
        m = pattern.search(string)
        return m.group(0)
    except (TypeError, ValueError, AttributeError):
        return np.nan

p = re.compile(r'\d+')
df['result'] = [try_extract(p, x) for x in df['result']]
df

    time result
1  09:00     52
2  10:00     62
3  11:00     44
4  12:00     30
5  13:00    110

我们还可以使用列表理解重新编写@eumiro和@MonkeyButter的答案:

df['result'] = [x.lstrip('+-').rstrip('aAbBcC') for x in df['result']]

而且

df['result'] = [x[1:-1] for x in df['result']]

同样的规则也适用于处理NaNs等。


性能比较

enter image description here

使用perfplot生成的图。Full code listing, for your reference.下面列出了相关函数。

有些比较是不公平的,因为它们利用了OP的数据结构,但你可以从中得到你想要的。需要注意的一点是,每个列表理解函数都比其等价的pandas变体更快或更具可比性。

函数

def eumiro(df):
    return df.assign(
        result=df['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC')))

def coder375(df):
    return df.assign(
        result=df['result'].replace(r'\D', r'', regex=True))

def monkeybutter(df):
    return df.assign(result=df['result'].map(lambda x: x[1:-1]))

def wes(df):
    return df.assign(result=df['result'].str.lstrip('+-').str.rstrip('aAbBcC'))

def cs1(df):
    return df.assign(result=df['result'].str.replace(r'\D', ''))

def cs2_ted(df):
    # `str.extract` based solution, similar to @Ted Petrou's. so timing together.
    return df.assign(result=df['result'].str.extract(r'(\d+)', expand=False))

def cs1_listcomp(df):
    return df.assign(result=[p1.sub('', x) for x in df['result']])

def cs2_listcomp(df):
    return df.assign(result=[p2.search(x)[0] for x in df['result']])

def cs_eumiro_listcomp(df):
    return df.assign(
        result=[x.lstrip('+-').rstrip('aAbBcC') for x in df['result']])

def cs_mb_listcomp(df):
    return df.assign(result=[x[1:-1] for x in df['result']])
data['result'] = data['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC'))

相关问题 更多 >