Переназначение значений в столбце 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
как я могу лучше всего это сделать? По какой-то причине термины googling, относящиеся к этому, показывают мне только ссылки о том, как сделать столбцы из диктов и наоборот :-/
7 ответов
можно использовать .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)
.
map
может быть намного быстрее, чем replace
если ваш словарь имеет более чем пару клавиш, с помощью map
может быть намного быстрее, чем replace
. Существует две версии этого подхода, в зависимости от того, полностью ли ваш словарь отображает все возможные значения (а также Хотите ли вы заменить несоответствия или оставить их как отсутствующие значения):
Исчерпывающее Отображение
в этом случае форма очень просто:
df['col1'].map(di) # note: if the dictionary does not exhaustively map all
# entries then non-matched entries are changed to NaNs
хотя map
чаще всего принимает функцию в качестве аргумента, он может альтернативно взять словарь или серию:документация для панд.серии.карта
Неисчерпывающее Отображение
если у вас есть неисчерпывающее отображение и вы хотите сохранить существующие переменные для несоответствий, вы можете добавить fillna
:
df['col1'].map(di).fillna(df['col1'])
как в ответе @jpp здесь:заменить значения в серии pandas через словарь эффективно
критерии
используя следующие данные с pandas версии 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 (связанный выше) для более обширных критериев и обсуждение.
в вашем вопросе есть немного двусмысленности. Есть по крайней мере три два толкования:
- ключи
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
are 0
и 2
, которые с индексированием на основе Python 0 относятся к первому и третьему местоположениям.
добавление к этому вопросу, если у вас когда-либо было более одного столбца для переназначения в фрейме данных:
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
надеюсь, что это может быть полезным кому-то.
Ура
DSM имеет принятый ответ, но кодирование, похоже, не работает для всех. Вот один, который работает с текущей версией pandas (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
документы на панды.Фрейм данных.заменить здесь.
более родной подход панд заключается в применении функции замены, как показано ниже:
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)
или 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
>>>