Значения Remap в столбце pandas с dict
У меня есть словарь, который выглядит следующим образом: di = {1: "A", 2: "B"}
Я хотел бы применить его к столбцу "col1" в кадре данных, подобном:
col1 col2
0 w a
1 1 2
2 2 NaN
чтобы получить:
col1 col2
0 w a
1 A 2
2 B NaN
Как я могу это сделать? По какой-то причине условия, относящиеся к этой теме, только показывают мне, как создавать столбцы из dicts и наоборот: -/
Ответы
Ответ 1
Вы можете использовать .replace
. Например:
>>> 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
или непосредственно в Series
, т.е. df["col1"].replace(di, inplace=True)
.
Ответ 2
map
может быть намного быстрее, чем replace
Если ваш словарь содержит более пары ключей, использование map
может быть намного быстрее, чем replace
. Существует две версии этого подхода, в зависимости от того, исчерпывающе ли сопоставляет ваш словарь все возможные значения (а также от того, хотите ли вы, чтобы несоответствия сохранили свои значения или были преобразованы в NaN):
Исчерпывающее картографирование
В этом случае форма очень проста:
df['col1'].map(di) # note: if the dictionary does not exhaustively map all
# entries then non-matched entries are changed to NaNs
Хотя map
чаще всего принимает функцию в качестве аргумента, в качестве альтернативы она может использовать словарь или серию: Документация для Pandas.series.map
Неисчерпывающее картографирование
Если у вас неисчерпывающее отображение и вы хотите сохранить существующие переменные для несоответствий, вы можете добавить fillna
:
df['col1'].map(di).fillna(df['col1'])
как в @jpp, ответьте здесь: Замените значения в ряду панд через словарь эффективно
Ориентиры
Используя следующие данные с пандами версии 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 ) })
и тестирование с %timeit
, похоже, что map
примерно в 10 раз быстрее, чем replace
.
Обратите внимание, что ваше ускорение с map
будет зависеть от ваших данных. Наибольшее ускорение, по-видимому, связано с большими словарями и исчерпывающими заменами. См. Ответ @jpp (ссылка выше) для более подробных тестов и обсуждения.
Ответ 3
В вашем вопросе есть немного двусмысленности. По меньшей мере три две интерпретации:
- ключи в
di
относятся к значениям индекса
- ключи в
di
относятся к df['col1']
значениям
- ключи в
di
относятся к местоположениям индекса (а не к вопросу OP, но выбрасываются для удовольствия.)
Ниже приведено решение для каждого случая.
Случай 1:
Если ключи di
предназначены для обозначения значений индекса, вы можете использовать метод update
:
df['col1'].update(pd.Series(di))
Например,
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)
дает
col1 col2
1 w a
2 B 30
0 A NaN
Я изменил значения из вашего исходного сообщения, чтобы было ясно, что делает update
.
Обратите внимание, что ключи в di
связаны с значениями индекса. Порядок значений индекса, то есть расположение индекса, не имеет значения.
Случай 2:
Если ключи в di
относятся к значениям df['col1']
, то @DanAllan и @DSM показывают, как это сделать с помощью 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)
дает
col1 col2
1 w a
2 A 30
0 B NaN
Обратите внимание, что в этом случае ключи в di
были изменены для соответствия значениям в df['col1']
.
Случай 3:
Если ключи в di
относятся к местоположениям индекса, вы можете использовать
df['col1'].put(di.keys(), di.values())
так
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)
дает
col1 col2
1 A a
2 10 30
0 B NaN
Здесь первая и третья строки были изменены, поскольку ключи в di
являются 0
и 2
, которые с индексированием на основе Python 0 относятся к первому и третьему местоположениям.
Ответ 4
Добавление к этому вопросу, если у вас когда-либо было несколько столбцов для переназначения в фрейме данных данных:
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
Надеюсь, что это может быть полезно кому-то.
Приветствия
Ответ 5
У DSM есть принятый ответ, но кодирование, кажется, не работает для всех. Вот тот, который работает с текущей версией панд (0.23.4 по состоянию на 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())
Вы увидите, что это выглядит так:
col1 col2 converted_column
0 1 negative -1
1 2 positive 1
2 2 neutral 0
3 3 neutral 0
4 1 positive 1
Документы для панд. DataFrame.replace здесь.
Ответ 6
Более родной подход панд заключается в применении функции замены, как показано ниже:
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)
После того, как вы определили функцию, вы можете применить ее к вашему фрейму данных.
di = {1: "A", 2: "B"}
df['col1'] = df.apply(lambda row: multiple_replace(di, row['col1']), axis=1)
Ответ 7
Или apply
:
df['col1'].apply(lambda x: {1: "A", 2: "B"}.get(x,x))
Демо-версия:
>>> 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
>>>
Ответ 8
Хорошее законченное решение, которое хранит карту меток ваших классов:
labels = features['col1'].unique()
labels_dict = dict(zip(labels, range(len(labels))))
features = features.replace({"col1": labels_dict})
Таким образом, вы можете в любой момент сослаться на оригинальную метку класса из label_dict.