Объединение двух методов «замены»?

Можно ли объединить два метода «замены» в приведенном ниже примере в один? Целью является масштабируемость.

import pandas as pd

custom_groups = {"odd": [1, 3, 5], "even": [2, 4]}

s = pd.Series([1, 2, 3, 4, 5])

s.replace(custom_groups["odd"], "odd").replace(custom_groups["even"], "even")

Не совсем уверен, какой у вас вариант использования, но почему бы вам просто не перестроить custom_groups в отображаемую форму? s.map({1: 'odd', 2: 'even', 3: 'odd', 4: 'even', 5: 'odd'})

Henry Ecker 20.08.2024 04:18

Привет, Генри. Вы случайно не знаете, есть ли что-нибудь вроде s.replace({[1, 3, 5]: "нечетный", [2, 4]: "четный"}), чтобы пропустить шаг создания таблицы "один к одному"? -одни отношения?

Howard 20.08.2024 04:35

Не существует способа сделать это, поскольку это не имеет смысла, поскольку списки не могут быть ключами словаря. Вы не можете напрямую сравнивать значения в своей серии со списком без проверки членства. Как бы вы ни смотрели на замену, вам в конечном итоге понадобится сопоставление 1 к 1. Даже если вы выполняете сравнения value in N, чтобы оно выглядело как сопоставление N-к-1.

Henry Ecker 20.08.2024 04:53

Когда вы передаете список в replace, этой функции все равно придется в конечном итоге проверять отдельные значения. Технически, он создает временный список, содержащий значение замены той же длины, что и ваша серия, затем маскирует его на основе списка to_replace, а затем заполняет из временного списка (по крайней мере, в текущей версии Pandas 2.2.2). В этом случае для первого replace это будет временный список ["нечетный", "нечетный", "нечетный", "нечетный", "нечетный"], а затем создайте маскирующий массив [True, False, True, False, True], затем заполните значения True в массиве маскирования из нечетного списка.

Henry Ecker 20.08.2024 04:53

С другой стороны, преобразователь, похожий на dict, очень эффективен при его замене, хотя map может потребовать обратного заполнения любых неучтенных значений. Вот почему я снова спросил, каков ваш фактический вариант использования, потому что в этом примере инвертирование ваших custom_groups и передача их в map, вероятно, будет быстрее и требует меньше места, чем объединение замен в цепочку или создание отдельного объекта Series.

Henry Ecker 20.08.2024 04:54

Спасибо, Генри, за подтверждение того, что при замене значений необходимо предоставление отношений «один к одному». Мне нужно немного времени, чтобы понять, как писать код, но теперь я понимаю весь процесс.

Howard 20.08.2024 05:17
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
6
64
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете написать цикл:

for key in custom_groups:
    s.replace(custom_groups[key], key)

Спасибо, Джон. Это умно! Однако мне очень хотелось бы знать, есть ли способ сделать это без цикла. Я понимаю, что параметр «to_replace» может принимать словарь, позволяя заменять несколько отдельных значений соответствующими одиночными значениями одновременно, например. s.replace({1: «нечетный», 2: «четный»}). Я надеюсь заменить несколько списков отдельных значений соответствующими отдельными значениями за один раз, например. что-то вроде s.replace({[1, 3, 5]: «нечетный», [2, 4]: «четный»}).

Howard 20.08.2024 04:14

Код

tmp = pd.Series(custom_groups).explode()
out = s.replace(pd.Series(tmp.index, index=tmp.values))

вне:

0     odd
1    even
2     odd
3    even
4     odd
dtype: object

Спасибо, Панда. У меня такое чувство, что это может быть лучшим решением. Я просто дам немного больше времени, чтобы посмотреть, есть ли еще какие-либо идеи по синтаксису, прежде чем отмечать ваше как ответ.

Howard 20.08.2024 04:26
Ответ принят как подходящий

Самый питонический/эффективный подход: переверните словарь с помощью словарного понимания и замените один раз:

d = {v:k for k, l in custom_groups.items()
     for v in l}
s.replace(d)

Выход:

0     odd
1    even
2     odd
3    even
4     odd
dtype: object

Промежуточный d:

{1: 'odd', 3: 'odd', 5: 'odd', 2: 'even', 4: 'even'}

тайминги

Это примерно в 2 раза быстрее, чем использование Series+deplode для небольших наборов данных, и имеет тенденцию к той же скорости для больших наборов данных.

## OP's example
# dictionary comprehension
745 µs ± 31.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# Series explode
1.58 ms ± 213 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

## 1000 keys dictionary / 10 items per list / 10_000 items Series
# dictionary comprehension
163 ms ± 6.61 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

# Series explode
203 ms ± 64.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

обобщение

Если вам приходится часто делать это с разными словарями, вы даже можете использовать функцию инвертирования словаря.

def invert(d):
    return {v:k for k, l in custom_groups.items()
            for v in (l if isinstance(l, list) else [l])}
s.replace(invert(custom_groups))

Спасибо Mozway за подробное объяснение. dict_comprehension действительно кричит по-питонски. Если вы с Генри согласны, я считаю, что это «очевидный способ сделать это».

Howard 20.08.2024 14:04

Другие вопросы по теме