python python-3.x pandas dictionary dataframe

python - Reemplazar valores en una serie de pandas a través del diccionario de manera eficiente



python-3.x dictionary (1)

Una solución trivial es elegir un método que dependa de una estimación de cuán completamente los valores están cubiertos por las claves del diccionario.

Caso general

  • Utilice df[''A''].map(d) si se asignaron todos los valores; o
  • Utilice df[''A''].map(d).fillna(df[''A'']).astype(int) si> 5% de valores asignados.

Pocos, por ejemplo, <5%, valores en d

  • Use df[''A''].replace(d)

El "punto de cruce" de ~ 5% es específico para la evaluación comparativa a continuación.

Curiosamente, una simple comprensión de la lista generalmente tiene un rendimiento inferior al del map en cualquier escenario.

Benchmarking

import pandas as pd, numpy as np df = pd.DataFrame({''A'': np.random.randint(0, 1000, 1000000)}) lst = df[''A''].values.tolist() ##### TEST 1 - Full Map ##### d = {i: i+1 for i in range(1000)} %timeit df[''A''].replace(d) # 1.98s %timeit df[''A''].map(d) # 84.3ms %timeit [d[i] for i in lst] # 134ms ##### TEST 2 - Partial Map ##### d = {i: i+1 for i in range(10)} %timeit df[''A''].replace(d) # 20.1ms %timeit df[''A''].map(d).fillna(df[''A'']).astype(int) # 111ms %timeit [d.get(i, i) for i in lst] # 243ms

Explicación

La razón por la cual el s.replace es tan lento es que hace mucho más que simplemente mapear un diccionario. Trata algunos casos extremos y situaciones posiblemente raras, que generalmente merecen más atención en cualquier caso.

Este es un extracto de replace() en pandas/generic.py .

items = list(compat.iteritems(to_replace)) keys, values = zip(*items) are_mappings = [is_dict_like(v) for v in values] if any(are_mappings): # handling of nested dictionaries else: to_replace, value = keys, values return self.replace(to_replace, value, inplace=inplace, limit=limit, regex=regex)

Parece que hay muchos pasos involucrados:

  • Conversión de diccionario a una lista.
  • Iterando a través de la lista y buscando diccionarios anidados.
  • Alimentando un iterador de claves y valores en una función de reemplazo.

Esto se puede comparar con un código mucho más delgado de map() en pandas/series.py :

if isinstance(arg, (dict, Series)): if isinstance(arg, dict): arg = self._constructor(arg, index=arg.keys()) indexer = arg.index.get_indexer(values) new_values = algos.take_1d(arg._values, indexer)

Cómo reemplazar valores en una serie Pandas s través de un diccionario d se ha pedido y vuelto a preguntar muchas veces.

El método recomendado ( 1 , 2 , 3 , 4 ) es usar s.replace(d) o, ocasionalmente, usar s.map(d) si todos los valores de su serie se encuentran en las teclas del diccionario.

Sin embargo, el rendimiento con s.replace menudo es irrazonablemente lento, a menudo 5-10 veces más lento que una simple lista de comprensión.

La alternativa, s.map(d) tiene un buen rendimiento, pero solo se recomienda cuando se encuentran todas las claves en el diccionario.

¿Por qué es tan lento s.replace y cómo se puede mejorar el rendimiento?

import pandas as pd, numpy as np df = pd.DataFrame({''A'': np.random.randint(0, 1000, 1000000)}) lst = df[''A''].values.tolist() ##### TEST 1 ##### d = {i: i+1 for i in range(1000)} %timeit df[''A''].replace(d) # 1.98s %timeit [d[i] for i in lst] # 134ms ##### TEST 2 ##### d = {i: i+1 for i in range(10)} %timeit df[''A''].replace(d) # 20.1ms %timeit [d.get(i, i) for i in lst] # 243ms

Nota: Esta pregunta no está marcada como duplicada porque busca consejos específicos sobre cuándo usar diferentes métodos dados diferentes conjuntos de datos. Esto es explícito en la respuesta y es un aspecto que generalmente no se aborda en otras preguntas.