Расчет Python Pandas снизу вверх внутри групп - PullRequest
0 голосов
/ 12 сентября 2018

Предположим, у меня есть следующий набор данных:

df = pd.DataFrame({"A":range(1,10), "B":range(5,14), "Group": 
[1,1,2,2,2,2,3,3,3],"C":[0,0,10,0,0,16,0,0,22], "last":[0,1,0,0,0,1,0,0,1], 
"Want": [19.25,8,91.6,71.05,45.85,16,104.95,65.8,22]})

Для последнего наблюдения в группе у меня есть следующий код:

def calculate(df):
if (df.last == 1):
    value = df.loc["A"] + df.loc["B"]
else:

для всех других наблюдений на группу, значение строки рассчитывается следующим образом:

value = (df.loc[i-1, "C"] + 3 * df.loc[i, "A"] + 1.65 * df.loc[i, "B"])
    return value

На простом английском это то, что я пытаюсь сделать. Для последнего наблюдения в каждой группе столбец C равен сумме столбцов A and B

Для всех других наблюдений я хотел бы вычислить значение столбца C снизу вверх, используя приведенное выше «утверждение else» (которое есть для подтверждения концепции).

Для дальнейшего пояснения, это формулы для вычисления столбца Want для Group 2 с использованием excel: F4="F5+(3*A4)+(1.65*B4)", F5="F6+(3*A5)+(1.65*B5)", F6="F7+(3*A6)+(1.65*B6)", F7="A7+B7". В этом есть какая-то "рекурсивная" природа, поэтому я подумал о цикле "for"

Я бы очень признателен за решение, в котором оно согласуется с первым if statement. То есть

value = something

, а не функция, возвращающая фрейм данных или что-то в этом роде, так что я могу вызвать функцию с помощью следующего

df["value"] = df.apply(calculate, axis=1)

Ваша помощь приветствуется. Спасибо

Ответы [ 3 ]

0 голосов
/ 12 сентября 2018

Кажется, вам нужно np.where с shift

np.where(df.last==1,df.A+df.B,df.A+1.65*df.B+df.C.shift())
Out[199]: array([  nan, 11.9 , 14.55, 27.2 , 19.85, 22.5 , 41.15, 27.8 , 30.45])
0 голосов
/ 12 сентября 2018

Вот моя попытка.Я стараюсь держать вещи как можно более прямыми.

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A":range(1,10), 
    "B":range(5,14), 
    "Group": [1,1,2,2,2,2,3,3,3],
    "C":[0,0,10,0,0,16,0,0,22], 
    "want":[19.25,8,91.6,71.05,45.85,16,104.95,65.8,22],
    "last":[0,1,0,0,0,1,0,0,1]})

# Determine where the last-in-group value applies.
condition = df['Group'] != df['Group'].shift(-1)

# Calculate the alternative data.
alternate_formula = (3 * df['A'] + 1.65 * df['B'])

# Calculate C as either the 'last-in-group' function or the alternative function.
df['C'] = np.where(condition, df['A'] + df['B'], alternate_formula)

# Reverse the order of the dataframe, group by the 'Group' column, run a cumulative sum
# for each group and then resort the back to the original order.
df['C'] = df.sort_index(ascending=False).groupby('Group')['C'].cumsum().sort_index()

print(df)

Я думаю, что обычно предпочтительнее использовать векторизованный подход, чем итеративный подход, такой как «применять».

0 голосов
/ 12 сентября 2018

Вы можете использовать df.assign и np.where и df.rolling для достижения цели.

import pandas as pd
import numpy as np
df = pd.DataFrame({"A":range(1,10), "B":range(5,14), "Group": 
[1,1,2,2,2,2,3,3,3],"C":[0,0,10,0,0,16,0,0,22], \
               "last":[0,1,0,0,0,1,0,0,1],
               "Want": [19.25,8,91.6,71.05,45.85,16,104.95,65.8,22]}).sort_index(ascending = False)
df = df.assign(FakeC = df['A'] + df['B']) #you can comment out this line then replace FakeC with A+B for the following expressions
df = df.assign(value = np.where(df['last'] == 1, df['A'] + df['B'], df['FakeC'].rolling(2, min_periods=1).sum() - df['FakeC'] + 3 * df['A'] + 1.65 * df['B']))
df = df.assign(final = np.where(df['last'] == 1, df['value'], df['value'].rolling(2, min_periods=1).sum() -  df['FakeC'].rolling(2, min_periods=1).sum() + df['FakeC']))
print(df)

Выход:

   A   B   C  Group    Want  last  FakeC  value   final
8  9  13  22      3   22.00     1     22  22.00   22.00
7  8  12   0      3   65.80     0     20  65.80   65.80
6  7  11   0      3  104.95     0     18  59.15  104.95
5  6  10  16      2   16.00     1     16  16.00   16.00
4  5   9   0      2   45.85     0     14  45.85   45.85
3  4   8   0      2   71.05     0     12  39.20   71.05
2  3   7  10      2   91.60     0     10  32.55   59.75
1  2   6   0      1    8.00     1      8   8.00    8.00
0  1   5   0      1   19.25     0      6  19.25   19.25
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...