我有一个未来预测值的数据框,我想要显示一个特定数量的时间减少。
我想离开这个:
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)
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. :)
我想出了一个解决方案提醒我的Excel日子,当时我常常使用很多辅助列(仅在hehehe之后删除它们)。假设您知道起始位置,并且数据框的结构如您在问题中所述,则以下过程有效: 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已经发布了答案,但我只是想给出另一种选择,我认为这样做更简单但是可以做到这一点。我让你做性能比较。如果这有助于你,请告诉我。