Python 熊猫:根据下一行的值替换组中的列值

Python 熊猫:根据下一行的值替换组中的列值,python,pandas,Python,Pandas,我正在使用这个数据框架,它必须按DocumentId和PersonId进行分组。在该组中,如果结束日期列为空,则用DocCode为RT的行填充该列 它工作得很好,但还有另一个转折点。在该DocumentId&PersonID组中,如果金额发生变化,则下一个金额的开始日期将是上一个金额的结束日期。因此,中间数据帧将如下所示: 然后,该组中所有金额重复且金额为空的行将折叠为一行 最终数据集如下所示: 下面是我用来填充DocCode为RT的行中所有空EndDate列的代码: 首先,填写金额列值以填充

我正在使用这个数据框架,它必须按DocumentId和PersonId进行分组。在该组中,如果结束日期列为空,则用DocCode为RT的行填充该列

它工作得很好,但还有另一个转折点。在该DocumentId&PersonID组中,如果金额发生变化,则下一个金额的开始日期将是上一个金额的结束日期。因此,中间数据帧将如下所示:

然后,该组中所有金额重复且金额为空的行将折叠为一行

最终数据集如下所示:

下面是我用来填充DocCode为RT的行中所有空EndDate列的代码:

首先,填写金额列值以填充所有空格。这样做是为了在金额发生变化时查找。将StartDate值移回1,当检测到金额变化时,将使用该值填充EndDate列:

df.Amount.ffill(inplace=True)
df['StartDateShift'] = df['StartDate'].shift(-1)

>>> df
   DocumentID  PersonID DocCode StartDate  Amount EndDate StartDateShift
0      120303    110001      FB   5/18/21   245.0     NaN        5/25/21
1      120303    110001      TW   5/25/21   460.0     NaN         6/1/21
2      120303    110001      RT    6/1/21   460.0  6/6/21         4/1/21
3      120303    110011      GK    4/1/21     0.0     NaN         4/8/21
4      120303    110011      AK    4/8/21   128.0     NaN        4/12/21
5      120303    110011      PL   4/12/21   128.0     NaN        4/16/21
6      120303    110011      FB   4/16/21   256.0     NaN        4/28/21
7      120303    110011      RT   4/28/21   256.0  5/4/21            NaN
现在获取所有数量发生变化的行,并从中创建一个掩码。使用此掩码使用StartDateShift中的值填充EndDate中的NAN:

倒填EndDate值,然后在Amount列中删除重复项,将空值折叠成一行。现在还删除StartDateShift列,您将获得最终的数据帧:

df['EndDate'].bfill(inplace=True)
df = df.drop_duplicates('Amount', keep='first').drop('StartDateShift', axis=1)

>>> df
   DocumentID  PersonID DocCode StartDate  Amount  EndDate
0      120303    110001      FB   5/18/21   245.0  5/25/21
1      120303    110001      TW   5/25/21   460.0   6/6/21
3      120303    110011      GK    4/1/21     0.0   4/8/21
4      120303    110011      AK    4/8/21   128.0  4/16/21
6      120303    110011      FB   4/16/21   256.0   5/4/21
在上面的步骤中,我没有按DocumentId和PersonId列分组,因为逻辑在没有它的情况下对示例df起作用。但对于您的实际用例,您可以在DocumentId和PersonId列上应用groupby,并为每个组执行上述所有步骤,然后在最后执行concat:

dfs = []
for i,dfg in df.groupby(['DocumentID','PersonID']):
    dfg.Amount.ffill(inplace=True)
    dfg['StartDateShift'] = dfg['StartDate'].shift(-1)
    dfg['EndDate'].fillna(dfg[~(dfg['Amount']==dfg['Amount'].shift(-1))]['StartDateShift'], inplace=True)
    dfg['EndDate'].bfill(inplace=True)
    dfg = dfg.drop_duplicates('Amount', keep='first').drop('StartDateShift', axis=1)
    dfs.append(dfg)

final_df = pd.concat(dfs)

>>> final_df
   DocumentID  PersonID DocCode StartDate  Amount  EndDate
0      120303    110001      FB   5/18/21   245.0  5/25/21
1      120303    110001      TW   5/25/21   460.0   6/6/21
3      120303    110011      GK    4/1/21     0.0   4/8/21
4      120303    110011      AK    4/8/21   128.0  4/16/21
6      120303    110011      FB   4/16/21   256.0   5/4/21

在投票之前,至少要问一个澄清的问题。没有投票,但你共享了图像而不是文本,人们不能复制数据并测试他们的解决方案,除非他们自己逐行构建数据框架,这是极不可能的,而且pd.read_图像不存在yetMake sense,我可以用实际数据替换excel屏幕截图。通过突出显示值来自的列来显示中间结果很直观。@MustafaAydın这有帮助吗?谢谢@Ank非常感谢您的帮助!
mask = (df['Amount'] != df['Amount'].shift(-1))
df['EndDate'].fillna(df[mask]['StartDateShift'], inplace=True)

>>> df
   DocumentID  PersonID DocCode StartDate  Amount  EndDate StartDateShift
0      120303    110001      FB   5/18/21   245.0  5/25/21        5/25/21
1      120303    110001      TW   5/25/21   460.0      NaN         6/1/21
2      120303    110001      RT    6/1/21   460.0   6/6/21         4/1/21
3      120303    110011      GK    4/1/21     0.0   4/8/21         4/8/21
4      120303    110011      AK    4/8/21   128.0      NaN        4/12/21
5      120303    110011      PL   4/12/21   128.0  4/16/21        4/16/21
6      120303    110011      FB   4/16/21   256.0      NaN        4/28/21
7      120303    110011      RT   4/28/21   256.0   5/4/21            NaN
df['EndDate'].bfill(inplace=True)
df = df.drop_duplicates('Amount', keep='first').drop('StartDateShift', axis=1)

>>> df
   DocumentID  PersonID DocCode StartDate  Amount  EndDate
0      120303    110001      FB   5/18/21   245.0  5/25/21
1      120303    110001      TW   5/25/21   460.0   6/6/21
3      120303    110011      GK    4/1/21     0.0   4/8/21
4      120303    110011      AK    4/8/21   128.0  4/16/21
6      120303    110011      FB   4/16/21   256.0   5/4/21
dfs = []
for i,dfg in df.groupby(['DocumentID','PersonID']):
    dfg.Amount.ffill(inplace=True)
    dfg['StartDateShift'] = dfg['StartDate'].shift(-1)
    dfg['EndDate'].fillna(dfg[~(dfg['Amount']==dfg['Amount'].shift(-1))]['StartDateShift'], inplace=True)
    dfg['EndDate'].bfill(inplace=True)
    dfg = dfg.drop_duplicates('Amount', keep='first').drop('StartDateShift', axis=1)
    dfs.append(dfg)

final_df = pd.concat(dfs)

>>> final_df
   DocumentID  PersonID DocCode StartDate  Amount  EndDate
0      120303    110001      FB   5/18/21   245.0  5/25/21
1      120303    110001      TW   5/25/21   460.0   6/6/21
3      120303    110011      GK    4/1/21     0.0   4/8/21
4      120303    110011      AK    4/8/21   128.0  4/16/21
6      120303    110011      FB   4/16/21   256.0   5/4/21