Результаты регулярных выражений в новом столбце не работают должным образом (Панды)

#python #regex #pandas

Вопрос:

Я использую набор данных Titanic, чтобы научиться очищать данные. Сейчас я пытаюсь создать новую колонку с заголовками из колонки Имен (Мистер, миссис, Доктор и т. Д.) И сгруппировать их по социальному классу:

 Dr. – Doctor
Rev. – Clerical
Master. – Scholar 
Major., Col., Capt. – Military 
Mr., Mrs., Ms., Miss. – Commoners
Don., Sir., Mme., Mlle., Lady., Countess., Jonkheer. – Nobility 
 

Я создал функцию, которая по большей части работает, за исключением того, что все значения возвращаются « Other .

 import os
import re

filename = os.path.join(os.path.dirname(__file__),'train.csv')
data = pd.read_csv(filename)

def create_title_column(data, colname):
    def search_title(x):
        title_search = re.search('s([A-Za-z] ).', x)
        if title_search:
            title = title_search.groups(0)
            if title == 'Rev.':
                return 'Clerical'
            elif title == 'Master.':
                return 'Scholar'
            elif title == 'Dr.':
                return 'Doctor'
            elif title in ['Major.', 'Col.', 'Capt.']:
                return 'Military'
            elif title in ['Mr.','Mrs.','Ms.','Miss.']:
                return 'Commoner'
            elif title in ['Don.','Sir.','Mme.','Mlle.','Lady.','Countess.','Jonkheer.']:
                return 'Nobility'
            else:
                return 'Other'

    return_titles = data[colname].apply(search_title)
    dict_title = {1: 'Clerical', 2:'Scholar', 3:'Doctor', 4:'Military',5:'Commoner',6:'Nobility'}
    return return_titles.replace(dict_title)
data['Title'] = create_title_column(data, 'Name')

print(data.head(10))
 

Я не знаю, что я делаю не так. Кроме того, если вы знаете лучший, более лаконичный способ сделать это, пожалуйста, покажите мне. Любая помощь была бы отличной, поэтому заранее благодарю вас за потраченное время.

Вы можете скачать набор данных Titanic здесь: https://www.kaggle.com/hesh97/titanicdataset-traincsv

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

1. У вас есть начальные пробелы.

2. Эй, @garagnoth , спасибо, что вмешался. Я добавил re.search(‘s[A-Za-z] .’, x), но он все равно не будет работать

3. Я представил свою версию ниже. Тебе нужно это сделать title_search.groups(0).strip()

Ответ №1:

IIUC:

 import pandas as pd
import re
 

Считывание данных из локального хранилища

 data = pd.read_csv('titanic_train.csv')
 

Определить функцию:

 def search_title(x):
    if x == 'Rev.':
        return 'Clerical'
    if x == 'Mr':
        return 'Commoner'
    elif x == 'Master.':
        return 'Scholar'
    elif x == 'Dr.':
        return 'Doctor'
    elif x in ['Major.', 'Col.', 'Capt.']:
        return 'Military'
    elif x in ['Mr.','Mrs.','Ms.','Miss.']:
        return 'Commoner'
    elif x in ['Don.','Sir.','Mme.','Mlle.','Lady.','Countess.','Jonkheer.']:
        return 'Nobility'
    else:
        return 'Other'
 

Применяются два шага (поскольку я новичок, мне легче читать):

 data['Title'] = data['Name'].apply(lambda x: re.search(' ([A-Za-z] ).', x).group(0))
data['Title'] = data['Title'].apply(lambda x: search_title(x.strip()))
 

Выход:

введите описание изображения здесь

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

1. lol Намного проще, чем то, к чему я стремился. Это прекрасно работает! Однако есть еще одна проблема, но я думаю, что она не связана с кодом. По какой-то причине он также читает Дворянство как простолюдинов. Например, если вы перейдете к самому csv-файлу и выполните поиск Здесь, вы также получите все промахи. Понятия не имею, почему.

2. Ну, в данных о поезде есть только 1 Дама (Дафф Гордон, Леди. (Люсиль Кристиана Сазерленд) («Миссис Морган»)) и это правильно обозначено как Благородство.

3. Хорошо, мне нужно взглянуть на файл. Но сначала мне нужно поспать, лол. Здесь сейчас 4 часа утра. Я продолжу это завтра и дам вам знать. Спасибо вам за помощь!

Ответ №2:

Существует отличная функция для таких задач, как ваша, предлагаемая в numpy пакете, select . Это векторизованное решение, и оно помогает поддерживать ваш код в чистоте. Поэтому я бы не рекомендовал определять функцию для вашей задачи.

Я бы сначала начал с извлечения названий из столбца » Имя «(т. Е. «Мистер», «Мисс»,»Клерикальный»..).

Важно создать цепочку str.stip() в конце, чтобы исключить нежелательные пробелы.

 # Grab the titles from the Name column
df['title']=df.Name.str.split(',').str[1].str.split('.').str[0].str.strip()
>>> df['title'].value_counts()

 Mr              517
 Miss            182
 Mrs             125
 Master           40
 Dr                7
 Rev               6
 Mlle              2
 Major             2
 Col               2
 Ms                1
 Don               1
 Capt              1
 Sir               1
 Lady              1
 the Countess      1
 Jonkheer          1
 Mme               1
Name: title, dtype: int64
 

В следующем фрагменте кода я указываю, что такое текущее название и на что должно быть изменено каждое название. Пожалуйста, имейте в виду, что порядок имеет значение (т. е. Преподобный будет Священнослужителем, Магистр будет Ученым и т. Д.)

 # Import numpy package
import numpy as np

# Set the current titles that you have in the column
current_titles  = [
              df['title'] == 'Rev',
              df['title'] == 'Master',
              df['title'] == 'Dr',
              df['title'].isin(['Major', 'Col', 'Capt']),
              df['title'].isin(['Mr','Mrs','Ms','Miss']),
              df['title'].isin(['Don','Sir','Mme','Mlle','Lady','Countess','Jonkheer'])
              ]
# Set the new title to each title.
title_changes     = ['Clerical','Scholar','Doctor','Military','Commoner','Nobility']
 

Указав ваши conditions (current_titles) и ваши choices (title_changes), которые являются 2 из 3 параметров, которые np.select требуются, вы можете создать свой новый столбец с обновленными данными:

 df["title_refined"] = np.select(current_titles, title_changes, default="Other")
 

Печать 3 столбцов, чтобы четко проиллюстрировать различия, дает ожидаемый результат:

 >>> df[['Name','title','title_refined']]

                                                  Name title title_refined
0                              Braund, Mr. Owen Harris    Mr      Commoner
1    Cumings, Mrs. John Bradley (Florence Briggs Th...   Mrs      Commoner
2                               Heikkinen, Miss. Laina  Miss      Commoner
3         Futrelle, Mrs. Jacques Heath (Lily May Peel)   Mrs      Commoner
4                             Allen, Mr. William Henry    Mr      Commoner
..                                                 ...   ...           ...
886                              Montvila, Rev. Juozas   Rev      Clerical
887                       Graham, Miss. Margaret Edith  Miss      Commoner
888           Johnston, Miss. Catherine Helen "Carrie"  Miss      Commoner
889                              Behr, Mr. Karl Howell    Mr      Commoner
890                                Dooley, Mr. Patrick    Mr      Commoner
 

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

1. Эй, софолы, это очень мило! Однако мне нужно пересмотреть свою глупость. Я попытаюсь повторить ваш ответ и дам вам знать, однако я вижу, что на выходе отображается «Другое» для многих ячеек. У меня также возникли проблемы с моим исходным кодом и версией @garagnoth. По какой-то причине все дворяне, например, все еще читают как простолюдины. Леди читается как мисс.

2. Я отредактировал свой ответ, причина, по которой было слишком много «Других», заключается в том, что я неправильно набрал названия. Теперь это исправлено. Что вы имеете в виду, когда Благородство все еще читается как простолюдин? Дворянство и Простолюдин в настоящее время не существуют в столбце «Название», это ваши новые изменения..

3. Неважно, это была моя ошибка. Здесь уже слишком поздно. Мне нужно немного поспать. Я скопирую ваш код завтра и свяжусь с вами. А пока я озвучу ваш ответ. Спасибо вам за помощь!