【问题标题】:Remove non-ASCII characters from pandas column从 pandas 列中删除非 ASCII 字符
【发布时间】: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 字符时,它应该被一个空格替换。

有人可以帮帮我吗?

谢谢!

【问题讨论】:

    标签: python string pandas character-encoding


    【解决方案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)

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

              【讨论】:

                猜你喜欢
                • 2018-07-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-07-28
                • 2012-01-21
                相关资源
                最近更新 更多