剥离/修剪数据框的所有字符串


80

清理python / pandas中的多类型数据框的值后,我要修剪字符串。我目前正在执行两条指令:

import pandas as pd

df = pd.DataFrame([['  a  ', 10], ['  c  ', 5]])

df.replace('^\s+', '', regex=True, inplace=True) #front
df.replace('\s+$', '', regex=True, inplace=True) #end

df.values

这很慢,我可以改善什么?


1
df.replace(r'\s*(.*?)\s*', r'\1', regex=True)
MaxU

1
这是最好的答案,刚刚通过@MaxU登录以投票表决了答案
Linkon

Answers:


151

您可以使用DataFrame.select_dtypes选择string列,然后apply运行str.strip

注意:值不能typesdictslists,因为它们dtypesobject

df_obj = df.select_dtypes(['object'])
print (df_obj)
0    a  
1    c  

df[df_obj.columns] = df_obj.apply(lambda x: x.str.strip())
print (df)

   0   1
0  a  10
1  c   5

但是,如果只有几列,请使用str.strip

df[0] = df[0].str.strip()

1
在这种情况下,SettingWithCopyWarning应该被忽略,如stackoverflow.com/questions/20625582/…所述
Harvey

71

钱射击

这是使用applymap简单的lambda表达式strip仅在值是字符串类型时调用的紧凑版本:

df.applymap(lambda x: x.strip() if isinstance(x, str) else x)

完整的例子

一个更完整的示例:

import pandas as pd


def trim_all_columns(df):
    """
    Trim whitespace from ends of each value across all series in dataframe
    """
    trim_strings = lambda x: x.strip() if isinstance(x, str) else x
    return df.applymap(trim_strings)


# simple example of trimming whitespace from data elements
df = pd.DataFrame([['  a  ', 10], ['  c  ', 5]])
df = trim_all_columns(df)
print(df)


>>>
   0   1
0  a  10
1  c   5

工作范例

这是Trinket托管的工作示例:https : //trinket.io/python3/e6ab7fb4ab


1
嗨@DaleKube ...我只是在新机器上尝试了一下,以进行健全性检查,结果与答案相同。您可以确认使用的是Python2还是Python3?这些天我只使用Python3,但这也许是一个因素。如果是这样,我会在发布的答案中指出这一点,如果您能够确认的话。谢谢!
Jonathan B.

1
我删除了我的评论。我在代码中发现了一个错误,并且可以确认它现在可以正常运行了。仅供参考,我正在使用Python3。很抱歉造成麻烦。
Dale Kube

您应该使用type(x) == str,而不是type(x) is str
fjsj

@fjsj感谢您的推动。我已使用PEP8指导偏好更新了示例isinstance(x, str)
乔纳森·B

10

你可以试试:

df[0] = df[0].str.strip()

或更具体地针对所有字符串列

non_numeric_columns = list(set(df.columns)-set(df._get_numeric_data().columns))
df[non_numeric_columns] = df[non_numeric_columns].apply(lambda x : str(x).strip())

9

如果您真的想使用正则表达式,那么

>>> df.replace('(^\s+|\s+$)', '', regex=True, inplace=True)
>>> df
   0   1
0  a  10
1  c   5

但是这样做应该更快:

>>> df[0] = df[0].str.strip()

5

您可以使用该apply功能的的Series对象:

>>> df = pd.DataFrame([['  a  ', 10], ['  c  ', 5]])
>>> df[0][0]
'  a  '
>>> df[0] = df[0].apply(lambda x: x.strip())
>>> df[0][0]
'a'

注意和的用法strip不是regex更快

另一个选择-使用DataFrame对象的apply功能

>>> df = pd.DataFrame([['  a  ', 10], ['  c  ', 5]])
>>> df.apply(lambda x: x.apply(lambda y: y.strip() if type(y) == type('') else y), axis=0)

   0   1
0  a  10
1  c   5

1
df[0] = df[0].str.strip()-很有可能在大型DF上更快
MaxU

-1
def trim(x):
    if x.dtype == object:
        x = x.str.split(' ').str[0]
    return(x)

df = df.apply(trim)

1
您能否解释一下该功能在做什么?
CJ丹尼斯

例如,我在日常工作中遇到这样的数据: 가나다 봻 空白部分是我想要的,右侧部分是垃圾。修剪功能从原始数据中提取我想要的内容。
郑贤宇

投票的原因是这不会修剪字符串,它删除了第一个空格之后的所有内容。这不是问题中要求的行为,它会引入读者可能不会期望的副作用。而且,副作用可能不会立即显现。如果您要修剪“姓氏”列,您可能会认为这按预期工作,因为大多数人没有多个姓氏,并且尾随空格也已删除。然后,有两个姓氏的葡萄牙人加入您的网站,并且代码修剪掉了他们的姓氏,仅保留了他们的姓氏。
scottclowe
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.