python - sumar - Reasignación de valores en la columna de pandas con un dict
recorrer un diccionario en python (5)
Tengo un diccionario que se ve así: di = {1: "A", 2: "B"}
Me gustaría aplicarlo a la columna "col1" de un marco de datos similar a:
col1 col2
0 w a
1 1 2
2 2 NaN
Llegar:
col1 col2
0 w a
1 A 2
2 B NaN
¿Cómo puedo hacer esto mejor? Por alguna razón, los términos de Google relacionados con esto solo me muestran enlaces sobre cómo hacer columnas a partir de dicts y viceversa: - /
Agregando a esta pregunta si alguna vez tiene más de una columna para reasignar en un dataframe:
def remap(data,dict_labels):
"""
This function take in a dictionnary of labels : dict_labels
and replace the values (previously labelencode) into the string.
ex: dict_labels = {{''col1'':{1:''A'',2:''B''}}
"""
for field,values in dict_labels.items():
print("I am remapping %s"%field)
data.replace({field:values},inplace=True)
print("DONE")
return data
Espero que pueda ser útil para alguien.
Aclamaciones
Esta es una respuesta alternativa que puede ser mucho más rápida cuando su diccionario tiene más de un par de claves. Si su diccionario mapea exhaustivamente todos los valores posibles, esto toma una forma muy simple:
df[''col1''].map(di) # note: if the dictionary does not exhaustively map all
# entries then non-matched entries are changed to NaNs
Aunque el map
toma más comúnmente una función como argumento, alternativamente puede tomar un diccionario o una serie: Documentación para Pandas.series.map
Sin un mapeo exhaustivo, debe agregar la update
si desea evitar que las no concordancias se cambien a NaN.
df[''col1''].update( df[''col1''].map(di) ) # note: series update is an inplace operation
Aquí hay algunos tiempos para el caso exhaustivo en un marco de datos con 100.000 filas y 8 teclas de diccionario (es aproximadamente 10 veces más rápido).
di = {1: "A", 2: "B", 3: "C", 4: "D", 5: "E", 6: "F", 7: "G", 8: "H" }
df = pd.DataFrame({ ''col1'': np.random.choice( range(1,9), 100000 ) })
%timeit df.replace({"col1": di})
10 loops, best of 3: 55.6 ms per loop
%timeit df[''col1''].map(di)
100 loops, best of 3: 4.16 ms per loop
Hay un poco de ambigüedad en tu pregunta. Hay al menos tres interpretaciones:
- las claves en
di
refieren a valores de índice - las teclas en
di
referencia adf[''col1'']
valoresdf[''col1'']
- las claves en
di
refieren a las ubicaciones de los índices (no la pregunta del OP, sino que se envían por diversión).
A continuación hay una solución para cada caso.
Caso 1: Si las claves de di
están destinadas a referirse a valores de índice, entonces podría usar el método de update
:
df[''col1''].update(pd.Series(di))
Por ejemplo,
import pandas as pd
import numpy as np
df = pd.DataFrame({''col1'':[''w'', 10, 20],
''col2'': [''a'', 30, np.nan]},
index=[1,2,0])
# col1 col2
# 1 w a
# 2 10 30
# 0 20 NaN
di = {0: "A", 2: "B"}
# The value at the 0-index is mapped to ''A'', the value at the 2-index is mapped to ''B''
df[''col1''].update(pd.Series(di))
print(df)
rendimientos
col1 col2
1 w a
2 B 30
0 A NaN
Modifiqué los valores de tu publicación original para que quede más claro qué está haciendo la update
. Observe cómo las claves en di
están asociadas con valores de índice. El orden de los valores de índice, es decir, las ubicaciones de índice, no importa.
Caso 2: Si las claves en di
referencia a df[''col1'']
valores df[''col1'']
, entonces @DanAllan y @DSM muestran cómo lograr esto con replace
:
import pandas as pd
import numpy as np
df = pd.DataFrame({''col1'':[''w'', 10, 20],
''col2'': [''a'', 30, np.nan]},
index=[1,2,0])
print(df)
# col1 col2
# 1 w a
# 2 10 30
# 0 20 NaN
di = {10: "A", 20: "B"}
# The values 10 and 20 are replaced by ''A'' and ''B''
df[''col1''].replace(di, inplace=True)
print(df)
rendimientos
col1 col2
1 w a
2 A 30
0 B NaN
Observe cómo en este caso las claves en di
se cambiaron para hacer coincidir los valores en df[''col1'']
.
Caso 3: si las claves en di
refieren a ubicaciones de índice, entonces podrías usar
df[''col1''].put(di.keys(), di.values())
ya que
df = pd.DataFrame({''col1'':[''w'', 10, 20],
''col2'': [''a'', 30, np.nan]},
index=[1,2,0])
di = {0: "A", 2: "B"}
# The values at the 0 and 2 index locations are replaced by ''A'' and ''B''
df[''col1''].put(di.keys(), di.values())
print(df)
rendimientos
col1 col2
1 A a
2 10 30
0 B NaN
Aquí, la primera y la tercera filas fueron alteradas, porque las claves en di
son 0
y 2
, que con la indexación basada en 0 de Python se refieren a la primera y tercera ubicación.
Puedes usar .replace
. Por ejemplo:
>>> df = pd.DataFrame({''col2'': {0: ''a'', 1: 2, 2: np.nan}, ''col1'': {0: ''w'', 1: 1, 2: 2}})
>>> di = {1: "A", 2: "B"}
>>> df
col1 col2
0 w a
1 1 2
2 2 NaN
>>> df.replace({"col1": di})
col1 col2
0 w a
1 A 2
2 B NaN
o directamente en la Series
, es decir, df["col1"].replace(di, inplace=True)
.
Un enfoque más pandas nativos es aplicar una función de reemplazo de la siguiente manera:
def multiple_replace(dict, text):
# Create a regular expression from the dictionary keys
regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
# For each match, look-up corresponding value in dictionary
return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
Una vez que haya definido la función, puede aplicarla a su marco de datos.
di = {1: "A", 2: "B"}
df[''col1''] = df.apply(lambda row: multiple_replace(di, row[''col1'']), axis=1)