我正在尝试使用numpy.select
替换列中的字符串值;如果字符串包含一个关键字,我需要将整个字符串替换为另一个关键字(有+-25个组合)。
df["new_col"] = np.select(
condlist=[
df["col"].str.contains("cat1", na=False, case=False),
df["col"].str.contains("cat2", na=False, case=False),
df["col"].str.contains("cat3", na=False, case=False),
df["col"].str.contains("cat4", na=False, case=False),
# ...
df["col"].str.contains("cat25", na=False, case=False),
],
choicelist=[
"NEW_cat1",
"NEW_cat2",
"NEW_cat3",
"NEW_cat4",
# ...
"NEW_cat25"
],
default="DEFAULT_cat",
)
是否有更简洁的方法,还是应该在str.contains(...)
内重复condlist
25次? numpy.select
到底是正确的方式吗?
我假设这里可以使用dict
,但看不出具体如何。
df["col"].map(d)
,其中d
是具有{"cat1":"NEW_cat1"}
之类的旧值和新值的字典,因为我无法对需要替换的确切值进行硬编码(并且这就是为什么我使用str.contains
)。
答案 0 :(得分:2)
应该能够使用str.extract
,然后映射匹配项。
import pandas as pd
import re
df = pd.DataFrame({'col': ['foo', 'foOBar', 'oRange', 'manGo', 'i LIKE PIZZA',
'some sentence with foo', 'foo and PizzA']})
cat_list = ['foo', 'orange', 'pizza'] # all lower case
label_l = ['Label_foo', 'Label_orange', 'Label_pizza']
patt = re.compile('('+'|'.join(cat_list)+')', re.IGNORECASE)
df['new_col'] = (df.col.str.extract(patt)[0] # First label in str if multiple
.str.lower()
.map(dict(zip(cat_list, label_l)))
.fillna('DEFAULT_LABEL'))
col new_col
0 foo Label_foo
1 foOBar Label_foo
2 oRange Label_orange
3 manGo DEFAULT_LABEL
4 i LIKE PIZZA Label_pizza
5 some sentence with foo Label_foo
6 foo and PizzA Label_foo
如果有可能出现多个匹配项,并且我们需要实现一个层次结构,在该层次结构中,“比萨饼”的优先级应高于“ foo”,我们可以使用有序类别dtype添加更多步骤。
cat_list = ['pizza', 'orange', 'foo'] # ordered in priority
label_l = ['Label_pizza', 'Label_orange', 'Label_foo']
my_cat = pd.api.types.CategoricalDtype(categories=cat_list, ordered=True)
s = (df.col.str.extractall(patt)[0]
.str.lower()
.astype(my_cat))
df['new_col'] = (s.to_frame().groupby(level=0).min()[0] # min gets priority
.map(dict(zip(cat_list, label_l))))
df['new_col'] = df['new_col'].astype(str).replace('nan', 'DEFAULT_LABEL')
# col new_col
#0 foo Label_foo
#1 foOBar Label_foo
#2 oRange Label_orange
#3 manGo DEFAULT_LABEL
#4 i LIKE PIZZA Label_pizza
#5 some sentence with foo Label_foo
#6 foo and PizzA Label_pizza
答案 1 :(得分:2)
作为condlist
和choicelist
参数传递的内容是普通的Python列表。列表内容可以通过使用列表理解(即语法[expression_using_item for item in sequence]
换句话说,您的代码可以写为:
df["new_col"] = np.select(
condlist=[
df["col"].str.contains(f"cat{i}", na=False, case=False) for i in range(1, 26)],
choicelist=[f"NEW_cat{i}" for i in range(1, 26)],
default="DEFAULT_cat",
)
(如果类别名称不是数字序列,并且您在此处给出这些名称仅作为示例,则使用所有显式类别名称创建一个序列(列表),并插入该名称代替
上方摘录中的range()
调用
答案 2 :(得分:2)
基于this answer to a similar question和this one,一个简单的解决方案:
import pandas as pd
import string
# Preparing test data
test_cont = [f"cat_{i}" for i in string.ascii_lowercase]
test_rep = [f"cat_{i}" for i in range(27)]
kv = zip(test_cont, test_rep)
test_df_data = zip(range(27), test_cont)
test_df = pd.DataFrame(data=test_df_data, columns=["some_col", "str_vals"])
# The solution itself
for (cont, rep) in kv:
cont_mask = test_df["str_vals"].str.contains(cont, na=False, case=False)
test_df.loc[cont_mask, "str_vals"] = rep