Переопределение значений в колонке pandas с помощью словаря, сохраняя NaN значения
У меня есть словарь, который выглядит так: di = {1: "A", 2: "B"}
.
Я хотел бы применить этот словарь к столбцу col1
в DataFrame, который выглядит примерно так:
col1 col2
0 w a
1 1 2
2 2 NaN
В результате я хочу получить следующий DataFrame:
col1 col2
0 w a
1 A 2
2 B NaN
Как лучше всего это сделать?
5 ответ(ов)
В вашем вопросе есть небольшая неоднозначность. Существует как минимум две интерпретации:
- Ключи в
di
ссылаются на значения индексов. - Ключи в
di
ссылаются на значенияdf['col1']
.
Ниже приведены решения для каждого случая.
Случай 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"}
# Значение по индексу 0 заменяется на 'A', значение по индексу 2 заменяется на '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']
, то вы можете использовать метод replace
, как показали @DanAllan и @DSM:
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"}
# Значения 10 и 20 заменяются на 'A' и 'B'
df['col1'].replace(di, inplace=True)
print(df)
результат будет:
col1 col2
1 w a
2 A 30
0 B NaN
Обратите внимание, что в этом случае ключи в di
были изменены, чтобы соответствовать значениям в df['col1']
.
Если у вас есть дополнительные вопросы или требуется уточнение, пожалуйста, дайте знать!
При использовании map
, который быстрее, чем replace
(по решению @JohnE), нужно быть осторожным с неполными отображениями, когда вы собираетесь сопоставлять определенные значения с NaN
. В этом случае правильный подход требует, чтобы вы сначала маскировали
Series перед вызовом .fillna
, иначе вы аннулируете сопоставление с NaN
.
Вот пример кода на Python с использованием библиотеки pandas:
import pandas as pd
import numpy as np
d = {'m': 'Male', 'f': 'Female', 'missing': np.NaN}
df = pd.DataFrame({'gender': ['m', 'f', 'missing', 'Male', 'U']})
Здесь мы создаем список ключей, для которых значения являются NaN
:
keep_nan = [k for k, v in d.items() if pd.isnull(v)]
s = df['gender']
Затем мы применяем map
и корректно обрабатываем NaN
:
df['mapped'] = s.map(d).fillna(s.mask(s.isin(keep_nan)))
В результате мы получаем следующий DataFrame:
gender mapped
0 m Male
1 f Female
2 missing NaN
3 Male Male
4 U U
Таким образом, вы видите, что для элементов, которые отсутствуют в словаре d
, и для которых вы хотите, чтобы результат был NaN, правильный подход заключается в использовании маскировки fillna
.
Вы можете обновить ваш словарь отображений, добавив недостающие пары из DataFrame. Например:
import pandas as pd
import numpy as np
df = pd.DataFrame({'col1': ['a', 'b', 'c', 'd', np.nan]})
map_ = {'a': 'A', 'b': 'B', 'd': np.nan}
# Получаем уникальные значения из df
uniques = df['col1'].unique()
map_new = dict(zip(uniques, uniques))
# {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd', nan: nan}
# Обновляем отображение
map_new.update(map_)
# {'a': 'A', 'b': 'B', 'c': 'c', 'd': nan, nan: nan}
df['col2'] = df['col1'].map(map_new)
Результат будет следующим:
col1 col2
0 a A
1 b B
2 c c
3 d NaN
4 NaN NaN
Таким образом, вы сможете эффективно расширить ваше отображение, включая новые значения из DataFrame.
Если у вас есть более одного столбца, которые необходимо переименовать в DataFrame, вот функция, которая может быть полезна:
def remap(data, dict_labels):
"""
Эта функция принимает словарь меток: dict_labels
и заменяет значения (предварительно закодированные с помощью label encoding) на строки.
Пример: dict_labels = {'col1': {1: 'A', 2: 'B'}}
"""
for field, values in dict_labels.items():
print("Я переименовываю столбец %s" % field)
data.replace({field: values}, inplace=True)
print("ГОТОВО")
return data
Надеюсь, это будет полезно кому-то.
С уважением!
Вы можете использовать метод apply
для обработки значений в столбце DataFrame следующим образом:
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
В этом примере все значения в столбце col1
, которые равны 1 и 2, будут заменены на "A" и "B" соответственно, а остальные значения останутся без изменений.
Преобразование списка словарей в DataFrame pandas
Преобразование словаря Python в DataFrame
Объединение двух столбцов текста в DataFrame pandas
Получить список из колонки или строки DataFrame в pandas?
Выбор строки из pandas Series/DataFrame по целочисленному индексу