我有一个未来值的数据框,该值希望随时间减少指定数量。
我想从这里出发:
Group Period Value
A 1/1/2020 4.3
A 2/1/2020
A 3/1/2020
A 4/1/2020
A 5/1/2020
A 6/1/2020
A 7/1/2020
A 8/1/2020
A 9/1/2020
B 1/1/2020 6.5
B 2/1/2020
B 3/1/2020
B 4/1/2020
B 5/1/2020
B 6/1/2020
B 7/1/2020
B 8/1/2020
B 9/1/2020
对此:
Group Period Value
A 1/1/2020 4.3
A 2/1/2020 3.3
A 3/1/2020 2.3
A 4/1/2020 1.3
A 5/1/2020 0.3
A 6/1/2020 0
A 7/1/2020 0
A 8/1/2020 0
A 9/1/2020 0
B 1/1/2020 6.5
B 2/1/2020 5.5
B 3/1/2020 4.5
B 4/1/2020 3.5
B 5/1/2020 2.5
B 6/1/2020 1.5
B 7/1/2020 0.5
B 8/1/2020 0
B 9/1/2020 0
我已经使用起始位置的值创建了数据框(在此示例中为1/1/2020)。
尝试过。见下文。
group = df2.groupby(['region', 'site', 'product_ID'], as_index=False)
df2['Projected_S'] = group['Projected_S'].rolling(window=1).apply(lambda x: x.shift(1)-1)
答案 0 :(得分:1)
IIUC,使用类似的东西
f=lambda x: np.where(x.ffill()-x.ffill().expanding().count()<0
,0,x.ffill()-x.ffill().expanding().count())
df.Value=df.groupby(df.Value.notna().cumsum())['Value'].transform(f)
print(df)
Group Period Value
0 A 1/1/2020 3.3
1 A 2/1/2020 2.3
2 A 3/1/2020 1.3
3 A 4/1/2020 0.3
4 A 5/1/2020 0.0
5 A 6/1/2020 0.0
6 A 7/1/2020 0.0
7 A 8/1/2020 0.0
8 A 9/1/2020 0.0
9 B 1/1/2020 5.5
10 B 2/1/2020 4.5
11 B 3/1/2020 3.5
12 B 4/1/2020 2.5
13 B 5/1/2020 1.5
14 B 6/1/2020 0.5
15 B 7/1/2020 0.0
16 B 8/1/2020 0.0
17 B 9/1/2020 0.0
说明 :
df.Value.notna().cumsum()
从包含条目的行开始创建组,直到下一个有效值。然后,我们使用.ffill()
向下填充值。然后使用expanding()
进行计数,因此基本上可以用扩展计数减去该值。
最后使用np.where()
检查哪里是负值,并将其替换为0。:)
答案 1 :(得分:0)
当我曾经使用很多帮助器列(只是在删除之后删除它们)时,我想出了一种解决方案,可以提醒我Excel的日子。
假设您知道起始位置,并且数据帧的结构如您在问题中所述,那么以下过程将起作用:
1)确保日期信息已正确转换为日期对象
2)在由组名称和日期组成的数据框中设置多索引
3)计算每个组的元素数
4)创建一个由重复的值组成的帮助器数组,该重复值与每个组中元素的数量一样多,称为A
5)使用您要减去的数量创建另一个数组,将其称为B
6)C = A-B
7)将负值替换为0
8)为相关列分配新值
这是代码:
import numpy as np
import pandas as pd
import datetime as dt
# Enforce conversion to date object
def date_converter(x):
return dt.datetime.strptime(x, "%m/%d/%Y")
test["Period"] = test["Period"].apply(date_converter)
test.set_index(["Group", "Period"], inplace=True)
starting_pos = "01-01-2020"
forecast_col = "Value"
# Get the names of the groups
u = test.index.unique(0).tolist()
# Get all the instances of all groups
f = test.index.get_level_values(0).tolist()
A = []
B = []
for element in u:
# Query the value you want to decrease
value = float(test.loc[(element, starting_pos), forecast_col])
# Count how many elements there are for each group
x = f.count(element)
# Repeat value x times
y = [value]*x
# Append repetitions to global result
A = A + y
# Create array you want to subtract with len(x)
B = B + [n for n in range(x)]
to_zero = lambda x: np.where(x < 0, 0, x)
C = pd.Series(np.array(A) - np.array(B)).apply(to_zero)
test.loc[:,"Value"] = C.values
test
尽管anky_91已经发布了答案,但我只想提供另一个选择,我认为它更简单,但可以完成任务。我让你做性能比较。让我知道这是否对您有帮助。