Python суммирует дважды для groupby

Я борюсь с суммой ряда после того, как уже сгруппировал фреймворк, и я надеялся, что кто-то может помочь мне с идеей. В основном, в приведенном ниже примере мне нужна сумма для каждого «Материала». Обычно материал «ABC» должен дать мне 2, а все остальные, поскольку они имеют только одну операцию знака, будут иметь такое же значение.

import numpy as np
import pandas as pd

df = pd.DataFrame({ 
    "Material" : ["M-12", "H4-LAMPE", "M-12", "H4-LAMPE",
                  "ABC" , "H4-LAMPE", "ABC", "ABC"] , 
    "Quantity" : [6, 1, 3, 5, 1, 1, 10, 9],
    "TYPE": ["+", "-", "+", "-", "+", "-", "+", "-"]})
df.groupby(['Material', "Quantity"], as_index=False).count()

listX = []
for item in df["TYPE"]:
    if item == "+":
        listX.append(1)
    elif item == "-":
        listX.append(-1)
    else:
        pass
df["Sign"] = lista
df["MovementsQty"] = df["Quantity"]*df["Sign"]
#df = df.groupby(["Material", "TYPE", "Quantity1"]).sum()
df1 = df.groupby(["Material", "TYPE"]).sum()
df1.drop(columns=["Quantity", "Sign"], inplace=True)

print(df1)

Результат:

Python суммирует дважды для groupby

Желаемый результат:

Python суммирует дважды для groupby

Я попытался подвести итоги еще раз, рассмотреть по-другому, но пока мне это не удалось, и я думаю, что мне нужна помощь.

Большое спасибо за Вашу помощь

Предположительно, вам не нужен Type в желаемом результате, так как знак уже является частью количества чистых перемещений.

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

Ответы 3

Ответ принят как подходящий

Вы на правильном пути. Я пытался улучшить ваш код. Просто используйте «Тип», чтобы определить и присвоить знак с помощью np.where, выполните groupby и sum, а затем повторно вычислите столбец «Тип» на основе результата.

v = (df.assign(Quantity=np.where(df.TYPE == '+', df.Quantity, -df.Quantity))
       .groupby('Material', as_index=False)[['Quantity']]
       .sum())

v.insert(1, 'Type', np.where(np.sign(v.Quantity) == 1, '+', '-'))

print (v)
   Material Type  Quantity
0       ABC    +         2
1  H4-LAMPE    -        -7
2      M-12    +         9

В качестве альтернативы вы можете сделать это с помощью двух вызовов groupby:

i = df.query('TYPE == "+"').groupby('Material').Quantity.sum()
j = df.query('TYPE == "-"').groupby('Material').Quantity.sum()
# Find the union of the indexes.
idx = i.index.union(j.index)
# Reindex and subtract.
v = i.reindex(idx).fillna(0).sub(j.reindex(idx).fillna(0)).reset_index()
# Insert the Type column back into the result.
v.insert(1, 'Type', np.where(np.sign(v.Quantity) == 1, '+', '-'))

print(v)
   Material Type  Quantity
0       ABC    +       2.0
1  H4-LAMPE    -      -7.0
2      M-12    +       9.0

Дагнаббит! Ты подтолкнул меня на это. df.assign(Quantity = np.where(df['TYPE'].eq('+'),df['Quantity'],-df['Quantity']))‌​.groupby(['Material'‌​]).sum().pipe(lambda x: x.assign(TYPE = np.where(x.Quantity.lt(0),'-','+'))) У меня был классный однострочник с использованием pipe.

Scott Boston 12.09.2018 00:01

@coldspeed: Большое спасибо!

Eranio 12.09.2018 09:54

Вот еще один вариант (хотя и довольно похожий на холодную скорость).

#Correct quantity with negative sign (-) according to TYPE 
df.loc[df['TYPE'] == '-', 'Quantity'] *= -1

#Reconstruct df as sum of quantity to remove dups
df = df.groupby('Material')['Quantity'].sum().reset_index()
df['TYPE'] = np.where(df['Quantity'] < 0, '-', '+')

print(df)

Возврат:

   Material  Quantity TYPE
0       ABC         2    +
1  H4-LAMPE        -7    -
2      M-12         9    +

map и numpy.sign

Просто просуммируйте Quantity * TYPE, а потом выясните знак.

d = {'+': 1, '-': -1}
r = dict(map(reversed, d.items())).get
q = df.Quantity
m = df.Material
t = df.TYPE

s = pd.Series((q * t.map(d)).values, m, name='MovementsQty').sum(level=0)
s.reset_index().assign(TYPE=lambda x: [*map(r, np.sign(x.MovementsQty))])

   Material  MovementsQty TYPE
0      M-12             9    +
1  H4-LAMPE            -7    -
2       ABC             2    +

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