使用带有子集的迭代的数据帧操作

时间:2019-01-23 21:22:37

标签: python python-3.x pandas

鉴于他们的ID,初始金额和余额,我正在尝试操作此数据框, 这是我想要的数据框,其中期望输出是我创建的列:

df = pd.DataFrame(
{"ID" : [1,1,1,2,3,3,3],
 "Initial amount": [7650,25500,56395,13000,10700,12000,27000],
"Balance": [43388,43388,43388,2617,19250,19250,19250], "desired_output": [7650,25500,10238,2617,10720,8530,0]})

这是我当前的代码:

unique_ids = list(df["ID"].unique())
new_output = []
for i,row in df.iterrows():
    this_adv = row["ID"]
    subset = df.loc[df["ID"] == this_adv,:]
    if len(subset) == 1:
        this_output = np.where(row["Balance"] >= row["Initial amount"], row["Initial amount"], row["Balance"])
        new_output.append(this_output)
    else:
        if len(subset) >= 1:
            if len(subset) == 1:
                this_output = np.where(row["Balance"] >= row["Initial amount"], row["Initial amount"], row["Balance"])
                new_output.append(this_output)
            elif row["Balance"] - sum(new_output) >= row["Initial amount"]:
                this_output = row["Initial amount"]
                new_output.append(this_output)
            else:
                this_output = row["Balance"] - sum(new_output)
                new_output.append(this_output)

new_df = pd.DataFrame({"new_output" : new_output})
final_df = pd.concat([df,new_df], axis = 1)

基本上我想做的是,如果只有1个唯一ID(len(subset)== 1),然后使用第一个if语句。 ID大于1(len(subset)> = 1)的任何其他项都使用另一个if语句。我没有得到想要的输出,你们将如何处理?

谢谢!任何建议表示赞赏。

1 个答案:

答案 0 :(得分:0)

您的算法似乎正在尝试为每个Initial amount计算ID的滚动总和,然后部分根据{ {1}}的当前期间new_output与同一ID的上一个期间的滚动余额比较。

如果我们从您的示例数据帧开始:

Balance

我们首先需要创建临时列来存储ID计数(您在上文中称为ID),然后创建每个ID的滚动余额。

df = pd.DataFrame(
{"ID" : [1,1,1,2,3,3,3],
 "Initial amount": [7650,25500,56395,13000,10700,12000,27000],
"Balance": [43388,43388,43388,2617,19250,19250,19250], "desired_output": [7650,25500,10238,2617,10720,8530,0]})

我们还将创建一个包含len(subset)的列:

val_cts = pd.DataFrame(df['ID'].value_counts().reset_index().rename({'ID': 'ID Count', 'index': 'ID'}, axis=1)) df = df.merge(val_cts, left_on='ID', right_on='ID') df['rolling_balance'] = df.groupby(['ID'])['Initial amount'].cumsum()

此时new_output如下所示:

df['new_output'] = 0

现在开始做饭:我写了一个函数,我相信它封装了您尝试使用if语句实现的算法:

df

将上述算法应用于每一行:

    ID  Initial amount  Balance desired_output  ID Count    rolling_balance   new_output
0   1   7650            43388             7650         3               7650            0
1   1   25500           43388            25500         3              33150            0
2   1   56395           43388            10238         3              89545            0
3   2   13000            2617             2617         1              13000            0
4   3   10700           19250            10720         3              10700            0
5   3   12000           19250             8530         3              22700            0
6   3   27000           19250                0         3              49700            0

然后删除我们在计算中使用的列:def calc_output(count, init_amt, bal, cur_roll_bal, prev_roll_bal): if count == 1: return init_amt if bal > init_amt else bal else: if bal > init_amt: return init_amt if bal > cur_roll_bal else bal - prev_roll_bal else: return bal-prev_roll_bal if bal-prev_roll_bal > 0 else 0

然后数据框如下所示:

for i,row in df.iterrows():
    # Make sure not at first row belonging to an 'ID'
    if i > 0 and df.iloc[i-1]['ID'] == row['ID']:
        prev_idx = i-1
    else:
        prev_idx = i
    row['new_output'] = calc_output(row['ID Count'], row['Initial amount'], row['Balance'], row['rolling_balance'], df.iloc[prev_idx]['rolling_balance'])

我在第4行中的df = df.drop(['ID Count', 'rolling_balance'], axis=1)值要少20,而在第5行中的 ID Initial amount Balance desired_output new_output 0 1 7650 43388 7650 7650 1 1 25500 43388 25500 25500 2 1 56395 43388 10238 10238 3 2 13000 2617 2617 2617 4 3 10700 19250 10720 10700 5 3 12000 19250 8530 8550 6 3 27000 19250 0 0 值要比其对应的new_output值大20,但是我希望是因为这些值最初是错误地输入到上面的示例数据框中的。