Замена нескольких символов с помощью словаря сопоставления

#python #pandas #string #data-cleaning

#питон #панды #строка #очистка данных

Вопрос:

Я работаю над гармонизацией / очисткой довольно «грязного» набора данных в Pandas. Ради демонстрации давайте представим, что это именно этот:

 df = pd.DataFrame({"colname": ["ÀÁÂÃÄÅÆ", "Ç", "ÈÉÊË", "ÌÍÎÏ", "Ð", "Ñ", "ÒÓÔÕÖ", "×", "Ø", "ÙÚÛÜ", "Ý", "Þ", "ß"]})

print(df)

    colname
0   ÀÁÂÃÄÅÆ
1         Ç
2      ÈÉÊË
3      ÌÍÎÏ
4         Ð
5         Ñ
6     ÒÓÔÕÖ
7         ×
8         Ø
9      ÙÚÛÜ
10        Ý
11        Þ
12        ß

 

Моя цель — очистить приведенный выше столбец, применив к символам следующее сопоставление:

 Before: ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß
After:  AAAAAAACEEEEIIIIDNOOOOO OUUUUY S
 

Хотя цепочка 32 str.replace() должна выполнить эту работу, мне это не кажется особенно удобочитаемым решением. Например, для первых двух:

df["colname"] = df["colname"].str.replace("À", "A").str.replace("Á", "A")

Вместо этого мне было интересно, можно ли определить следующий словарь сопоставления

 sub_dict = {
    "À": "A", "Á": "A", "Â": "A", "Ã": "A", "Ä": "A", "Å": "A", "Æ": "A", "Ç": "C", 
    "È": "E", "É": "E", "Ê": "E", "Ë": "E", "Ì": "I", "Í": "I", "Î": "I", "Ï": "I",
    "Ð": "D", "Ñ": "N", "Ò": "O", "Ó": "O", "Ô": "O", "Õ": "O", "Ö": "O", "×": " ",
    "Ø": "O", "Ù": "U", "Ú": "U", "Û": "U", "Ü": "U", "Ý": "Y", "Þ": " ", "ß": "S"
}
 

и применить это сопоставление к столбцу фрейма данных?

Очищенный выходной фрейм данных должен быть следующим:

     colname
0   AAAAAAA
1         C
2      EEEE
3      IIII
4         D
5         N
6     OOOOO
7          
8         O
9      UUUU
10        Y
11         
12        S
 

Ответ №1:

Да, вы определенно можете это сделать! Имейте в виду, что существуют важные различия между встроенными replace() и pandas Series.replace(). Последний позволяет передавать словарь и выполнять несколько замен одновременно. В заключение я рекомендую использовать pandas Series.replace() с вашими словарями:

 df["colname"] = df["colname"].replace(sub_dict,regex=True)
 

Комментарии:

1. Это аккуратно, ха-ха, не знал, что вы можете перейти regex=True к .replace

2. Да @Toukenize, и это позволяет передавать гораздо больше объектов (списки, dicts), это намного более гибкий imo.

Ответ №2:

Вы можете преобразовать строку в список символов, разбить список и применить сопоставление sub_dict к каждому символу, а затем снова сгруппировать символы:

 df_out = (
    df['colname']
    .apply(list)
    .explode()
    .map(sub_dict)
    .groupby(level=0)
    .apply(lambda x : ''.join(x))
)
 

что дает вам желаемый результат:

     colname
0   AAAAAAA
1   C
2   EEEE
3   IIII
4   D
5   N
6   OOOOO
7   
8   O
9   UUUU
10  Y
11  
12         # Check your mapping for "ß", which currently maps to " " instead of "S"