2013-11-27 3 views
102

У меня есть словарь, который выглядит следующим образом: di = {1: "A", 2: "B"}значения Переопределять в колонке панд с Dict

Я хотел бы применить его к «col1» столбца dataframe аналогично:

 col1 col2 
0  w  a 
1  1  2 
2  2 NaN 

для получения:

 col1 col2 
0  w  a 
1  A  2 
2  B NaN 

Как я могу это сделать? По какой-то причине условия, относящиеся к этой теме, только показывают мне, как создавать столбцы из dicts и наоборот: -/

ответ

119

Вы можете использовать .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).

+0

Это не работает для меня, если '' 'col''' является кортежем. Информация об ошибке - '' 'Невозможно сравнить типы 'ndarray (dtype = object)' и 'tuple'''' –

+3

Похоже, что это больше не работает ** **, что неудивительно, учитывая ответ был от 4 лет назад. Этот вопрос требует нового ответа, учитывая, насколько общая операция ... – PrestonH

+1

@PrestonH Он отлично работает для меня. Запуск: ''3.6.1 | Пользовательский Anaconda (64-разрядный) | (по умолчанию, 11 мая 2017, 13:25:24) [MSC v.1900 64 бит (AMD64)] '' – Dan

36

В вашем вопросе есть немного двусмысленности. Есть, по крайней мере три две интерпретации:

  1. ключей в di обратитесь к Заданным значениям
  2. ключей в di обратитесь к df['col1'] значениям
  3. ключей в di обратитесь к местам индекса (не параметры порядка вопрос, но брошен в удовольствие.)

Ниже приведено решение для каждого случая.


Случай 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

[ 'replace''] (http://pandas.pydata.org/pandas-docs/dev/generated/pandas.DataFrame.replace.html) одинаково хорошо, и, может быть, лучше слово что здесь происходит. –

+0

@ DSM позаботился об этом. –

+0

Не удаляет ли отображаемый целевой фрейм OP неоднозначность? Тем не менее, этот ответ полезен, поэтому +1. – DSM

31

Это альтернативный ответ, который может быть намного быстрее, если словарь содержит более двух ключей. Если ваш словарь исчерпывающе отображает все возможные значения, это занимает очень простой вид:

df['col1'].map(di)  # note: if the dictionary does not exhaustively map all 
         # entries then non-matched entries are changed to NaNs 

Хотя map обычно принимает функцию в качестве аргумента, он может в качестве альтернативы взять словарь или серию: Documentation for Pandas.series.map

без исчерпывающее отображение, вы должны добавить update, если хотите предотвратить изменение совпадений в NaN.

df['col1'].update(df['col1'].map(di)) # note: series update is an inplace operation 

Вот некоторые тайминги для исчерпывающего случае на dataframe с 100000 строк и 8 ключей словаря (это примерно в 10 раз быстрее).

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 
+3

Последний блок кода для этого ответа, безусловно, не самый изящный, но этот ответ заслуживает некоторого кредита. Он на порядок быстрее для больших словарей и не использует всю мою оперативную память. Он переименовал 10 000 строк с использованием словаря, в котором за полминуты было около 9 миллионов записей. Функция 'df.replace', в то время как аккуратная и полезная для небольших dicts, потерпела крах после запуска в течение 20 минут или около того. – griffinc

+1

@griffinc Спасибо за отзыв и обратите внимание, что я обновил этот ответ с помощью более чистого способа сделать более общий (неисчерпывающий) случай: 'df ['col1']. Update (df ['col1']. Map (di)) ' – JohnE

+1

Связанные: [Заменить значения в серии pandas через словарь эффективно] (https://stackoverflow.com/questions/49259580/replace-values-in-a-pandas-series-via-dictionary-efficiently) – jpp

0

Добавления к этому вопросу, если вы когда-либо иметь более одного столбец переназначить в 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 

Надеется, что это может быть полезным для кого-то.

Приветствия

0

Более родной панды подход заключается в применении функции замены, как показано ниже:

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) 

После того, как вы определили функцию, вы можете применить его к dataframe.

di = {1: "A", 2: "B"} 
df['col1'] = df.apply(lambda row: multiple_replace(di, row['col1']), axis=1) 

 Смежные вопросы

  • Нет связанных вопросов^_^