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

新手上路,请多包涵

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

数据看起来像:

     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)

任何指针将不胜感激!

原文由 Yannan Wang 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 413
2 个回答
data['result'] = data['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC'))

原文由 eumiro 发布,翻译遵循 CC BY-SA 3.0 许可协议

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

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

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


.str.replace

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

 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

如果需要将结果转换为整数,可以使用 Series.astype

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

df.dtypes
time      object
result     int64
dtype: object

如果您不想就地修改 df ,请使用 DataFrame.assign

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


.str.extract

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

 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 将返回一个系列,其中包含第一个捕获组中捕获的项目。


.str.split.str.get

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

 # 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

如果您正在寻找通用解决方案,请不要推荐。


如果您对上面简洁易读的 str 基于访问器的解决方案感到满意,你可以到此为止。但是,如果您对更快、性能更高的替代方案感兴趣,请继续阅读。


优化:列表理解

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

我的 文章,熊猫中的 for 循环真的很糟糕吗?我什么时候应该关心? , 更详细。

str.replace 选项可以使用 re.sub

 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

如果可能出现 NaN 或不匹配,您将需要重写上面的内容以包括一些错误检查。我使用一个函数来做到这一点。

 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']]

适用于处理 NaN 等的相同规则。


性能比较

在此处输入图像描述

使用 perfplot 生成的图形。 完整代码清单,供您参考。 相关函数如下所示。

其中一些比较是不公平的,因为它们利用了 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']])

原文由 cs95 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题