Как заменить группу строк в серии панд на основе словаря значениями в виде списка? - PullRequest
0 голосов
/ 31 октября 2018

Я не смог найти решение в stackoverflow для замены на основе словаря, где значения находятся в списке.

Словарь

dct  = {"LOL": ["laught out loud", "laught-out loud"],
        "TLDR": ["too long didn't read", "too long; did not read"],
        "application": ["app"]}

Ввод

input_df = pd.DataFrame([("haha too long didn't read and laught out loud :D"),
                         ("laught-out loud so I couldnt too long; did not read"),
                         ("what happened?")], columns=['text'])

Ожидаемый результат

output_df = pd.DataFrame([("haha TLDR and LOL :D"),
                          ("LOL so I couldnt TLDR"),
                          ("what happened?")], columns=['text'])

Редактировать

Добавлена ​​дополнительная запись в словарь, т. Е. "Application": ["app"]

Текущие решения дают результат как "что радует?"

Пожалуйста, предложите исправление.

Ответы [ 4 ]

0 голосов
/ 31 октября 2018

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

import itertools
dict_rev = dict(itertools.chain.from_iterable([list(zip(v, [k]*len(v))) for k, v in dct.items()]))

Который не очень удобочитаемый. Или этот, который выглядит лучше, и я украл из другого ответа:

dict_rev = {v : k for k, V in dct.items() for v in V}

Для этого необходимо, чтобы каждое из значений в вашем словаре находилось в списке (или других итерируемых), например "new key": ["single_val"] в противном случае будет взорван каждый символ в строке.

Затем вы можете сделать следующее (основываясь на приведенном здесь коде Как заменить несколько подстрок строки? )

import re
rep = dict((re.escape(k), v) for k, v in dict_rev.items())
pattern = re.compile("|".join(rep.keys()))
input_df["text"] = input_df["text"].str.replace(pattern, lambda m: rep[re.escape(m.group(0))])

Этот метод работает примерно в 3 раза быстрее, чем более простое и элегантное решение:

Simple:

%timeit input_df["text"].replace(dict_rev, regex=True)

425 µs ± 38.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Быстрее:

%timeit input_df["text"].str.replace(pattern, lambda m: rep[re.escape(m.group(0))])

160 µs ± 7.78 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
0 голосов
/ 31 октября 2018

Вот как я пойду:

import pandas as pd


dct  = {"LOL": ["laught out loud", "laught-out loud"],
        "TLDR": ["too long didn't read", "too long; did not read"]
        }

input_df = pd.DataFrame([("haha too long didn't read and laught out loud :D"),
       ("laught-out loud so I couldnt too long; did not read")], columns=['text'])

dct_inv = {}
for key, vals in dct.items():
    for val in vals:
        dct_inv[val]=key

dct_inv

def replace_text(input_str):
    for key, val in dct_inv.items():
        input_str = str(input_str).replace(key, val)
    return input_str

input_df.apply(replace_text, axis=1).to_frame()
0 голосов
/ 31 октября 2018

Создайте перевернутое отображение и используйте Series.replace с regex=True.

mapping = {v : k for k, V in dct.items() for v in V}
input_df['text'] = input_df['text'].replace(mapping, regex=True)

print(input_df)
                    text
0   haha TLDR and LOL :D
1  LOL so I couldnt TLDR

Где,

print(mapping)
{'laught out loud': 'LOL',
 'laught-out loud': 'LOL',
 "too long didn't read": 'TLDR',
 'too long; did not read': 'TLDR'}

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

mapping = {rf'\b{v}\b' : k for k, V in dct.items() for v in V}
input_df['text'] = input_df['text'].replace(mapping, regex=True)

print(input_df)
                    text
0   haha TLDR and LOL :D
1  LOL so I couldnt TLDR
2         what happened?

Где,

print(mapping)
{'\\bapp\\b': 'application',
 '\\blaught out loud\\b': 'LOL',
 '\\blaught-out loud\\b': 'LOL',
 "\\btoo long didn't read\\b": 'TLDR',
 '\\btoo long; did not read\\b': 'TLDR'}
0 голосов
/ 31 октября 2018

Использование df.apply и пользовательская функция

Ex:

import pandas as pd


def custReplace(value):
    dct  = {"LOL": ["laught out loud", "laught-out loud"],
        "TLDR": ["too long didn't read", "too long; did not read"]
        }

    for k, v in dct.items():
        for i in v:
            if i in value:
                value = value.replace(i, k)
    return value

input_df = pd.DataFrame([("haha too long didn't read and laught out loud :D"),
       ("laught-out loud so I couldnt too long; did not read")], columns=['text'])

print(input_df["text"].apply(custReplace))

Выход:

0     haha TLDR and LOL :D
1    LOL so I couldnt TLDR
Name: text, dtype: object

или

dct  = {"LOL": ["laught out loud", "laught-out loud"],
        "TLDR": ["too long didn't read", "too long; did not read"]
        }

dct = { "(" + "|".join(v) + ")": k for k, v in dct.items()}
input_df = pd.DataFrame([("haha too long didn't read and laught out loud :D"),
       ("laught-out loud so I couldnt too long; did not read")], columns=['text'])

print(input_df["text"].replace(dct, regex=True))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...