规范化错过了抛光字符

时间:2017-03-07 10:31:15

标签: python python-3.x pandas

我有一个包含人员数据的大数据框。我想压扁所有奇怪的变音符号并将它们转换为最接近的ascii字符。基于我在SO中找到的解决方案,我执行以下操作:

for column in df.columns:
            df[column] = df[column].astype("str").str.normalize('NFKD').str.encode('ascii', errors='ignore').str.decode('utf-8')

它适用于大多数情况(没有全部检查过)但是我注意到它错过了波兰语中的字母'ł'。例如,Lech Wałęsa被翻译为Lech Waesa,而我的期望是Lech Walesa。我的猜测是ignore方法中str.encode参数的作用。知道如何让它适用于任何变音符号吗?

3 个答案:

答案 0 :(得分:3)

尝试使用unidecode,完全适用于您所描述的示例。

from unidecode import unidecode

for column in df.columns:
   df[column] = [unidecode(x) for x in df[column].values]

答案 1 :(得分:3)

查看normalize('NFKD')对输入字符串"Lech Wałęsa"实际执行的操作:

import unicodedata
s = "Lech Wałęsa"
print(list(unicodedata.normalize("NFKD", s)))

['L', 'e', 'c', 'h', ' ', 'W', 'a', 'ł', 'e', '̨', 's', 'a']

正如你所看到的,字符'''被分解为字母'e'和变音'̨',但是'ł'没有这样的分解。似乎unicode字符LATIN SMALL LETTER L WITHSTROKE'ł'和LATIN CAPITAL LETTER L WITHSTROKE'Ł'是among the few characters,unicode分解不起作用。

现在,当您使用normalize("NFKD")的输出作为encode("ascii", errors="ignore")的输入时,会发生的情况是,所有无法表示为ASCII字符的字符都会被静默忽略,从而为您提供输出{ {1}}。

解决这个问题的方法是在从支持分解的字符中删除变音符之前,用'L'和'l'手动替换异常的'Ł'和'ł'。您必须像这样更改代码:

"Lech Waesa"

答案 2 :(得分:0)

如其他答案所述,某些Unicode字符不能使用“ NFKD”方法进行分解。我已经使用unicode字符名称编译了所有这些字符及其等效的规范化字符的列表。

以下代码将解决您的问题:

import unicodedata

NON_NFKD_MAP = {u'\u0181': u'B', u'\u1d81': u'd', u'\u1d85': u'l', u'\u1d89': u'r', u'\u028b': u'v', u'\u1d8d': u'x', u'\u1d83': u'g', u'\u0191': u'F', u'\u0199': u'k', u'\u019d': u'N', u'\u0220': u'N', u'\u01a5': u'p', u'\u0224': u'Z', u'\u0126': u'H', u'\u01ad': u't', u'\u01b5': u'Z', u'\u0234': u'l', u'\u023c': u'c', u'\u0240': u'z', u'\u0142': u'l', u'\u0244': u'U', u'\u2c60': u'L', u'\u0248': u'J', u'\ua74a': u'O', u'\u024c': u'R', u'\ua752': u'P', u'\ua756': u'Q', u'\ua75a': u'R', u'\ua75e': u'V', u'\u0260': u'g', u'\u01e5': u'g', u'\u2c64': u'R', u'\u0166': u'T', u'\u0268': u'i', u'\u2c66': u't', u'\u026c': u'l', u'\u1d6e': u'f', u'\u1d87': u'n', u'\u1d72': u'r', u'\u2c74': u'v', u'\u1d76': u'z', u'\u2c78': u'e', u'\u027c': u'r', u'\u1eff': u'y', u'\ua741': u'k', u'\u0182': u'B', u'\u1d86': u'm', u'\u0288': u't', u'\u018a': u'D', u'\u1d8e': u'z', u'\u0111': u'd', u'\u0290': u'z', u'\u0192': u'f', u'\u1d96': u'i', u'\u019a': u'l', u'\u019e': u'n', u'\u1d88': u'p', u'\u02a0': u'q', u'\u01ae': u'T', u'\u01b2': u'V', u'\u01b6': u'z', u'\u023b': u'C', u'\u023f': u's', u'\u0141': u'L', u'\u0243': u'B', u'\ua745': u'k', u'\u0247': u'e', u'\ua749': u'l', u'\u024b': u'q', u'\ua74d': u'o', u'\u024f': u'y', u'\ua751': u'p', u'\u0253': u'b', u'\ua755': u'p', u'\u0257': u'd', u'\ua759': u'q', u'\xd8': u'O', u'\u2c63': u'P', u'\u2c67': u'H', u'\u026b': u'l', u'\u1d6d': u'd', u'\u1d71': u'p', u'\u0273': u'n', u'\u1d75': u't', u'\u1d91': u'd', u'\xf8': u'o', u'\u2c7e': u'S', u'\u1d7d': u'p', u'\u2c7f': u'Z', u'\u0183': u'b', u'\u0187': u'C', u'\u1d80': u'b', u'\u0289': u'u', u'\u018b': u'D', u'\u1d8f': u'a', u'\u0291': u'z', u'\u0110': u'D', u'\u0193': u'G', u'\u1d82': u'f', u'\u0197': u'I', u'\u029d': u'j', u'\u019f': u'O', u'\u2c6c': u'z', u'\u01ab': u't', u'\u01b3': u'Y', u'\u0236': u't', u'\u023a': u'A', u'\u023e': u'T', u'\ua740': u'K', u'\u1d8a': u's', u'\ua744': u'K', u'\u0246': u'E', u'\ua748': u'L', u'\ua74c': u'O', u'\u024e': u'Y', u'\ua750': u'P', u'\ua754': u'P', u'\u0256': u'd', u'\ua758': u'Q', u'\u2c62': u'L', u'\u0266': u'h', u'\u2c73': u'w', u'\u2c6a': u'k', u'\u1d6c': u'b', u'\u2c6e': u'M', u'\u1d70': u'n', u'\u0272': u'n', u'\u1d92': u'e', u'\u1d74': u's', u'\u2c7a': u'o', u'\u2c6b': u'Z', u'\u027e': u'r', u'\u0180': u'b', u'\u0282': u's', u'\u1d84': u'k', u'\u0188': u'c', u'\u018c': u'd', u'\ua742': u'K', u'\u1d99': u'u', u'\u0198': u'K', u'\u1d8c': u'v', u'\u0221': u'd', u'\u2c71': u'v', u'\u0225': u'z', u'\u01a4': u'P', u'\u0127': u'h', u'\u01ac': u'T', u'\u0235': u'n', u'\u01b4': u'y', u'\u2c72': u'W', u'\u023d': u'L', u'\ua743': u'k', u'\u0249': u'j', u'\ua74b': u'o', u'\u024d': u'r', u'\ua753': u'p', u'\u0255': u'c', u'\ua757': u'q', u'\u2c68': u'h', u'\ua75b': u'r', u'\ua75f': u'v', u'\u2c61': u'l', u'\u2c65': u'a', u'\u01e4': u'G', u'\u0167': u't', u'\u2c69': u'K', u'\u026d': u'l', u'\u1d6f': u'm', u'\u0271': u'm', u'\u1d73': u'r', u'\u027d': u'r', u'\u1efe': u'Y'}

def deaccent(name):
    # Convert accented chars to their non-accented equivalent.
    # e.g.: Polynésie Française -> Polynesie Francaise
    if not isinstance(name, unicode):
        name = unicode(name)

    return ''.join(NON_NFKD_MAP[c] if c in NON_NFKD_MAP else c \
                   for part in unicodedata.normalize('NFKD', name) for c in part
                   if unicodedata.category(part) != 'Mn')

print deaccent(u"Lech Wałęsa")

结果:

Lech Walesa