如何根据字典替换熊猫系列中的字符串组,并将值作为列表?
Posted
技术标签:
【中文标题】如何根据字典替换熊猫系列中的字符串组,并将值作为列表?【英文标题】:How to replace group of strings in pandas series based on a dictionary with values as list? 【发布时间】:2019-04-04 06:47:59 【问题描述】:我在 *** 中找不到基于列表中值的字典进行替换的解决方案。
字典
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'])
编辑
在字典中添加了一个附加条目,即“应用程序”:[“应用程序”]
当前的解决方案给出的输出是“应用了什么?”
请提出修复建议。
【问题讨论】:
【参考方案1】:构建一个反向映射并将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'\bv\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'
【讨论】:
太棒了!请为以下问题提出修复建议。在字典“application”中添加了一个附加条目:[“app”] 当前的解决方案给出的输出是“what happlicationened?” @ML_Pro 你的意思是你只希望它匹配整个单词?嗯,在这种情况下,尝试将“app”更改为 r“\bapp\b”,并对要替换的每个字符串执行此操作。这是一个正则表达式单词边界,它只匹配整个单词。 谢谢。但是,我正在从 JSON 文件加载字典。如何使用 python 代码将“app”转换为 r“\bapp\b”?我找不到将字符串转换为原始字符串的函数。接受您的回复作为答案。 优秀。明白了。【参考方案2】:这就是我要走的路:
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()
【讨论】:
【参考方案3】:使用df.apply
和自定义函数
例如:
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))
【讨论】:
【参考方案4】:我认为最合乎逻辑的起点是反转你的字典,这样你的键就是你的原始字符串,它映射到你的新字符串的值。您可以手动完成,也可以通过其他一百万种方式完成,例如:
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"]
否则会爆炸字符串中的每个字符。
然后您可以执行以下操作(基于此处的代码 How to replace multiple substrings of a string?)
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 倍:
简单:
%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)
【讨论】:
以上是关于如何根据字典替换熊猫系列中的字符串组,并将值作为列表?的主要内容,如果未能解决你的问题,请参考以下文章