从 pandas 列中删除非 ASCII 字符

Posted

技术标签:

【中文标题】从 pandas 列中删除非 ASCII 字符【英文标题】:Remove non-ASCII characters from pandas column 【发布时间】:2016-07-20 08:00:06 【问题描述】:

我一直在尝试解决这个问题。我正在尝试从 DB_user 列中删除非 ASCII 字符并尝试用空格替换它们。但我不断收到一些错误。这是我的数据框的外观:

+-------------------------------------------------- ---------- | DB_user 源计数 | +-------------------------------------------------- ---------- | ???/"Ò|Z?)?]??C %??J A 10 | | ?D$ZGU ;@D??_???T(?) B 3 | | ?Q`H??M'?Y??KTK$?Ù‹???ЩJL4??*?_?? C 2 | +-------------------------------------------------- ----------

我正在使用这个功能,我在研究 SO 问题时遇到了这个功能。

def filter_func(string):
   for i in range(0,len(string)):


      if (ord(string[i])< 32 or ord(string[i])>126
           break

      return ''

And then using the apply function:

df['DB_user'] = df.apply(filter_func,axis=1)

我不断收到错误:

'ord() 期望一个字符,但找到长度为 66 的字符串',u'出现在索引 2'

但是,我认为通过在 filter_func 函数中使用循环,我是通过在“ord”中输入一个字符来处理这个问题的。因此,当它碰到一个非 ASCII 字符时,它应该被一个空格替换。

有人可以帮帮我吗?

谢谢!

【问题讨论】:

【参考方案1】:

你可以试试这个:

df.DB_user.replace(r'[^\x00-\x7F]+':'', regex=True, inplace=True)

【讨论】:

很好的答案,这也可以用于整个 DataFrame。 这执行的任务与问题中说明的任务略有不同——它接受所有 ASCII 字符,而问题中的示例代码从字符 32 而不是 0 开始拒绝不可打印的字符。字符 \x00 可以替换为单个空格,以使此答案与其行为中接受的答案相匹配。【参考方案2】:

您的代码失败,因为您没有将其应用于每个字符,而是按单词和顺序错误应用它,因为它需要一个字符,您需要:

  df['DB_user'] = df["DB_user"].apply(lambda x: ''.join([" " if ord(i) < 32 or ord(i) > 126 else i for i in x]))

您还可以使用链式比较来简化连接:

   ''.join([i if 32 < ord(i) < 126 else " " for i in x])

您也可以使用string.printable 过滤字符:

from string import printable
st = set(printable)
df["DB_user"] = df["DB_user"].apply(lambda x: ''.join([" " if  i not in  st else i for i in x]))

最快的是使用翻译:

from string import maketrans

del_chars =  " ".join(chr(i) for i in range(32) + range(127, 256))
trans = maketrans(t, " "*len(del_chars))

df['DB_user'] = df["DB_user"].apply(lambda s: s.translate(trans))

有趣的是,这比:

  df['DB_user'] = df["DB_user"].str.translate(trans)

【讨论】:

@red_devil,没问题,有很多不同的方法可以做到这一点,但知道哪里出错很重要。 值得注意的是,上述方法不适用于python 3(例如你不能这样做range(..) + range(..) t 在第 3 和第 4 方法中未定义 值得注意的是,maketrans 现在是 str 内置类型的一个方法。【参考方案3】:

这对我有用:

import re
def replace_foreign_characters(s):
    return re.sub(r'[^\x00-\x7f]',r'', s)

df['column_name'] = df['column_name'].apply(lambda x: replace_foreign_characters(x))

【讨论】:

【参考方案4】:

一个常见的技巧是使用 errors="ignore" 标志执行 ASCII 编码,然后将其解码为 ASCII:

df['DB_user'].str.encode('ascii', 'ignore').str.decode('ascii')

从python3.x及以上,这是我推荐的解决方案。


最小代码示例

s = pd.Series(['Déjà vu', 'Ò|zz', ';test 123'])
s

0      Déjà vu
1         Ò|zz
2    ;test 123
dtype: object


s.str.encode('ascii', 'ignore').str.decode('ascii')

0        Dj vu
1          |zz
2    ;test 123
dtype: object

P.S.:这也可以扩展到需要过滤掉不属于任何字符编码方案(不仅仅是 ASCII)的字符的情况。

【讨论】:

【参考方案5】:

这里给出的几个答案是不正确的。简单验证:

s = pd.Series([chr(x) for x in range(256)])
s.loc[0]
>> '\x00'
s.replace(r'[^\x00-\x7F]+':'', regex=True).loc[0]
>> '\x00'  # FAIL
s.str.encode('ascii', 'ignore').str.decode('ascii').loc[0]
>> '\x00'  # FAIL
s.apply(lambda x: ''.join([i if 32 < ord(i) < 126 else " " for i in x])).loc[0]
>> ' '  # Success!
import string
s.apply(lambda x: ''.join([" " if  i not in string.printable else i for i in x])).loc[0]
>> ' '  # Looks good, but...
s.apply(lambda x: ''.join([" " if  i not in string.printable else i for i in x])).loc[11]
>> '\x0b'  # FAIL
del_chars =  " ".join([chr(i) for i in list(range(32)) + list(range(127, 256))])
trans = str.maketrans(del_chars, " " * len(del_chars))
s.apply(lambda x: x.translate(trans)).loc[11]
>> ' '  # Success!

结论:只有已接受答案中的选项(来自 Padraic Cunningham)可靠地工作。他的第二个答案中有一些奇怪的 Python 错误/错别字,在这里进行了修改,否则它应该是最快的。

【讨论】:

【参考方案6】:

这对我有用。鉴于该系列有一些 NaN 值,它只对字符串执行:

from string import printable

import pandas as pd

df["text_data"] = df["text_data"].str.split().str.join(' ')

df["text_data"] = df["text_data"].apply(lambda string_var: ''.join(filter(lambda y: y in printable, string_var)) if isinstance(string_var, str) else string_var)

【讨论】:

【参考方案7】:
from string import printable

def printable_mapper(x): 
    return ''.join([_ if _ in printable else " " for _ in x])

df.DB_user = df.DB_user.map(printable_mapper)

【讨论】:

【参考方案8】:

这是我使用的一种衬里:

df = df.replace(to_replace="/[^ -~]+/g", value="", regex=True)

使用正则表达式,它全局删除不在''(空格)和~范围内的字符

【讨论】:

以上是关于从 pandas 列中删除非 ASCII 字符的主要内容,如果未能解决你的问题,请参考以下文章

从数据文件中删除非 ASCII 字符

如何从字符串中删除非 ASCII 字符?

从 pandas 数据框中的元组列中删除元素

使用 SQL Server 在 varchar 列中查找非 ASCII 字符

从 Snowflake 中的字符串中删除非 ASCII 字符

从 Pandas 列中删除缩写(字母+点的组合)