Python. Заменить подстроку вначале текстовой строки в датафрейме на основании другого датафрейма

Есть два датафрейма:

reference = [['поселок ', 'поселок'], ['посёлок ', 'поселок'], ['п ', 'поселок'], ['п. ', 'поселок']]
reference = pd.DataFrame(reference, columns = ['dirty', 'clean'])

data = [['посёлок Подгорный'], ['посeлок Глинка'], ['п. Новокамышенка']]
data = pd.DataFrame(data, columns = ['setll'])

Хочу сделать проверку: если setll из data начинается на одно из значений dirty из reference, то из setll извлечь dirty. Пробую так:

def extract_settl_type(df_column):
    for dirty, clean in reference.itertuples(index=False):
        if df_column.startswith(dirty):
            setll_norm = df_column.replace(dirty, '')
            setll_type_norm = clean
            return setll_norm, setll_type_norm
        else:
            return None
    
data['setll_norm'] = data['setll'].apply(extract_settl_type)

Но возвращается None: | |setll | setll_norm | | --------- |--------- | -------------- | |0 |посёлок Подгорный |None| |1 |посeлок Глинка |None| |2 |п. Новокамышенка |None|

Хотя если пробовать на отдельном значении:

strr = 'посёлок Подгорный'
for dirty, clean in reference.itertuples(index=False):
    if strr.startswith(dirty):
        print(dirty)

То возвращается "посёлок ", то есть не None. Камрады, что я упускаю в функции extract_settl_type? :с


Ответы (1 шт):

Автор решения: Максим Науменко

Немного оптимизировал и поменял нейминги. Если я правилно понял задачу, то вот мой вариант:

import pandas as pd

references = pd.DataFrame(
    columns=['dirty', 'clean'],
    data=[['посёлок', 'поселок'],
          ['п', 'поселок'],
          ['п.', 'поселок']]
)
data = pd.DataFrame(
    columns=['raw_locality'],
    data=[['посёлок Подгорный'],
          ['посeлок Глинка'],
          ['п. Новокамышенка']]
)


def locality_type_replacer(raw_str: str) -> str:
    """
    Replace locality type
    """
    split_string: list = raw_str.split(" ")
    raw_type = split_string[0] if len(split_string) > 1 else None

    # Check raw_type exist, raw_type in references, string starts of raw_type
    if not any((
            raw_type,
            raw_type in tuple(references['dirty']),
            raw_str.startswith(raw_type)
    )):
        return raw_str

    # Get index for mapping
    index = references.dirty[references.dirty == 'п'].index

    # Get value for rename
    mapped_value = references.clean[index].item()

    # Replace locality type
    split_string[0] = mapped_value

    return ' '.join(split_string)


data['locality'] = data['raw_locality'].apply(locality_type_replacer)
data

result

→ Ссылка