Estoy tratando de usar numpy.select
para reemplazar los valores de cadena dentro de una columna; si la cadena contiene una palabra clave, necesito que toda la cadena sea reemplazada por otra palabra clave (hay + - 25 combinaciones).
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",
)
¿Hay una forma más concisa, o debería repetir str.contains(...)
dentro de condlist
25 veces ?; ¿es numpy.select
la forma correcta de hacerlo, en absoluto?
Supongo que dict
podría usarse aquí, pero no veo cómo exactamente.
df["col"].map(d)
donde d
es un dict con valores antiguos y nuevos como {"cat1":"NEW_cat1"}
no funcionaría (?) Ya que no puedo codificar valores exactos que necesitan ser reemplazados (y es por eso que estoy usando str.contains
).
3 respuestas
El contenido que está pasando como los parámetros condlist
y choicelist
son listas de Python normales. El contenido de la lista se puede producir de manera concisa en el lenguaje mediante el uso de las comprensiones de la lista, es decir, la sintaxis: [expression_using_item for item in sequence]
En otras palabras, su código se puede escribir como:
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",
)
(y si los nombres de categoría no son una secuencia numérica, y está dando estos nombres aquí solo como un ejemplo, crea una secuencia (lista) con todos los nombres explícitos de categoría y la conecta en lugar de la llamada range()
en el fragmento de arriba)
Basado en esta respuesta a una pregunta similar, y este, una solución simple:
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
Debería poder utilizar str.extract
y luego asignar las coincidencias.
Preparar
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']
Código
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
Si existe la posibilidad de múltiples coincidencias y necesitamos implementar una jerarquía en la que la 'pizza' debe tener prioridad sobre 'foo', podemos agregar algunos pasos más usando un tipo de categoría ordenado.
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
Preguntas relacionadas
Preguntas vinculadas
Nuevas preguntas
python
Python es un lenguaje de programación multipropósito, de tipificación dinámica y de múltiples paradigmas. Está diseñado para ser rápido de aprender, comprender y usar, y hacer cumplir una sintaxis limpia y uniforme. Tenga en cuenta que Python 2 está oficialmente fuera de soporte a partir del 01-01-2020. Aún así, para preguntas de Python específicas de la versión, agregue la etiqueta [python-2.7] o [python-3.x]. Cuando utilice una variante de Python (por ejemplo, Jython, PyPy) o una biblioteca (por ejemplo, Pandas y NumPy), inclúyala en las etiquetas.