J'ai un dictionnaire qui ressemble à ceci: di = {1: "A", 2: "B"}
Je voudrais l'appliquer à la colonne "col1" d'un cadre de données similaire à:
col1 col2
0 w a
1 1 2
2 2 NaN
obtenir:
col1 col2
0 w a
1 A 2
2 B NaN
Comment puis-je le faire au mieux? Pour une raison quelconque, les termes de recherche sur Google relatifs à cela ne me montrent que des liens sur la création de colonnes à partir de dict et vice-versa: - /
Vous pouvez utiliser .replace
. Par exemple:
>>> 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
ou directement sur la Series
, c.-à-d. df["col1"].replace(di, inplace=True)
.
map
peut être beaucoup plus rapide que replace
Si votre dictionnaire comporte plus de deux clés, utiliser map
peut être beaucoup plus rapide que replace
. Il existe deux versions de cette approche, selon que votre dictionnaire mappe de manière exhaustive toutes les valeurs possibles (et que vous souhaitiez également que les non-correspondances conservent leurs valeurs ou soient converties en NaN):
Dans ce cas, le formulaire est très simple:
df['col1'].map(di) # note: if the dictionary does not exhaustively map all
# entries then non-matched entries are changed to NaNs
Bien que map
prenne le plus souvent une fonction comme argument, il peut aussi prendre un dictionnaire ou une série: Documentation for Pandas.series.map
Si vous avez un mappage non exhaustif et souhaitez conserver les variables existantes pour les non-correspondances, vous pouvez ajouter fillna
:
df['col1'].map(di).fillna(df['col1'])
comme dans la réponse de @ jpp ici: Remplacer efficacement les valeurs d'une série de pandas via le dictionnaire
Utilisation des données suivantes avec Pandas version 0.23.1:
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 ) })
et en testant avec %timeit
, il apparaît que map
est environ 10 fois plus rapide que replace
.
Notez que votre accélération avec map
variera avec vos données. La plus grande accélération semble concerner les grands dictionnaires et les remplacements exhaustifs. Voir la réponse @jpp (lien ci-dessus) pour des repères plus détaillés et une discussion.
Il y a un peu d'ambiguïté dans votre question. Il y a au moins trois deux interprétations:
di
font référence aux valeurs d'indexdi
font référence à df['col1']
valeursdi
font référence aux emplacements d'index (pas la question du PO, mais insérées pour le plaisir.)Vous trouverez ci-dessous une solution pour chaque cas.
Cas 1: Si les clés de di
sont censées faire référence à des valeurs d'index, vous pouvez utiliser la méthode update
:
df['col1'].update(pd.Series(di))
Par exemple,
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)
les rendements
col1 col2
1 w a
2 B 30
0 A NaN
J'ai modifié les valeurs de votre message d'origine afin de clarifier ce que update
fait . Notez comment les clés de di
sont associées à des valeurs d'index. L'ordre des valeurs d'index, c'est-à-dire l'indice locations - n'a pas d'importance.
Cas 2: Si les clés dans di
font référence à df['col1']
valeurs, alors @DanAllan et @DSM montrent comment y parvenir avec 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)
les rendements
col1 col2
1 w a
2 A 30
0 B NaN
Notez comment, dans ce cas, les clés dans di
ont été modifiées pour correspondre à values dans df['col1']
.
Cas 3: Si les clés dans di
font référence à des emplacements d'index, vous pourriez alors utiliser
df['col1'].put(di.keys(), di.values())
puisque
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)
les rendements
col1 col2
1 A a
2 10 30
0 B NaN
Ici, les première et troisième lignes ont été modifiées, car les clés dans di
sont 0
et 2
, qui, avec l'indexation à base de Python à 0, font référence aux premier et troisième emplacements.
Ajout à cette question si vous avez déjà plusieurs colonnes à remapper dans un cadre de données de données:
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
J'espère que cela peut être utile à quelqu'un.
À votre santé
DSM a la réponse acceptée, mais le codage ne semble pas fonctionner pour tout le monde. En voici une qui fonctionne avec la version actuelle de pandas (0.23.4 à partir du 8/2018):
import pandas as pd
df = pd.DataFrame({'col1': [1, 2, 2, 3, 1],
'col2': ['negative', 'positive', 'neutral', 'neutral', 'positive']})
conversion_dict = {'negative': -1, 'neutral': 0, 'positive': 1}
df['converted_column'] = df['col2'].replace(conversion_dict)
print(df.head())
Vous verrez que ça ressemble à:
col1 col2 converted_column
0 1 negative -1
1 2 positive 1
2 2 neutral 0
3 3 neutral 0
4 1 positive 1
Les docs pour pandas.DataFrame.replace sont ici .
Ou est-ce que apply
:
df['col1'].apply(lambda x: {1: "A", 2: "B"}.get(x,x))
Démo:
>>> df['col1']=df['col1'].apply(lambda x: {1: "A", 2: "B"}.get(x,x))
>>> df
col1 col2
0 w a
1 1 2
2 2 NaN
>>>
Une approche plus native des pandas consiste à appliquer une fonction de remplacement comme ci-dessous:
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)
Une fois que vous avez défini la fonction, vous pouvez l’appliquer à votre cadre de données.
di = {1: "A", 2: "B"}
df['col1'] = df.apply(lambda row: multiple_replace(di, row['col1']), axis=1)
Une solution complète et agréable qui garde une carte de vos étiquettes de classe:
labels = features['col1'].unique()
labels_dict = dict(Zip(labels, range(len(labels))))
features = features.replace({"col1": labels_dict})
De cette façon, vous pouvez à tout moment faire référence à l'étiquette de classe d'origine de labels_dict.