Выполните некоторую операцию, если 2 кадра данных pandas имеют одинаковые записи в python

У меня есть 2 кадра данных (покупка и продажа) следующим образом:

ПОКУПКА:

Имя элемент ваучер Амт Кол-во А Товар1 Покупка 10000 100 Б Пункт2 Покупка 500 50 Б Товар1 Покупка 2000 г. 20 С Пункт 3 Покупка 1000 100 Д Пункт4 Покупка 500 100 А Пункт 3 Покупка 5000 50

ПРОДАЖИ:

Имя элемент ваучер Амт Кол-во А Товар1 Продажи 5300 50 Б Пункт2 Продажи 450 40 Б Товар1 Продажи 1675 15 С Пункт 3 Продажи 1800 100

Мне нужен выходной фрейм данных, в котором, если человек (Name) продает товар, Amt и Qty должны быть вычтены из фрейма данных покупки, а новый фрейм данных должен быть создан с оставшимися Amt и Qty, как показано ниже:

ВЫХОДНОЙ КАДР ДАННЫХ:

Имя элемент ваучер Амт Кол-во А Товар1 Оставшийся 4700 50 А Пункт 3 Оставшийся 5000 50 Б Пункт2 Оставшийся 50 10 Б Товар1 Оставшийся 325 5 С Пункт 3 Оставшийся -800 0 Д Пункт4 Оставшийся 500 100

Обратите внимание, что любые предметы, проданные человеком (Name), были вычтены из кадра данных покупки, а оставшиеся предметы (Amt и Qty) сохранены в новом выходном кадре данных. Также человек D никогда не продавал какие-либо предметы, даже если это должно быть включено в выходной фрейм данных.

Заранее спасибо!

Датафрейм

import pandas as pd

Purchases = {
    "Name": ["A", "B", "B", "C", "D", "A"],
    "item": ["Item1", "Item2", "Item1", "Item3", "Item4", "Item3"],
    "voucher": ["Purchase", "Purchase", "Purchase", "Purchase", "Purchase", "Purchase"],
    "Amt": [10000, 500, 2000, 1000, 500, 5000],
    "Qty": [100, 50, 20, 100, 100, 50],
}

Purchases = pd.DataFrame(Purchases)

Sales = {
    "Name": ["A", "B", "B", "C"],
    "item": ["Item1", "Item2", "Item1", "Item3"],
    "voucher": ["Sales", "Sales", "Sales", "Sales"],
    "Amt": [5300, 450, 1675, 1800],
    "Qty": [50, 40, 15, 100],
}

Sales = pd.DataFrame(Sales)

Я думаю, что в вашем входном фрейме данных есть ошибка: (C, item3) должно быть 800, а не 1800.

Corralien 16.04.2023 07:36

@Corralien Я не вижу где, кажется, сейчас 1800

Laurent B. 16.04.2023 07:39

Во фрейме данных SALES. Результат 200, поэтому вычитание должно быть 1000-800, а не 1000-1800.

Corralien 16.04.2023 07:40
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
59
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Purchases = Purchases.set_index(['Name', 'item'])
Sales = Sales.set_index(['Name', 'item'])
Purchases['Amt'].update(Purchases['Amt'].sub(Sales['Amt']))
Purchases['Qty'].update(Purchases['Qty'].sub(Sales['Qty']))
Purchases = Purchases.reset_index().sort_values(by=['Name'])

print(Purchases)
  Name   item   voucher   Amt  Qty
0    A  Item1  Purchase  4700   50
5    A  Item3  Purchase  5000   50
1    B  Item2  Purchase    50   10
2    B  Item1  Purchase   325    5
3    C  Item3  Purchase  -800    0
4    D  Item4  Purchase   500  100

Спасибо за эту информацию, Корралиен, ìnplace будет объявлен устаревшим в следующей версии Pandas (например, Pandas 2). Так что теперь нужно взять хорошие привычки ;-)

Laurent B. 16.04.2023 07:44

Вероятно, update тоже устаревает. (Я надеюсь :-)). Я думаю, что все методы всегда должны возвращать копию (явный лучше, чем неявный). Только .loc, .iloc и другие назначения элементов должны изменять DataFrame/Series на месте, потому что они являются явными. ИМХО :-)

Corralien 16.04.2023 07:53

Да, конечно, это было бы предпочтительнее, но update не устарело в Pandas 2: pandas.pydata.org/docs/reference/api/pandas.Series.update.ht‌​ml (версия 2.0.0 (стабильная)). Но я должен признать, даже если update очень полезен, мне не нравятся методы, возвращающие None (источники ошибок).

Laurent B. 16.04.2023 08:06

Вы можете использовать merge:

# dfP = PURCHASE dataframe
# dfS = SALES dataframe
out = (Purchases.merge(Sales.drop(columns='voucher'), on=['Name', 'item'],
                 suffixes=(None, '_'), how='left')
                .assign(Amt=lambda x: x['Amt'] - x.pop('Amt_').fillna(0).astype(int),
                        Qty=lambda x: x['Qty'] - x.pop('Qty_').fillna(0).astype(int),
                        voucher='Remaining'))

Выход:

>>> out
  Name   item    voucher   Amt  Qty
0    A  Item1  Remaining  4700   50
1    B  Item2  Remaining    50   10
2    B  Item1  Remaining   325    5
3    C  Item3  Remaining  -800    0
4    D  Item4  Remaining   500  100
5    A  Item3  Remaining  5000   50
Ответ принят как подходящий

Используя старое доброе выравнивание индекса:

tmp = Purchases.set_index(['Name', 'item'])
out = (tmp
       .sub(Sales.set_index(['Name', 'item'])[['Amt', 'Qty']])
       .combine_first(tmp).assign(voucher='Remaining')
       .reset_index()[Purchases.columns]
      )

Выход:

  Name   item    voucher     Amt    Qty
0    A  Item1  Remaining  4700.0   50.0
1    A  Item3  Remaining  5000.0   50.0
2    B  Item1  Remaining   325.0    5.0
3    B  Item2  Remaining    50.0   10.0
4    C  Item3  Remaining  -800.0    0.0
5    D  Item4  Remaining   500.0  100.0

Я не знаю, люблю я тебя или ненавижу тебя, лол ;-p

Laurent B. 16.04.2023 08:11

@LaurentB. тогда скорее люби меня, пожалуйста, в этом мире достаточно ненависти :p

mozway 16.04.2023 08:12

хорошо, это то, что показывает мне мой кубик :-p

Laurent B. 16.04.2023 08:13

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